Fehlerbehebung bei Kubernetes-Pod-Ausfällen: Ein umfassender Leitfaden

Navigieren Sie durch die Komplexität von Kubernetes-Pod-Ausfällen mit diesem umfassenden Leitfaden. Lernen Sie den strukturierten Prozess zur Diagnose häufiger Probleme wie CrashLoopBackOff, ImagePullBackOff und Ressourcenerschöpfung. Wir erläutern, wie Sie wichtige Tools wie `kubectl describe` und `kubectl logs --previous` nutzen, um die Ursache zu identifizieren, Container-Exit-Status zu interpretieren und praktische Lösungen zu implementieren, um eine zuverlässige Anwendungsverfügbarkeit und -stabilität zu gewährleisten.

Fehlerbehebung bei Kubernetes-Pod-Ausfällen: Ein umfassender Leitfaden

Die Fehlerbehebung bei Kubernetes-Pod-Ausfällen erfordert weniger das Auswendiglernen jedes Status, sondern vielmehr das Wissen, wo Kubernetes Hinweise hinterlässt. Ein Pod fällt fast nie „still" aus. Der Scheduler, die Kubelet, die Container-Laufzeitumgebung, die Image-Registry, das Volume-Plugin und Ihre Anwendung hinterlassen alle Spuren an verschiedenen Stellen. Der Trick besteht darin, sie in der richtigen Reihenfolge zu überprüfen, damit Sie nicht zwanzig Minuten damit verbringen, Anwendungslogs für einen Pod zu lesen, der sein Image nie gezogen hat.

Normalerweise beginne ich mit einer Frage: Ist der Pod fehlgeschlagen, bevor der Container gestartet wurde, während des Container-Starts oder nachdem die Anwendung zu laufen begann? Diese einzelne Unterscheidung hält die Untersuchung auf dem Boden. Pending deutet normalerweise auf Probleme bei der Planung, dem Speicher oder der Image-Einrichtung hin. ImagePullBackOff deutet auf den Registry-Pfad, das Tag, die Anmeldeinformationen oder den Node-Egress hin. CrashLoopBackOff bedeutet normalerweise, dass der Prozess startet und dann beendet wird, obwohl der Grund eine Konfiguration, eine fehlende Datei, ein fehlerhafter Befehl, eine fehlgeschlagene Abhängigkeit oder Speicherdruck sein kann.


Die drei Säulen der Pod-Diagnose

Die Fehlerbehebung beginnt mit der Verwendung von drei primären kubectl-Befehlen, um alle verfügbaren Informationen über den fehlgeschlagenen Pod zu sammeln.

1. Erste Statusprüfung (kubectl get pods)

Der erste Schritt besteht immer darin, den aktuellen Status des Pods und seiner Container zu ermitteln. Achten Sie besonders auf die Spalten STATUS und READY.

kubectl get pods -n my-namespace

Interpretation des Pod-Status

Status Bedeutung Erste Maßnahme
Running Mindestens ein Container läuft; dies bedeutet nicht immer, dass die App Traffic bedient. Überprüfen Sie READY, Neustarts und Readiness-Ereignisse.
Pending Pod wurde von Kubernetes akzeptiert, aber Container wurden noch nicht erstellt. Überprüfen Sie Planungsereignisse oder den Image-Pull-Status.
CrashLoopBackOff Container startet, stürzt ab und Kubelet versucht, ihn wiederholt neu zu starten. Überprüfen Sie Anwendungslogs (kubectl logs --previous).
ImagePullBackOff Kubelet kann das erforderliche Container-Image nicht ziehen. Überprüfen Sie Image-Name, Tag und Registry-Anmeldeinformationen.
Error Pod wurde aufgrund eines Laufzeitfehlers oder eines fehlgeschlagenen Startbefehls beendet. Überprüfen Sie Logs und describe-Ereignisse.
Terminating/Unknown Pod wird heruntergefahren oder der Kubelet-Host reagiert nicht. Überprüfen Sie die Node-Gesundheit.

2. Tiefgehende Inspektion (kubectl describe pod)

Wenn der Status etwas anderes als Running ist, liefert der describe-Befehl entscheidenden Kontext, der Planungsentscheidungen, Ressourcenzuweisungen und Container-Status detailliert beschreibt.

kubectl describe pod [POD_NAME] -n my-namespace

Konzentrieren Sie sich auf diese Abschnitte in der Ausgabe:

  • Containers/Init Containers: Überprüfen Sie den State (insbesondere Waiting oder Terminated) und den Last State (wo der Fehlergrund oft aufgezeichnet ist, z.B. Reason: OOMKilled).
  • Resource Limits: Stellen Sie sicher, dass Limits und Requests korrekt gesetzt sind.
  • Events: Dies ist der kritischste Abschnitt. Ereignisse zeigen den Lebenszyklusverlauf, einschließlich Planungsfehlern, Volume-Mounting-Problemen und Image-Pull-Versuchen.

Tipp: Wenn der Abschnitt Events eine Meldung wie „0/N nodes available" anzeigt, kann der Pod wahrscheinlich aufgrund unzureichender Ressourcen (CPU, Speicher) oder nicht erfüllter Affinitätsregeln nicht geplant werden.

Lesen Sie Ereignisse von unten nach oben, wenn Sie den neuesten Hinweis möchten, aber ignorieren Sie ältere Ereignisse nicht. Ein Pod kann mehr als ein Problem haben. Beispielsweise kann ein Deployment mit FailedScheduling beginnen, weil der angeforderte Speicher zu hoch ist, und später nach dem Hinzufügen eines Nodes zu ImagePullBackOff wechseln. Wenn Sie nur den endgültigen Status betrachten, übersehen Sie möglicherweise die Änderung, die das Problem vorangebracht hat.

3. Überprüfung der Logs (kubectl logs)

Bei Laufzeitproblemen der Anwendung liefern Logs den Stacktrace oder Fehlermeldungen, die erklären, warum der Prozess beendet wurde.

# Aktuelle Container-Logs überprüfen
kubectl logs [POD_NAME] -n my-namespace

# Logs für einen bestimmten Container innerhalb des Pods überprüfen
kubectl logs [POD_NAME] -c [CONTAINER_NAME] -n my-namespace

# Entscheidend für CrashLoopBackOff: Logs des *vorherigen* fehlgeschlagenen Laufs überprüfen
kubectl logs [POD_NAME] --previous -n my-namespace

Wenn der Pod Sidecars hat, fügen Sie immer -c hinzu. Viele frustrierende Untersuchungen resultieren daraus, dass die Logs des gesunden Sidecars anstelle des fehlgeschlagenen Anwendungscontainers gelesen werden. Verwenden Sie bei Fehlern von Init-Containern ebenfalls den Init-Container-Namen mit -c:

kubectl logs [POD_NAME] -c [INIT_CONTAINER_NAME] -n my-namespace

Häufige Pod-Fehlerszenarien und Lösungen

Die meisten Pod-Fehler fallen in einige erkennbare Muster, die jeweils einen gezielten Diagnoseansatz erfordern.

Szenario 1: CrashLoopBackOff

Dies ist der häufigste Pod-Fehler. Er bedeutet, dass der Container erfolgreich startet, die Anwendung innerhalb des Containers jedoch sofort beendet wird (mit einem Exit-Code ungleich Null).

Diagnose:

  1. Verwenden Sie kubectl logs --previous, um den Traceback oder den Exit-Grund anzuzeigen.
  2. Verwenden Sie kubectl describe, um den Exit Code im Abschnitt Last State zu überprüfen.

Häufige Ursachen und Lösungen:

  • Exit-Code 1/2: Allgemeiner Anwendungsfehler, fehlende Konfigurationsdatei, Datenbankverbindungsfehler oder Anwendungsabsturz aufgrund fehlerhafter Eingabe.
    • Lösung: Debuggen Sie den Anwendungscode oder überprüfen Sie die eingehängten ConfigMaps/Secrets.
  • Fehlende Abhängigkeiten: Das Einstiegsskript benötigt Dateien oder Umgebungen, die nicht vorhanden sind.
    • Lösung: Überprüfen Sie das Dockerfile und den Image-Build-Prozess.
  • Falscher Befehl oder falsche Argumente: Das Container-Image ist gültig, aber der Befehl in der Pod-Spezifikation überschreibt den Image-Einstiegspunkt falsch.
    • Lösung: Vergleichen Sie den Deployment-command und die args mit dem erwarteten Startbefehl des Images. Testen Sie dasselbe Image nach Möglichkeit lokal.
  • Durch Probes ausgelöste Neustarts: Eine Liveness-Probe kann eine langsam startende App töten, bevor sie vollständig hochgefahren ist.
    • Lösung: Erhöhen Sie initialDelaySeconds, verwenden Sie eine startupProbe oder richten Sie die Probe auf einen günstigeren Health-Endpunkt.

Ein praktisches Muster besteht darin, eine temporäre Kopie mit demselben Image, aber einem harmlosen Befehl bereitzustellen und dann das Dateisystem und die Umgebung zu inspizieren:

kubectl run debug-image \
  --image=registry.example.com/app:tag \
  --restart=Never \
  --command -- sleep 3600

kubectl exec -it debug-image -- /bin/sh

Dies ersetzt nicht die Behebung des Deployments, hilft aber, einfache Fragen schnell zu beantworten: Ist die Konfigurationsdatei tatsächlich im Image, existiert die Binärdatei, hat der Container die erwartete Shell und sind Umgebungsvariablen vorhanden?

Szenario 2: ImagePullBackOff / ErrImagePull

Dies tritt auf, wenn die Kubelet das in der Pod-Definition angegebene Container-Image nicht abrufen kann.

Diagnose:

  1. Überprüfen Sie den Abschnitt Events von kubectl describe auf die spezifische Fehlermeldung (z.B. 404 Not Found oder authentication required).

Häufige Ursachen und Lösungen:

  • Tippfehler oder falsches Tag: Der Image-Name oder das Tag ist falsch.
    • Lösung: Korrigieren Sie den Image-Namen in der Deployment- oder Pod-Spezifikation.
  • Zugriff auf private Registry: Der Cluster hat keine Anmeldeinformationen, um von einer privaten Registry (wie Docker Hub, GCR, ECR) zu ziehen.
    • Lösung: Stellen Sie sicher, dass ein entsprechendes imagePullSecret in der Pod-Spezifikation referenziert wird und dass das Secret im Namespace existiert.
# Beispiel-Pod-Spezifikationsausschnitt für die Verwendung eines Pull-Secrets
spec:
  containers:
  ...
  imagePullSecrets:
  - name: my-registry-secret

Überprüfen Sie auch, wo das Pull-Secret lebt. Kubernetes-Secrets sind namespaced. Ein Secret namens regcred im default-Namespace hilft einem Pod im payments-Namespace nicht. Wenn dasselbe Image in einem Namespace funktioniert, in einem anderen jedoch fehlschlägt, vergleichen Sie Service Accounts und Image-Pull-Secrets, bevor Sie annehmen, dass die Registry defekt ist:

kubectl get serviceaccount default -n payments -o yaml
kubectl get secret regcred -n payments

Szenario 3: Pending-Status (Feststecken)

Ein Pod bleibt im Status Pending, was normalerweise darauf hindeutet, dass er nicht auf einen Node geplant werden kann oder auf Ressourcen (wie ein PersistentVolume) wartet.

Diagnose:

  1. Führen Sie kubectl describe aus und sehen Sie sich den Abschnitt Events an.

Häufige Ursachen und Lösungen:

  • Ressourcenerschöpfung: Dem Cluster fehlen Nodes mit ausreichend verfügbarer CPU oder Arbeitsspeicher, um die requests des Pods zu erfüllen.
    • Lösung: Vergrößern Sie den Cluster oder reduzieren Sie die Pod-Ressourcenanforderungen (falls möglich).
    • Beispiel für Ereignismeldung: 0/4 nodes are available: 4 Insufficient cpu.
  • Volume-Bindungsprobleme: Der Pod benötigt einen PersistentVolumeClaim (PVC), der nicht an ein zugrunde liegendes PersistentVolume (PV) gebunden werden kann.
    • Lösung: Überprüfen Sie den Status des PVC (kubectl get pvc) und stellen Sie sicher, dass die StorageClass funktioniert.
  • Selektor- oder Affinitätskonflikt: Der Pod fragt nach einem Node-Label, das nicht existiert, oder eine erforderliche Affinitätsregel schließt jeden Node aus.
    • Lösung: Vergleichen Sie nodeSelector, nodeAffinity und Node-Labels mit kubectl get nodes --show-labels.
  • Taints nicht toleriert: Nodes sind verfügbar, aber sie stoßen diesen Pod ab, weil ihm eine passende Tolerierung fehlt.
    • Lösung: Fügen Sie die beabsichtigte Tolerierung zum Pod hinzu oder entfernen Sie den Taint, wenn er keine echte Platzierungsregel mehr darstellt.

Szenario 4: OOMKilled (Wegen Speichermangels beendet)

Obwohl dies normalerweise zu einem CrashLoopBackOff-Status führt, ist die zugrunde liegende Ursache spezifisch: Der Container hat mehr Speicher verbraucht als das in seiner Spezifikation definierte Limit, was dazu führte, dass das Host-Betriebssystem (über die Kubelet) ihn zwangsweise beendet hat.

Diagnose:

  1. Überprüfen Sie kubectl describe -> Last State -> Reason: OOMKilled.

Lösungen:

  1. Limits erhöhen: Erhöhen Sie das Speicher-limit in der Pod-Spezifikation, um mehr Spielraum zu schaffen.
  2. Anwendung optimieren: Profilieren Sie die Anwendung, um ihren Speicherverbrauch zu reduzieren.
  3. Requests setzen: Stellen Sie sicher, dass requests nahe am tatsächlichen stabilen Verbrauch liegen, um die Planungszuverlässigkeit zu verbessern.
resources:
  limits:
    memory: "512Mi" # Erhöhen Sie diesen Wert
  requests:
    memory: "256Mi"

Seien Sie vorsichtig mit Speicher-"Lösungen", die nur das Limit erhöhen. Wenn die Anwendung ein Leck hat, kann ein höheres Limit den nächsten Fehler nur verzögern und den Node einem größeren Risiko aussetzen. Betrachten Sie den Speicher im Laufe der Zeit in Ihrem Metriksystem. Ein Sägezahnmuster, das nach der Garbage Collection zur Baseline zurückkehrt, unterscheidet sich von einem stetigen Anstieg bis zum OOM.

Szenario 5: CreateContainerConfigError und CreateContainerError

Diese Status werden leicht übersehen, da sie nicht wie Anwendungsfehler klingen. Sie bedeuten normalerweise, dass die Kubelet die Container-Konfiguration nicht zusammenstellen konnte.

Häufige Ursachen sind:

  • Ein referenzierter ConfigMap oder Secret existiert nicht im Namespace.
  • Ein Schlüssel in einem ConfigMap oder Secret ist falsch geschrieben.
  • Ein Volume-Mount-Pfad kollidiert mit einem anderen Mount.
  • Der Container referenziert einen ungültigen Sicherheitskontext.

Der schnellste Check ist immer noch describe:

kubectl describe pod [POD_NAME] -n my-namespace

Achten Sie auf Ereignismeldungen wie secret "app-config" not found oder configmap "settings" not found. Überprüfen Sie dann das Objekt:

kubectl get secret app-config -n my-namespace
kubectl get configmap settings -n my-namespace -o yaml

Dies ist ein häufiger Fehler in Deployment-Pipelines. Das Anwendungsmanifest wird angewendet, aber der Schritt zur Secret-Erstellung ist fehlgeschlagen oder wurde gegen den falschen Namespace ausgeführt.

Szenario 6: Running but Not Ready

Ein Pod kann Running anzeigen, während er dennoch unbrauchbar ist. Die Spalte READY gibt an, wie viele Container gemäß ihrer Readiness-Probes bereit sind. Ein Pod mit 1/2 oder 0/1 kann zwar am Leben, aber von den Service-Endpunkten entfernt sein.

Überprüfen Sie Endpunkte, wenn Traffic ausfällt, aber Pods lebendig aussehen:

kubectl get endpoints [SERVICE_NAME] -n my-namespace
kubectl describe pod [POD_NAME] -n my-namespace

Wenn die Endpunktliste leer ist, liegt das Problem möglicherweise an einer Readiness-Probe, einem Service-Selektor-Konflikt oder daran, dass die Anwendung auf einem anderen Port lauscht, als der Service erwartet. In echten Vorfällen verlieren Leute hier Zeit: Sie starten Pods immer wieder neu, obwohl die Pods nicht der Grund für den fehlenden Traffic sind.


Vermeidung zukünftiger Fehler: Best Practices

Robuste Anwendungen erfordern eine sorgfältige Konfiguration, um häufige Deployment-Fallstricke zu vermeiden.

Verwenden Sie Liveness- und Readiness-Probes

Die ordnungsgemäße Implementierung von Probes ermöglicht es Kubernetes, die Container-Gesundheit intelligent zu verwalten:

  • Liveness-Probes: Stellen fest, ob der Container gesund genug ist, um weiterzulaufen. Wenn die Liveness-Probe fehlschlägt, startet Kubelet den Container neu (Behebung von Softlocks).
  • Readiness-Probes: Stellen fest, ob der Container bereit ist, Traffic zu bedienen. Wenn die Readiness-Probe fehlschlägt, wird der Pod aus den Service-Endpunkten entfernt, wodurch fehlgeschlagene Anfragen vermieden werden, während sich der Container erholt.

Richten Sie Liveness-Probes nicht auf tiefe Abhängigkeitsprüfungen, es sei denn, Sie möchten wirklich, dass Kubernetes den Container jedes Mal neu startet, wenn diese Abhängigkeit einen kurzen Ausfall hat. Eine Datenbank, die für dreißig Sekunden nicht verfügbar ist, ist normalerweise kein Beweis dafür, dass der Prozess tot ist. Readiness ist der bessere Ort, um zu sagen: „Senden Sie diesem Pod jetzt keinen Traffic."

Erzwingen Sie Ressourcenlimits und -anforderungen

Definieren Sie immer Ressourcenanforderungen für Container. Dies verhindert, dass Pods übermäßige Ressourcen verbrauchen (was zu Node-Instabilität führt) und stellt sicher, dass der Scheduler den Pod auf einem Node mit ausreichender Kapazität platzieren kann.

Verwenden Sie Init-Container für die Einrichtung

Wenn ein Pod eine Abhängigkeitsprüfung oder Dateneinrichtung benötigt, bevor die Hauptanwendung startet (z.B. Warten auf den Abschluss einer Datenbankmigration), verwenden Sie einen Init-Container. Wenn der Init-Container fehlschlägt, startet der Pod ihn wiederholt neu, wodurch Einrichtungsfehler sauber von Anwendungslaufzeitfehlern isoliert werden.

Ein praktischer Triage-Ablauf

Wenn Sie Bereitschaftsdienst haben, verwenden Sie einen wiederholbaren Pfad:

  1. Überprüfen Sie kubectl get pods -n <namespace> -o wide, um Status, Neustarts, Alter und Node-Platzierung zu sehen.
  2. Führen Sie kubectl describe pod aus und lesen Sie Events, State, Last State, Mounts und Ressourceneinstellungen.
  3. Ziehen Sie Logs mit kubectl logs, fügen Sie --previous für neu gestartete Container und -c für Multi-Container-Pods hinzu.
  4. Wenn der Pod Pending ist, inspizieren Sie Planung, Taints, Node-Labels und PVCs, bevor Sie App-Logs lesen.
  5. Wenn der Pod Running ist, aber keinen Traffic erhält, inspizieren Sie Readiness-Probes, Service-Selektoren und Endpunkte.
  6. Wenn der Pod OOMKilled wurde, vergleichen Sie Limits mit tatsächlichen Speicherdiagrammen, bevor Sie die Zahl einfach erhöhen.

Diese Reihenfolge verhindert, dass Sie direkt zur Anwendung springen, wenn Kubernetes sie noch nicht einmal gestartet hat.

Abschließende Überprüfung

Die nützlichste Gewohnheit ist, Symptome von Ursachen zu trennen. CrashLoopBackOff ist ein Symptom. Die Ursache könnte ein fehlendes Secret, eine fehlerhafte Migration, eine Liveness-Probe oder ein Speicherlimit sein. Pending ist ein Symptom. Die Ursache könnte CPU-Anforderungen, ein PVC, ein Taint oder ein Node-Selektor sein. Lassen Sie sich vom Pod-Status sagen, wo Sie suchen sollen, und dann lassen Sie Ereignisse und Logs sagen, was sich geändert hat.