CrashLoopBackOff bedeutet, dass ein Container in einem Pod wiederholt abstürzt oder sich beendet und Kubernetes ihn deshalb immer wieder neu startet, mit einer Wartezeit dazwischen, die nach jedem Fehlschlag wächst. Der Status ist kein Fehler von Kubernetes, sondern die ehrliche Meldung, dass dein Container etwas tut, das er nicht tun sollte.
Die gute Nachricht: In den allermeisten Fällen steckt die Ursache direkt in den Logs oder Events des Pods, du musst nur wissen, wo du nachsiehst. Die schlechte Nachricht: Ein CrashLoopBackOff kann von einem simplen Tippfehler im Kommando bis zu einer Race Condition mit der Datenbank praktisch alles bedeuten.
Ich betreibe Kubernetes-Cluster in Produktion und habe das Kubernetes-Praxisbuch bei Rheinwerk geschrieben. Alle meine Beiträge zu Kubernetes findest du gesammelt auf der Seite Kubernetes.
Was der Status CrashLoopBackOff bei einem Kubernetes Pod wirklich sagt
CrashLoopBackOff ist keine Phase des Pods, sondern ein Grund, der aus dem Zustand eines einzelnen Containers abgeleitet wird. Die Phase des Pods bleibt in dieser Zeit meist auf „Running", während ein Container darin ständig zwischen „Running" und „Terminated" wechselt. Die STATUS-Spalte von kubectl get pods zeigt dir dann den Grund des zuletzt gescheiterten Containers an, nicht den Zustand des ganzen Pods.
Der Name verrät auch die Mechanik dahinter: Nach jedem Absturz wartet Kubernetes eine Weile, bevor es den Container erneut startet, und diese Wartezeit verdoppelt sich mit jedem weiteren Fehlschlag, bis zu einer Obergrenze von einigen Minuten. Das schützt den Cluster davor, dass ein kaputter Container die Node mit endlosen Neustartversuchen belastet. Für dich bedeutet das: Je länger ein Pod schon im CrashLoopBackOff steckt, desto seltener siehst du live einen frischen Neustart, die Ursache liegt also fast immer schon in den vorherigen Logs. Den genauen Zusammenhang zwischen Pod-Phase und Container-Status beschreibt die Kubernetes-Dokumentation zum Pod-Lifecycle.
Diagnose in drei Befehlen
Für die Fehlersuche brauchst du selten mehr als drei Befehle, in dieser Reihenfolge. Zuerst ein Überblick, dann die Details, dann die Logs des zuletzt gescheiterten Versuchs. Als Merkliste für den Ernstfall, in genau dieser Abfolge:
- Events aus
describe lesen, sie nennen den Grund oft direkt.
- Logs des vorherigen Versuchs mit
--previous holen.
- Exit-Code im Last State ansehen und einordnen.
- Konfiguration prüfen: ConfigMap, Secret, Umgebungsvariablen, Pfade.
- Probes prüfen, vor allem zu kurze Startfristen.
- Ressourcen prüfen, Memory-Limit und OOM-Kill zuletzt.
kubectl get pods -n meine-anwendung
kubectl describe pod meine-anwendung-7d9f8c6b5-x2k9p -n meine-anwendung
kubectl logs meine-anwendung-7d9f8c6b5-x2k9p -n meine-anwendung --previous
kubectl get pods zeigt dir in der RESTARTS-Spalte, wie oft ein Container schon neu gestartet wurde, und in STATUS den aktuellen Grund. kubectl describe pod liefert die eigentliche Substanz: Im Abschnitt zu jedem Container findest du den aktuellen State und den Last State mit Exit-Code, ganz unten die Events mit dem chronologischen Ablauf, inklusive der Meldung, ob ein Image nicht gezogen werden konnte oder ein Volume nicht eingebunden wurde. Die Option --previous bei kubectl logs ist entscheidend: Ohne sie siehst du die Logs des aktuellen, möglicherweise noch leeren Versuchs, mit ihr die Logs des Containers, der zuletzt abgestürzt ist und damit den eigentlichen Fehler enthält.
Exit-Codes lesen: was die Zahl bedeutet
Der Exit-Code im Last State von kubectl describe pod ist oft der schnellste Weg zur Ursache. Die folgende Tabelle zeigt die Codes, die mir in der Praxis am häufigsten begegnen.
| Exit-Code |
Bedeutung |
Typischer Auslöser |
| 0 |
Prozess hat sich sauber beendet |
Anwendung ohne Dauerbetrieb, restartPolicy startet trotzdem neu |
| 1 |
allgemeiner Anwendungsfehler |
unbehandelte Exception, fehlende Konfiguration |
| 126 |
Kommando gefunden, aber nicht ausführbar |
fehlende Ausführungsrechte im Image |
| 127 |
Kommando nicht gefunden |
Tippfehler im command, falscher Pfad |
| 137 |
mit SIGKILL beendet (128 plus Signal 9) |
OOMKilled oder erzwungenes Löschen |
| 139 |
Speicherzugriffsfehler (128 plus Signal 11) |
Absturz in nativem Code, oft ein Bug in der Anwendung |
| 143 |
mit SIGTERM beendet (128 plus Signal 15) |
reguläres, meist gewolltes Herunterfahren |
Ein Exit-Code 137 lohnt einen zweiten Blick in kubectl describe pod: Steht dort zusätzlich der Grund „OOMKilled", hat der Container mehr Speicher verbraucht, als sein Limit erlaubt. Das ist ein guter Anlass, dir Kubernetes Requests und Limits erklärt noch einmal anzusehen.
Die häufigsten Ursachen und ihr Fix
Die meisten CrashLoopBackOff-Fälle lassen sich auf eine Handvoll wiederkehrender Ursachen zurückführen. Die folgende Tabelle ordnet sie nach Häufigkeit, wie ich sie in eigenen Clustern erlebt habe.
| Ursache |
Erkennungsmerkmal |
Fix |
| Fehler in der Anwendung selbst |
Exit-Code 1, Stacktrace in logs --previous |
Fehler im Code beheben, lokal reproduzieren |
| OOMKilled |
Exit-Code 137, Grund „OOMKilled" in Events |
Memory-Limit erhöhen oder Speicherverbrauch senken |
| Liveness Probe zu aggressiv konfiguriert |
Events zeigen „Liveness probe failed" |
Timeout und Schwellenwerte der Probe anpassen |
| ConfigMap oder Secret fehlt |
Events zeigen „CreateContainerConfigError" |
referenzierten Namen und Namespace prüfen |
| falsches Kommando oder falscher Pfad |
Exit-Code 127 oder 126 |
command und args im Manifest korrigieren |
| fehlende Berechtigungen im Container |
Exit-Code ungleich 0, Fehlermeldung zu Zugriffsrechten |
securityContext und Dateirechte im Image prüfen |
| Race Condition mit einer Abhängigkeit |
Anwendung startet, stürzt kurz danach ab |
Init Container, der auf die Abhängigkeit wartet |
Die letzte Zeile begegnet mir am häufigsten bei Anwendungen, die beim Start sofort eine Datenbankverbindung erwarten. Ist die Datenbank noch nicht bereit, stürzt die Anwendung ab, bevor eine Liveness Probe überhaupt greifen könnte. Ein kleiner Init Container, der wiederholt gegen die Datenbank prüft und erst dann durchlässt, löst das zuverlässiger als Retry-Logik in der Anwendung selbst.
CrashLoopBackOff nach einem Deployment oder GitOps-Sync
Ein Sonderfall, der mir in produktiven Clustern regelmäßig begegnet: Der CrashLoop taucht erst auf, nachdem ein neues Manifest ausgerollt wurde, sei es manuell mit kubectl apply oder automatisch über einen GitOps-Sync. In diesem Fall lohnt sich zuerst der Vergleich zur vorherigen Version, bevor du tief in die Anwendung selbst einsteigst.
Mit kubectl rollout undo deployment meine-anwendung -n meine-anwendung machst du den letzten Rollout rückgängig und bekommst den Cluster sofort wieder in einen funktionierenden Zustand. Läuft dein Cluster über GitOps, ist der sauberere Weg ein Revert des fehlerhaften Commits im Repository, damit der gewünschte Zustand in Git und der tatsächliche Zustand im Cluster wieder übereinstimmen. Erst danach analysierst du in Ruhe, was an der neuen Version tatsächlich gebrochen ist, etwa eine geänderte Umgebungsvariable oder ein neues Image, das eine andere Konfiguration erwartet.
So verhinderst du den nächsten CrashLoop
Die meisten CrashLoopBackOff-Fälle lassen sich mit drei einfachen Gewohnheiten deutlich seltener machen. Erstens: Setze realistische Requests und Limits, damit ein Container nicht durch OOMKilled beendet wird, nur weil er kurzzeitig mehr Speicher braucht als angenommen. Zweitens: Definiere Liveness und Readiness Probes bewusst, mit ausreichend Zeit für den Start und ohne Abhängigkeiten, die die Anwendung selbst nicht beheben kann. Drittens: Lagere Wartezeiten auf externe Abhängigkeiten in Init Container aus, statt sie in der Anwendung selbst zu behandeln.
Keine dieser drei Maßnahmen verhindert jeden CrashLoop, aber alle drei zusammen verkürzen die Zeit, die du künftig mit der Fehlersuche verbringst, spürbar.
Häufige Fragen
Was bedeutet CrashLoopBackOff genau?
Es bedeutet, dass ein Container in einem Pod wiederholt abstürzt oder sich beendet und Kubernetes ihn deshalb erneut startet, mit einer wachsenden Wartezeit zwischen den Versuchen. Es ist kein eigener Fehlerzustand, sondern eine Beschreibung dessen, was gerade mit dem Container passiert.
Wie sehe ich die Logs eines bereits abgestürzten Containers?
Mit kubectl logs <pod> --previous bekommst du die Logs des letzten Containers, der beendet wurde, statt der Logs des aktuellen, möglicherweise noch leeren Versuchs. Das ist der wichtigste Befehl, um die eigentliche Fehlermeldung überhaupt zu sehen.
Was bedeutet Exit Code 137?
Exit Code 137 setzt sich aus 128 plus dem Signal 9 zusammen, also SIGKILL. Meistens steckt dahinter ein OOMKilled, der Container hat mehr Speicher verbraucht, als sein Limit erlaubt, und wurde deshalb hart beendet. Ein Blick in die Events von kubectl describe pod bestätigt das.
Wie lange wartet Kubernetes zwischen zwei Neustartversuchen?
Die Wartezeit beginnt kurz und verdoppelt sich mit jedem weiteren Fehlschlag, bis zu einer Obergrenze von einigen Minuten. Läuft ein Container länger stabil, setzt Kubernetes den Zähler zurück. Genau dieser wachsende Abstand ist der Grund für den Namen CrashLoopBackOff.
Startet ein Pod im CrashLoopBackOff irgendwann von selbst wieder stabil?
Nur, wenn sich die Ursache von selbst löst, etwa weil eine Abhängigkeit inzwischen bereit ist. Ein Fehler im Code oder eine fehlende Konfiguration verschwindet dagegen nicht von allein, dort hilft nur die Analyse über describe und logs --previous und ein gezielter Fix.
Wie du weitermachst
Für die tägliche Arbeit mit Pods, Logs und Shells im Container lohnt sich ein Blick in kubectl Befehle: die wichtigsten im Alltag. Wie du Probes so konfigurierst, dass sie CrashLoopBackOff eher verhindern als auslösen, steht ausführlicher in Liveness und Readiness Probes erklärt, und die richtigen Werte für Requests und Limits, um OOMKilled-Abstürze zu vermeiden, findest du in Kubernetes Requests und Limits erklärt.
Mein Vorschlag, wenn dir das das nächste Mal begegnet: Fang mit kubectl describe pod an, lies die Events von unten nach oben, und wirf erst danach einen Blick in die Anwendung selbst.
Ausführlich mit allen Beispielen zur Kommandozeile und zu Probes steht das in den Kapiteln 2 und 8 meines Kubernetes-Praxisbuchs bei Rheinwerk.