- Authors

- Name
- Phillip Pham
- @ddppham
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 debugfuer 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 Code | Signal | Bedeutung | Typische Ursache |
|---|---|---|---|
| 0 | -- | Normales Ende | Container ohne Daemon-Prozess |
| 1 | -- | Allgemeiner Fehler | Anwendungsfehler, Exception |
| 126 | -- | Nicht ausfuehrbar | Permissions-Problem |
| 127 | -- | Command nicht gefunden | Falscher Pfad oder fehlendes Binary |
| 137 | SIGKILL | Erzwungenes Beenden | OOMKilled oder kubectl delete --force |
| 139 | SIGSEGV | Segmentation Fault | Speicherfehler im Binary |
| 143 | SIGTERM | Graceful Shutdown | Normaler 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:
| Dockerfile | Pod Spec | Ergebnis |
|---|---|---|
| ENTRYPOINT + CMD | -- | Dockerfile-Werte |
| ENTRYPOINT + CMD | command gesetzt | command ueberschreibt ENTRYPOINT, CMD ignoriert |
| ENTRYPOINT + CMD | args gesetzt | ENTRYPOINT bleibt, args ueberschreibt CMD |
| ENTRYPOINT + CMD | command + args | Beide 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
| Ursache | Exit Code | Erster Diagnose-Befehl | Loesung |
|---|---|---|---|
| Anwendungsfehler | 1 | kubectl logs --previous | Code oder Config fixen |
| Fehlende Env-Vars | 1 | kubectl logs --previous | Env/Secret/ConfigMap pruefen |
| OOMKilled | 137 | kubectl describe pod | Memory Limit erhoehen |
| Liveness Probe | -- | kubectl describe pod Events | initialDelaySeconds / startupProbe |
| ConfigMap fehlt | -- | kubectl describe pod Events | Fehlende Ressource erstellen |
| Command falsch | 127 | kubectl describe pod | command/args korrigieren |
| Volume Mount | -- | kubectl describe pod | PVC und Permissions pruefen |
| Dependency fehlt | 1 | kubectl logs --previous | Init-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
- Kubernetes OOMKilled Troubleshooting
- Kubernetes Pod Pending Troubleshooting
- Kubernetes Service nicht erreichbar
- Kubernetes Security Hardening Checkliste
- CKA Zertifizierung Guide
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
Kubernetes Pod Pending lösen: Ursachen und Fixes
Kubernetes Pod bleibt im Status Pending? Dieser Guide zeigt alle Ursachen und Lösungen von Resource Limits über Node Affinity bis hin zu Taints.
CoreDNS Debugging: Kubernetes-DNS Probleme lösen
DNS-Probleme in Kubernetes systematisch debuggen: CoreDNS-Logs, ndots-Konfiguration, NXDOMAIN-Fehler und Corefile-Optimierung für schnellere Auflösung.
Ephemeral Containers: Live-Debugging in Kubernetes
Ephemeral Containers fuer Live-Debugging in Kubernetes nutzen. Mit kubectl debug laufende Pods analysieren, Distroless-Images debuggen und Netzwerkprobleme loesen.
Kubernetes Troubleshooting: Systematisch debuggen
Kubernetes-Probleme systematisch debuggen mit kubectl describe, logs und debug. Lösungen für ImagePullBackOff, CrashLoopBackOff, Pending Pods und DNS-Fehler.
ContainerCreating hängt: Ursachen finden und beheben
Kubernetes Pod bleibt im Status ContainerCreating? Die drei häufigsten Ursachen und Lösungen für Image Pull, Volume Mount und Init Container Probleme.