Kubernetes Ingress Updates Skalierung

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen

Dieser Artikel baut auf dem vorherigen Deployment aus Compose-App nach Kubernetes übersetzen auf und ergänzt das, was mit Docker Compose gar nicht möglich war: externer Zugriff über Ingress, kontrollierte Updates ohne Downtime, Skalierung und persistente Daten.

Externer Zugriff mit Ingress

Port-Forwarding aus dem vorherigen Artikel funktioniert nur temporär und nur für eine Person gleichzeitig. Für dauerhaften externen Zugriff wird ein Ingress verwendet.

Was ein Ingress macht
  • Ein Ingress ist ein Regelwerk, das eingehenden HTTP(S)-Traffic anhand von Hostname oder Pfad an den passenden internen Service weiterleitet – vergleichbar mit einem Reverse Proxy wie Traefik oder Nginx, den man aus der Compose-Welt kennt.
Ingress-Controller bei k3s
  • k3s bringt Traefik als Ingress-Controller bereits vorinstalliert mit. Es muss nichts zusätzlich installiert werden.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
spec:
  rules:
    - host: web.lab.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80
Anwenden
  • kubectl apply -f web-ingress.yaml
Hostnamen lokal auflösen
  • Da web.lab.local keine echte Domain ist, muss der Hostname auf dem Client in /etc/hosts eingetragen werden, zeigend auf die IP-Adresse von k8s-server.
  • echo "<SERVER_IP> web.lab.local" | sudo tee -a /etc/hosts
Zugriff testen

Health-Checks: Probes

Im vorherigen Artikel wurde festgestellt, dass es kein Äquivalent zu depends_on gibt. Die Kubernetes-Antwort darauf sind Probes – fortlaufende Prüfungen, ob ein Container tatsächlich funktioniert.

Liveness Probe
  • Prüft, ob der Container noch lebt. Schlägt sie fehl, wird der Container neu gestartet.
Readiness Probe
  • Prüft, ob der Container bereit ist, Traffic zu empfangen. Schlägt sie fehl, wird der Pod aus dem Service entfernt, aber nicht neu gestartet – er bekommt einfach so lange keinen Traffic, bis die Probe wieder erfolgreich ist.
containers:
  - name: web
    image: nginx:1.25
    ports:
      - containerPort: 80
    readinessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 15
      periodSeconds: 20
Warum das die depends_on-Lücke schließt
  • Ein Service leitet Traffic nur an Pods weiter, deren Readiness Probe erfolgreich ist. Damit landet Traffic nie bei einer Instanz, die noch nicht bereit ist – unabhängig von der Startreihenfolge.

Rolling Updates

Was bei einem Compose-Update passiert
  • docker compose up -d nach einem Image-Wechsel ersetzt Container ohne eingebaute Kontrolle darüber, wie viele gleichzeitig offline sind.
Was ein Deployment stattdessen tut
  • Standardmäßig verwendet ein Deployment die Update-Strategie RollingUpdate: Es werden schrittweise neue Pods mit dem neuen Image gestartet und alte erst entfernt, wenn genügend neue bereit sind (erkennbar über die Readiness Probe).
Image aktualisieren
  • kubectl set image deployment/web web=nginx:1.26
Rollout beobachten
  • kubectl rollout status deployment/web
Rollout-Historie ansehen
  • kubectl rollout history deployment/web
Bei Problemen zurückrollen
  • kubectl rollout undo deployment/web

Skalierung

Deployment skalieren
  • kubectl scale deployment/web --replicas=3
Verteilung über die Nodes prüfen
  • kubectl get pods -o wide
  • Die drei Instanzen verteilen sich in der Regel automatisch über die verfügbaren Agent-Nodes.
Warum die Datenbank nicht einfach genauso skaliert wird
  • Würde db ebenfalls auf drei Replicas skaliert, entstünden drei unabhängige PostgreSQL-Instanzen ohne gemeinsamen Datenbestand – das produziert Dateninkonsistenz, keine Hochverfügbarkeit. Zustandsbehaftete Anwendungen wie Datenbanken benötigen einen anderen Ansatz (StatefulSet), der über den Rahmen dieses Kurses hinausgeht, aber als Begriff hier bewusst fällt.

Persistente Daten: PersistentVolumeClaim

In der ursprünglichen Compose-Datei sorgte volumes: db_data:/var/lib/postgresql/data dafür, dass die Datenbank einen Container-Neustart übersteht. Das Kubernetes-Äquivalent ist ein PersistentVolumeClaim (PVC).

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: db-data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
Im db-Deployment einbinden
  • Der Claim wird als Volume in den Pod eingehängt und im Container an den passenden Pfad gemountet.
spec:
  containers:
    - name: db
      image: postgres:16
      volumeMounts:
        - name: data
          mountPath: /var/lib/postgresql/data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: db-data
Anwenden und prüfen
  • kubectl apply -f db-pvc.yaml
  • kubectl get pvc

Übung: Rolling Update ohne Downtime beobachten

  1. Skaliert web zunächst auf 3 Replicas.
  2. Öffnet ein zweites Terminal und lasst dort fortlaufend Anfragen laufen, zum Beispiel mit watch curl -s http://web.lab.local.
  3. Startet im ersten Terminal ein Rolling Update auf ein anderes Image (nginx:1.26) und beobachtet parallel im zweiten Terminal, ob Anfragen fehlschlagen.
  4. Prüft mit kubectl rollout status deployment/web, wann der Rollout abgeschlossen ist.

Übung: Rollback im Fehlerfall

  1. Führt absichtlich ein Update auf ein nicht existierendes Image durch (nginx:kaputt).
  2. Beobachtet mit kubectl rollout status deployment/web, dass der Rollout hängen bleibt.
  3. Macht das Update mit kubectl rollout undo deployment/web rückgängig und bestätigt mit kubectl get pods, dass wieder die alte, funktionierende Version läuft.

Übung: Persistenz der Datenbank prüfen

  1. Bindet den PVC wie oben gezeigt ins db-Deployment ein und wendet die Änderung an.
  2. Legt über kubectl exec -it in den db-Pod eine Testtabelle oder einen Testeintrag in der Datenbank an.
  3. Löscht den db-Pod gezielt mit kubectl delete pod.
  4. Prüft nach dem automatischen Neustart, ob der zuvor angelegte Datenbestand noch vorhanden ist.