Veröffentlicht am

CrashLoopBackOff debuggen: Ursachen und Lösungen

Teilen:
Authors

Kubernetes CrashLoopBackOff: Systematisches Troubleshooting in 5 Minuten

TL;DR

  • CrashLoopBackOff bedeutet: Container startet, crasht, Kubernetes versucht Neustart mit exponentiellem Backoff (10s bis max 5min).
  • Erster Befehl immer: kubectl logs <pod> --previous -- zeigt die Logs des letzten gecrashteten Containers.
  • Exit Code 137 = OOMKilled (zu wenig Memory). Exit Code 1 = Anwendungsfehler. Exit Code 0 = Container beendet sich sofort ohne Fehler.
  • Die haeufigsten Ursachen: fehlende Env-Vars, falsche Liveness Probes, OOM, fehlende ConfigMaps/Secrets.
  • Nutzen Sie kubectl debug fuer interaktive Analyse, ohne den Pod neu deployen zu muessen.

Was CrashLoopBackOff bedeutet

Wenn kubectl get pods diesen Status zeigt, steckt Ihr Container in einer Neustartschleife:

NAME        READY   STATUS             RESTARTS      AGE
my-app      0/1     CrashLoopBackOff   7 (3m ago)    12m

Kubernetes versucht den Container immer wieder zu starten, wartet aber nach jedem Fehlversuch laenger: 10 Sekunden, 20, 40, 80, 160, bis maximal 5 Minuten. Das ist der "exponential backoff". Der Container selbst crasht -- Kubernetes versucht nur, ihn am Leben zu halten.

Der Diagnose-Workflow: 3 Befehle

Starten Sie immer mit diesen drei Befehlen. In 80% der Faelle finden Sie damit die Ursache:

# 1. Logs des letzten gecrashteten Containers
kubectl logs my-app --previous

# 2. Pod-Details mit Events und Exit Code
kubectl describe pod my-app

# 3. Cluster-Events fuer den Pod
kubectl get events --field-selector involvedObject.name=my-app --sort-by='.lastTimestamp'

Der wichtigste Befehl ist --previous. Ohne dieses Flag sehen Sie nur die Logs des aktuell (erneut) gestarteten Containers, der moeglicherweise schon wieder abstuerzt, bevor er etwas loggt.

Exit Codes verstehen

Der Exit Code verraet die Ursache. Sie finden ihn in der Ausgabe von kubectl describe pod:

Last State:     Terminated
  Reason:       Error
  Exit Code:    137
Exit CodeSignalBedeutungTypische Ursache
0--Normales EndeContainer ohne Daemon-Prozess
1--Allgemeiner FehlerAnwendungsfehler, Exception
126--Nicht ausfuehrbarPermissions-Problem
127--Command nicht gefundenFalscher Pfad oder fehlendes Binary
137SIGKILLErzwungenes BeendenOOMKilled oder kubectl delete --force
139SIGSEGVSegmentation FaultSpeicherfehler im Binary
143SIGTERMGraceful ShutdownNormaler Pod-Termination

Die 8 haeufigsten Ursachen

1. Fehlende Umgebungsvariablen (Exit Code 1)

Die Anwendung erwartet eine Umgebungsvariable, die nicht gesetzt ist. Passiert haeufig nach dem Umbenennen eines Secrets oder einer ConfigMap.

# Gesetzte Env-Vars im Pod pruefen
kubectl exec my-app -- env | sort

# Wenn der Pod nicht laeuft, direkt im Manifest pruefen
kubectl get pod my-app -o jsonpath='{.spec.containers[0].env}' | jq .

Loesung -- Env-Vars korrekt referenzieren:

spec:
  containers:
    - name: app
      env:
        - name: DB_HOST
          value: "postgres.production.svc.cluster.local"
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: password

2. OOMKilled (Exit Code 137)

Der Container verbraucht mehr Memory als sein Limit erlaubt. Kubernetes killt ihn mit SIGKILL.

# Aktuellen Memory-Verbrauch pruefen
kubectl top pod my-app

# Memory-Limits im Pod
kubectl get pod my-app -o jsonpath='{.spec.containers[0].resources}' | jq .

Loesung -- entweder Limit erhoehen oder die Anwendung optimieren:

spec:
  containers:
    - name: app
      resources:
        requests:
          memory: "256Mi"
          cpu: "250m"
        limits:
          memory: "512Mi"

Fuer Java-Anwendungen: Setzen Sie die Heap Size explizit mit -Xmx und -XX:MaxRAMPercentage. Ohne diese Flags versucht die JVM, den gesamten verfuegbaren Speicher zu nutzen.

3. Liveness Probe schlaegt fehl

Die Liveness Probe prueft, ob der Container noch lebt. Wenn sie fehlschlaegt, killt Kubernetes den Container. Das Problem: Die Probe kann zu aggressiv konfiguriert sein.

# Probe-Events pruefen
kubectl describe pod my-app | grep -A5 "Liveness"

# Manuell testen
kubectl exec my-app -- wget -qO- http://localhost:8080/healthz

Typische Fehlkonfiguration und Loesung:

spec:
  containers:
    - name: app
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
        initialDelaySeconds: 45    # Genug Zeit zum Starten geben
        periodSeconds: 10
        timeoutSeconds: 5
        failureThreshold: 3        # 3 Fehlversuche bevor Kill
      startupProbe:                # Ab K8s 1.20: separater Startup Check
        httpGet:
          path: /healthz
          port: 8080
        failureThreshold: 30
        periodSeconds: 5           # Bis zu 150s zum Starten

Die startupProbe ist oft die bessere Loesung als ein hoher initialDelaySeconds-Wert, weil sie die Liveness-Checks erst aktiviert, nachdem die Anwendung tatsaechlich bereit ist.

4. ConfigMap oder Secret nicht gefunden

Wenn ein Pod eine ConfigMap oder ein Secret referenziert, das nicht existiert, startet der Container gar nicht erst.

# Existiert die ConfigMap?
kubectl get configmap app-config -n production

# Existiert das Secret?
kubectl get secret app-secret -n production

# Events zeigen den Fehler
kubectl describe pod my-app | grep -i "warning"

Loesung:

# ConfigMap erstellen
kubectl create configmap app-config \
  --from-file=config.yaml=./config/production.yaml \
  -n production

# Secret erstellen
kubectl create secret generic app-secret \
  --from-literal=api-key=abc123 \
  -n production

5. Falscher Command oder Entrypoint

Der Container versucht ein Binary auszufuehren, das nicht existiert oder nicht ausfuehrbar ist.

# Command im Pod pruefen
kubectl get pod my-app -o jsonpath='{.spec.containers[0].command}' | jq .

# Interaktiv im Image pruefen
kubectl run debug --rm -it --image=myapp:v2.1 --restart=Never -- /bin/sh

Wichtig: command in der Pod-Spec ueberschreibt den ENTRYPOINT des Docker-Images. args ueberschreibt CMD. Das verwirrt viele Teams:

DockerfilePod SpecErgebnis
ENTRYPOINT + CMD--Dockerfile-Werte
ENTRYPOINT + CMDcommand gesetztcommand ueberschreibt ENTRYPOINT, CMD ignoriert
ENTRYPOINT + CMDargs gesetztENTRYPOINT bleibt, args ueberschreibt CMD
ENTRYPOINT + CMDcommand + argsBeide ueberschrieben

6. Volume Mount Fehler

Falscher Mount-Pfad, fehlende PVC oder Permissions-Problem auf dem Volume.

# Volume-Status pruefen
kubectl get pvc -n production

# Mount-Details
kubectl describe pod my-app | grep -A10 "Mounts"

7. Dependency nicht erreichbar

Die Anwendung versucht beim Start eine Verbindung zu einer Datenbank oder einem externen Service herzustellen und crasht, wenn diese nicht erreichbar ist.

Loesung mit Init-Container:

initContainers:
  - name: wait-for-postgres
    image: busybox:1.36
    command:
      - sh
      - -c
      - "until nc -z postgres.production.svc.cluster.local 5432; do echo 'Warte auf PostgreSQL...'; sleep 3; done"

8. Container beendet sich sofort (Exit Code 0)

Der Container startet und stoppt ohne Fehler. Das passiert, wenn kein lang laufender Prozess vorhanden ist -- zum Beispiel ein Script, das einmalig laeuft und dann beendet.

# Exit Code pruefen
kubectl describe pod my-app | grep "Exit Code"

Wenn der Container als Daemon laufen soll, stellen Sie sicher, dass der Hauptprozess im Vordergrund laeuft (nicht als Background-Prozess mit &).

Fortgeschrittenes Debugging

kubectl debug: Interaktive Analyse

Ab Kubernetes 1.25+ koennen Sie einen Debug-Container direkt in den laufenden (oder crashenden) Pod injizieren:

# Debug-Container im gleichen Pod starten (teilt Netzwerk und Volumes)
kubectl debug -it my-app --image=nicolaka/netshoot --target=app

# Innerhalb des Debug-Containers:
# Netzwerk testen
curl -v http://localhost:8080/healthz
nslookup postgres.production.svc.cluster.local

# Filesystem pruefen
ls -la /app/
cat /app/config/settings.yaml

Automatisiertes Debug-Script

Fuer wiederholtes Debugging hilft ein Script, das alle relevanten Informationen sammelt:

#!/bin/bash
POD=$1
NS=${2:-default}

echo "=== Pod Status ==="
kubectl get pod "$POD" -n "$NS" -o wide

echo -e "\n=== Exit Code ==="
kubectl get pod "$POD" -n "$NS" \
  -o jsonpath='{.status.containerStatuses[0].lastState.terminated.exitCode}'
echo ""

echo -e "\n=== Letzte Logs (gecrashteter Container) ==="
kubectl logs "$POD" -n "$NS" --previous --tail=30 2>/dev/null \
  || echo "Keine vorherigen Logs verfuegbar"

echo -e "\n=== Aktuelle Logs ==="
kubectl logs "$POD" -n "$NS" --tail=15 2>/dev/null \
  || echo "Container laeuft nicht"

echo -e "\n=== Events ==="
kubectl get events -n "$NS" \
  --field-selector "involvedObject.name=$POD" \
  --sort-by='.lastTimestamp' | tail -10

echo -e "\n=== Resource Requests/Limits ==="
kubectl get pod "$POD" -n "$NS" \
  -o jsonpath='{.spec.containers[0].resources}' | jq . 2>/dev/null

Speichern Sie das als crashloop-debug.sh und nutzen Sie es mit:

chmod +x crashloop-debug.sh
./crashloop-debug.sh my-app production

Zusammenfassung: Diagnose-Tabelle

UrsacheExit CodeErster Diagnose-BefehlLoesung
Anwendungsfehler1kubectl logs --previousCode oder Config fixen
Fehlende Env-Vars1kubectl logs --previousEnv/Secret/ConfigMap pruefen
OOMKilled137kubectl describe podMemory Limit erhoehen
Liveness Probe--kubectl describe pod EventsinitialDelaySeconds / startupProbe
ConfigMap fehlt--kubectl describe pod EventsFehlende Ressource erstellen
Command falsch127kubectl describe podcommand/args korrigieren
Volume Mount--kubectl describe podPVC und Permissions pruefen
Dependency fehlt1kubectl logs --previousInit-Container hinzufuegen

Der wichtigste Tipp zum Schluss: Immer zuerst kubectl logs <pod> --previous ausfuehren. Dieser eine Befehl loest die Haelfte aller CrashLoopBackOff-Probleme.

Weiterführende Artikel


Wenn Sie ein wiederkehrendes CrashLoopBackOff-Problem haben, das Sie nicht loesen koennen, oder Unterstuetzung beim Aufbau einer stabilen Kubernetes-Plattform brauchen, helfen wir gerne -- Kontakt aufnehmen.

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