Veröffentlicht am

Kubernetes Resilience Patterns für produktive Cluster

Teilen:
Authors

Kubernetes Resilience Patterns: Ausfallsicherheit fuer produktive Cluster

TL;DR

  • Resilienz in Kubernetes ergibt sich nicht automatisch -- sie erfordert bewusste Konfiguration von Probes, Resource Limits, Anti-Affinity und PodDisruptionBudgets
  • Pod Anti-Affinity verteilt Replicas ueber Nodes und Availability Zones, damit ein einzelner Ausfall nicht alle Instanzen trifft
  • PodDisruptionBudgets (PDB) schuetzen vor zu aggressiven Node-Drains bei Upgrades oder Cluster-Autoscaler-Aktionen
  • Circuit Breaker und Retries gehoeren in die Anwendung oder in ein Service Mesh, nicht in Kubernetes selbst
  • Chaos Engineering (z.B. mit Litmus oder chaos-mesh) deckt Schwachstellen auf, bevor die Produktion sie zeigt

Kubernetes ist nicht von allein ausfallsicher

Eine verbreitete Fehleinschaetzung: "Kubernetes ist fehlertolerant." Das stimmt nur zur Haelfte. Kubernetes startet abgestuerzte Pods neu und verteilt Workloads auf verfuegbare Nodes. Aber es macht keine Aussage darueber, ob Ihre Anwendung den Ausfall eines Pods ueberlebt, ob Ihre Daten konsistent bleiben, oder ob ein Node-Drain waehrend eines Upgrades den gesamten Service kurzzeitig offline nimmt.

Resilience Patterns sind die bewussten Architektur-Entscheidungen, die den Unterschied zwischen "Kubernetes startet den Pod neu" und "der Service bleibt fuer Endnutzer verfuegbar" ausmachen.

Pattern 1: Pod Anti-Affinity und Topology Spread

Das Grundproblem: Der Kubernetes Scheduler platziert Pods standardmaessig dort, wo Ressourcen frei sind. Ohne weitere Konfiguration koennen alle drei Replicas einer Anwendung auf demselben Node landen. Faellt der Node aus, sind alle drei weg.

Pod Anti-Affinity

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - order-service
            topologyKey: kubernetes.io/hostname
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - order-service
              topologyKey: topology.kubernetes.io/zone
      containers:
      - name: order-service
        image: registry.example.com/order-service:1.5.2
        resources:
          requests:
            cpu: "200m"
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"

Die Konfiguration hat zwei Ebenen:

  • required auf Hostname-Ebene: Zwei Pods der gleichen App duerfen nie auf demselben Node laufen. Hart erzwungen.
  • preferred auf Zone-Ebene: Kubernetes versucht, die Pods ueber Availability Zones zu verteilen, erzwingt es aber nicht. Das ist sinnvoll, weil bei kleinen Clustern nicht immer genug Zonen vorhanden sind.

TopologySpreadConstraints (Alternative)

Seit Kubernetes 1.19 gibt es topologySpreadConstraints als feingranularere Alternative zu Anti-Affinity. Der Vorteil: Sie definieren einen maxSkew, der angibt, wie ungleich die Verteilung maximal sein darf.

topologySpreadConstraints:
- maxSkew: 1
  topologyKey: topology.kubernetes.io/zone
  whenUnsatisfiable: DoNotSchedule
  labelSelector:
    matchLabels:
      app: order-service
- maxSkew: 1
  topologyKey: kubernetes.io/hostname
  whenUnsatisfiable: ScheduleAnyway
  labelSelector:
    matchLabels:
      app: order-service

maxSkew: 1 bedeutet: Der Unterschied zwischen der Zone mit den meisten und der Zone mit den wenigsten Pods darf maximal 1 betragen. Fuer die meisten Services ist das die richtige Einstellung.

Pattern 2: PodDisruptionBudgets

PodDisruptionBudgets (PDB) werden oft vergessen und sind trotzdem eines der wichtigsten Resilience-Tools. Sie definieren, wie viele Pods einer Anwendung gleichzeitig offline sein duerfen -- etwa bei einem Node-Drain, einem Cluster-Upgrade oder einer Cluster-Autoscaler-Aktion.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: order-service-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: order-service

Ohne PDB kann kubectl drain alle Pods eines Nodes gleichzeitig evicten. Mit minAvailable: 2 und drei Replicas darf immer nur ein Pod gleichzeitig heruntergefahren werden.

PDB-EinstellungEffektEmpfohlener Einsatz
minAvailable: 2Mindestens 2 Pods muessen immer laufenServices mit 3+ Replicas
maxUnavailable: 1Maximal 1 Pod darf gleichzeitig fehlenGleicher Effekt, andere Semantik
minAvailable: "50%"Mindestens die Haelfte muss laufenGroessere Deployments (10+ Pods)
maxUnavailable: 0Kein Pod darf entfernt werdenNur fuer absolute Notfaelle, blockiert Upgrades

Achtung: maxUnavailable: 0 blockiert Node-Drains komplett. Das kann sinnvoll sein fuer kritische Datenbankprozesse, fuehrt aber dazu, dass Cluster-Upgrades haengen bleiben. Verwenden Sie es nur, wenn Sie einen manuellen Freigabeprozess haben.

Mehr Details zum Thema Kapazitaetsplanung und wie PDBs mit dem Cluster Autoscaler zusammenspielen finden Sie unter Kubernetes Capacity Planning.

Pattern 3: Health Checks richtig konfigurieren

Liveness- und Readiness-Probes sind keine optionalen Features. Ohne sie weiss Kubernetes nicht, ob ein Container tatsaechlich funktioniert -- er weiss nur, ob der Prozess laeuft.

Haeufige Fehler:

  • Liveness-Probe auf eine Dependency zeigen lassen. Wenn die Liveness-Probe die Datenbank prueft und die DB kurz nicht erreichbar ist, werden alle Pods gekillt. Genau das Gegenteil von Resilienz.
  • Zu kurze initialDelaySeconds. Die Anwendung ist noch nicht gestartet, aber Kubernetes prueft schon und killt den Pod. CrashLoopBackoff.
  • Identische Liveness- und Readiness-Probes. Die Liveness-Probe soll pruefen: "Laeuft der Prozess noch?" Die Readiness-Probe soll pruefen: "Kann der Prozess Requests beantworten?" Das sind zwei verschiedene Fragen.

Best Practices:

livenessProbe:
  httpGet:
    path: /healthz        # Prueft nur den Prozess selbst, keine Dependencies
    port: 8080
  initialDelaySeconds: 15  # Genug Zeit zum Starten
  periodSeconds: 10
  failureThreshold: 3      # Drei Fehlversuche bevor der Pod gekillt wird
  timeoutSeconds: 3

readinessProbe:
  httpGet:
    path: /ready           # Prueft Prozess UND kritische Dependencies
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 2      # Schneller reagieren, Pod wird nur aus Service genommen
  timeoutSeconds: 3

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30     # 30 * 5s = 150s maximale Startzeit
  periodSeconds: 5

Die startupProbe ist seit Kubernetes 1.20 stabil und loest ein altes Problem: Anwendungen mit langer Startzeit. Ohne startupProbe mussten Sie initialDelaySeconds auf der Liveness-Probe hochsetzen, was die Erkennung von tatsaechlich toten Pods verzoegert.

Pattern 4: Circuit Breaker und Retries

Circuit Breaker und Retries sind streng genommen kein Kubernetes-Feature. Sie gehoeren entweder in die Anwendung (z.B. via resilience4j in Java, polly in .NET) oder in ein Service Mesh.

Warum ein Service Mesh sinnvoll sein kann

Ein Service Mesh wie Istio oder Linkerd setzt Circuit Breaker und Retries transparent auf Netzwerk-Ebene um. Der Vorteil: Sie muessen nicht jeden Service einzeln anpassen.

Vergleich der Optionen:

AnsatzVorteileNachteile
In der Anwendung (Libraries)Volle Kontrolle, kein Infrastruktur-OverheadMuss in jedem Service implementiert werden
Service Mesh (Istio/Linkerd)Transparent, einheitliche PolicyZusaetzliche Komplexitaet, Resource-Overhead
API Gateway (z.B. Kong, Envoy)Nur fuer externen TrafficDeckt Service-zu-Service-Kommunikation nicht ab

Fuer Cluster mit weniger als 10 Services reicht meist ein anwendungsseitiger Ansatz. Ab 20+ interagierenden Services wird ein Service Mesh wirtschaftlich sinnvoll.

Wer tiefer in das Thema Load Balancing und Traffic Management einsteigen will, findet unter Kubernetes Load Balancing weiterfuehrende Details.

Pattern 5: Chaos Engineering

Chaos Engineering bedeutet nicht "zufaellig Sachen kaputtmachen". Es bedeutet: Hypothesen ueber das Systemverhalten formulieren, kontrolliert Stoerungen einfuegen, beobachten, ob die Hypothese zutrifft.

Einfacher Einstieg mit kubectl:

# Hypothese: "Wenn ein Pod des order-service ausfaellt,
# bemerken Endnutzer keine Unterbrechung."

# Schritt 1: Monitoring oeffnen (Grafana, kubectl top, etc.)

# Schritt 2: Einen Pod loeschen
kubectl delete pod -l app=order-service --field-selector=status.phase=Running \
  | head -1

# Schritt 3: Beobachten
# - Wird der Pod automatisch neu erstellt? (Ja, durch das ReplicaSet)
# - Gibt es Fehler in den Logs der anderen Pods?
# - Steigt die Error-Rate im Monitoring?
# - Wie lange dauert es, bis der neue Pod ready ist?

# Schritt 4: Ergebnis dokumentieren

Fuer systematischere Chaos-Tests gibt es Tools wie Litmus, chaos-mesh oder Gremlin. Der Artikel zu Kubernetes Chaos Engineering geht darauf im Detail ein.

Resilienz-Checkliste fuer produktive Cluster

Bevor Sie einen Service als "production-ready" betrachten, sollten diese Punkte erfuellt sein:

KategorieCheckPrioritaet
ReplicasMindestens 3 Replicas fuer kritische ServicesHoch
Anti-AffinityPods auf verschiedene Nodes verteiltHoch
ProbesLiveness, Readiness und Startup konfiguriertHoch
PDBPodDisruptionBudget definiertHoch
Resource LimitsRequests und Limits fuer CPU und Memory gesetztHoch
HPAAutoscaling fuer variable Workloads konfiguriertMittel
Topology SpreadVerteilung ueber Availability ZonesMittel
BackupsPersistent Volumes regelmaessig gesichertHoch
Chaos TestsGrundlegende Ausfallszenarien getestetMittel
RunbooksIncident-Response-Playbooks dokumentiertMittel

Diese Checkliste laesst sich gut in ein CI/CD-Gate integrieren. Tools wie OPA/Gatekeeper oder Kyverno koennen viele dieser Checks automatisiert erzwingen. Fuer Details zur Absicherung der CI/CD-Pipeline empfehle ich den Artikel zu Kubernetes GitOps Security.

Monitoring: Die andere Haelfte der Resilienz

Resilienz-Patterns sind nur so gut wie Ihr Monitoring. Wenn ein Pod stirbt und automatisch neu startet, aber niemand es bemerkt, haben Sie ein Problem, das sich langsam akkumuliert.

Relevante Metriken:

  • Pod Restart Count: Steigende Restart-Zahlen deuten auf instabile Pods hin.
  • Request Error Rate: Anteil der 5xx-Responses pro Service.
  • Request Latency (p50, p95, p99): Steigende Latenz ist oft ein Fruehindikator fuer Probleme.
  • PDB Disruptions Allowed: Zeigt an, ob ein Node-Drain aktuell blockiert wuerde.
  • Node Conditions: NotReady-Nodes muessen sofort untersucht werden.

Wer seinen Observability Stack noch aufbauen muss, findet unter Kubernetes Observability Stack eine praxisnahe Anleitung.

Haeufige Fehler und wie man sie vermeidet

Fehler 1: Keine Resource Limits setzen. Ohne Limits kann ein einzelner Pod einen ganzen Node auslasten und andere Pods per OOM-Kill beenden. Das ist das "Noisy Neighbor"-Problem. Setzen Sie immer Requests und Limits. Details dazu unter Kubernetes OOM-Kills vermeiden.

Fehler 2: PDBs vergessen. Ihr Service hat drei Replicas und Anti-Affinity -- aber ohne PDB kann ein kubectl drain alle drei Pods gleichzeitig evicten, wenn sie zufaellig auf Nodes liegen, die nacheinander gedrained werden.

Fehler 3: Readiness-Probe fehlt. Ohne Readiness-Probe schickt Kubernetes Traffic an Pods, die noch starten oder deren Dependencies noch nicht bereit sind. Das fuehrt zu Fehlern bei Rolling Updates.

Fehler 4: Zu aggressive Liveness-Probe. periodSeconds: 1 mit failureThreshold: 1 bedeutet: Ein einziger langsamer Health Check toetet den Pod. Bei kurzzeitigen Lastspitzen reisst das die gesamte Anwendung herunter.

Fehler 5: Kein Chaos Testing. Sie wissen nicht, ob Ihr System resilient ist, bis Sie es testen. "Es sollte funktionieren" ist keine Grundlage fuer Produktionsbetrieb.

Fazit

Resilienz in Kubernetes ist kein einzelnes Feature, das man einschaltet. Es ist eine Sammlung von Patterns, die zusammenwirken: Anti-Affinity verteilt Pods, PDBs schuetzen vor zu aggressiven Drains, Probes erkennen fehlerhafte Container, und Chaos Engineering deckt die Luecken auf, die man in der Theorie uebersieht.

Fangen Sie mit den Basics an: Replicas, Probes, Resource Limits, PDB. Das deckt 80% der Ausfallszenarien ab. Die fortgeschrittenen Patterns (Service Mesh, Multi-Region) kommen spaeter, wenn die Grundlagen stehen.

Wenn Sie Unterstuetzung bei der Analyse und Optimierung Ihrer Cluster-Resilienz brauchen, stehen wir Ihnen gern zur Verfuegung unter /kontakt.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen

kubernetesresilience

Kubernetes Deutschland: Retry Pattern für resiliente Systeme

Erfahren Sie, wie das Retry Pattern die Resilienz und Fehlertoleranz von Kubernetes-Anwendungen in Deutschland optimiert. Steigern Sie die Verfügbarkeit Ihrer Systeme und gewährleisten Sie mit intelligenten Wiederholungsstrategien eine robuste Performance auch in anspruchsvollen Umgebungen.

Weiterlesen →