Zum Hauptinhalt springen
  1. Blog/

Kubernetes auf Hetzner Cloud: Ingress

Marcel Ryser
Autor
Marcel Ryser
Softwarearchitekt und Tech-Enthusiast aus Bern

Ein Hauptziel des Servers ist es, Websites/Apps auszuliefern. Um auf Services innerhalb eines Kubernetes-Clusters zuzugreifen, musst du ihn irgendwo öffnen. Das geht über einen NodePort, der aber nur auf dem Node öffnet, der den Pod ausführt. Geht dieser Node down, ist deine Anwendung nicht mehr unter derselben öffentlichen IP erreichbar wie zuvor – was du vielleicht nicht willst.

LoadBalancer to the rescue. Du brauchst einen LoadBalancer ausserhalb des Kubernetes-Clusters, der eine IP-Adresse hat und den Traffic an alle Nodes weiterleitet, die die Anwendung bereitstellen.

Ein LoadBalancer ist auch Voraussetzung, um eine Ingress-Resource-Implementierung wie NGINX zu deployen, die du für deinen Web-Traffic nutzen willst.

Hetzner bietet leider (noch) keinen LoadBalancer. Deshalb müssen wir mit dem, was wir haben, etwas kreativer werden.

Ein zentraler Aspekt ist die Floating IP, die unsere öffentliche IP-Adresse für den LoadBalancer darstellt. Aber wie richten wir den LoadBalancer ein? Hier betritt MetalLB die Bühne. Es braucht nur ein paar öffentliche IPs zum Verteilen und setzt einen LoadBalancer mit Standard-Routing-Mechanismen um. Hetzner unterstützt aber nicht das Verteilen von IPs ausserhalb seiner Reichweite, sondern nur die Zuweisung an einen Node (Floating IP). Wir nutzen also nur diese eine Floating IP von Hetzner für 1,077 €/Monat. Diese Floating IP lässt sich nur einem Node zuweisen – aber was passiert, wenn dieser Node aus irgendeinem Grund down geht? Ja, alle Anwendungen auf dieser öffentlichen IP sind nicht mehr verfügbar. Mist! Dank C. Beneke gibt es Hoffnung. Der hcloud fip controller prüft, ob ein Node down geht, und weist die Floating IP einem laufenden Node zu – das bewahrt uns vor Downtime!

Mit all dem hast du einen virtuellen LoadBalancer, der sich in die Hetzner-Cloud-Umgebung integriert. Keine ideale Lösung, aber die beste, die wir bisher bekommen. Vielleicht erlaubt uns Hetzner künftig, LoadBalancer zu erstellen?!?

Unsere neue Lösung sieht so aus:

Jetzt wollen wir das umsetzen und auch die NGINX-Ingress-Resource-Implementierung installieren, um in unserem Cluster Ingress-Ressourcen anlegen zu können – damit wir Websites in unserem Cluster einfach ausliefern!

Voraussetzungen
#

  • Du solltest den Kubernetes-Cluster auf Hetzner Cloud wie in meinem vorherigen Blogbeitrag beschrieben eingerichtet haben.
  • Erstelle eine Floating IP mit
    hcloud floating-ip create --type ipv4 --home-location nbg1 --name public-ip
    oder über das Web-Interface – Floating IPs – Floating IP hinzufügen

Floating IP auf jedem Node konfigurieren
#

Um die Floating IP zu nutzen, musst du sie auf jedem Worker-Node separat konfigurieren:

cat <<EOF > /etc/sysconfig/network-scripts/ifcfg-eth0:1
BOOTPROTO=static
DEVICE=eth0:1
IPADDR=<your-floating-ip-goes-here>
PREFIX=32
TYPE=Ethernet
USERCTL=no
ONBOOT=yes
EOF

danach solltest du die Netzwerkkonfiguration neu starten:

systemctl restart network.service

MetalLB installieren
#

Installiere MetalLB, indem du das Manifest anwendest:

kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.8.3/manifests/metallb.yaml

Du kannst es auch mit kustomize installieren (Helm wird leider nicht mehr unterstützt); eine Anleitung dazu findest du unter https://metallb.universe.tf/installation/.

Jetzt musst du nur noch deine Floating IP in MetalLB konfigurieren:

cat <<EOF |kubectl apply -f-
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - <your-floating-ip-goes-here>/32
EOF

FIP-Controller installieren
#

Um den automatischen Failover-Mechanismus umzusetzen, installiere den FIP-Controller.

Erstelle einen neuen Namespace und deploye den FIP-Controller hinein.

kubectl create namespace fip-controller
kubectl apply -f https://raw.githubusercontent.com/cbeneke/hcloud-fip-controller/master/deploy/rbac.yaml
kubectl apply -f https://raw.githubusercontent.com/cbeneke/hcloud-fip-controller/master/deploy/deployment.yaml

Da er auf die Hetzner-Cloud-API zugreifen muss, brauchst du ein weiteres API-Token (oder du nutzt ein bereits erstelltes wieder).

Um ein Hetzner-Cloud-API-Token zu erstellen, melde dich im Web-Interface an und navigiere zu deinem Projekt -> Access -> API tokens und erstelle ein neues Token.

Jetzt können wir FIP mit diesem Token und unserer Floating IP konfigurieren:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: fip-controller-config
  namespace: fip-controller
data:
  config.json: |
    {
      "hcloud_floating_ips": [ "<your-floating-ip-goes-here>" ]
    }
---
apiVersion: v1
kind: Secret
metadata:
  name: fip-controller-secrets
  namespace: fip-controller
stringData:
  HCLOUD_API_TOKEN: "<the api token you created just yet>"
EOF

NGINX Ingress Controller installieren
#

Zum Ausliefern von Webseiten deployen wir einen NGINX Ingress Controller. Der ist im Grunde ein Service vom Typ LoadBalancer und kann Traffic an mehrere Endpoints/Services routen.

Du deployst den NGINX Ingress Controller mit

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

und da wir MetalLB nutzen, erstellen wir einen Service, der auf den NGINX Ingress Controller zeigt:

cat <<EOF | kubectl apply -f -
kind: Service
apiVersion: v1
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  annotations:
    metallb.universe.tf/allow-shared-ip: "floating-ip"
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  type: LoadBalancer
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  ports:
    - name: http
      port: 80
      targetPort: http
    - name: https
      port: 443
      targetPort: https
EOF

Jetzt können wir Ingress-Ressourcen deployen, und wenn wir den Browser auf http://<floating-ip-address>/<whatever> richten, sehen wir die deployte Seite/Anwendung.

Aber IP-Adressen in den Browser zu tippen mag niemand – dafür gibt es DNS. Da wir das nicht manuell machen wollen, habe ich etwas im Kopf, worüber ich bald schreibe!