☸ Kubernetes im Heimlabor

Kurs › Folge 13

Wenn es nicht läuft: vier Fehlerbilder, die du sofort erkennst

ImagePullBackOff, CrashLoopBackOff, Pending, leere Endpoints — und der Ablauf, der dich in Minuten zur Ursache bringt.

Das Video zu dieser Folge ist noch nicht veröffentlicht. Die Notizen stehen trotzdem schon hier.

Was du danach kannst

  • die vier haeufigsten Fehlerbilder am Statuswort erkennen
  • den immer gleichen Ablauf anwenden - get, describe, logs, exec
  • die Logs eines bereits gestorbenen Containers lesen
  • einen Fehler zwischen Service und Pods finden, obwohl beide "laufen"

Warum diese Folge so früh kommt

Die meisten Kurse behandeln Fehlersuche am Ende. Das ist verkehrt herum: Den ersten ImagePullBackOff siehst du am ersten Tag, nicht in Woche vier.

Und im Beruf ist es die eigentliche Fähigkeit. Etwas zu bauen, das läuft, kann man nachschlagen. Herauszufinden, warum etwas nicht läuft, kann man nur üben.

Der Ablauf — immer derselbe

Vier Schritte, in dieser Reihenfolge. Nie eine Suchmaschine vor Schritt zwei.

kubectl get pods -o wide        # 1. Welches Statuswort? Welcher Knoten?
kubectl describe pod <name>     # 2. Die Events am Ende lesen
kubectl logs <name>             # 3. Was sagt die Anwendung selbst?
kubectl exec -it <name> -- sh   # 4. Nachsehen, wenn er wenigstens läuft

Der wichtigste Teil ist Schritt 2, und dort ausschließlich die Events-Liste ganz unten. Dort steht in fast allen Fällen die Antwort im Klartext — nur liest sie kaum jemand, weil vorher zwei Bildschirmseiten Objektbeschreibung stehen.

Fall 1: ImagePullBackOff

kubectl run kaputt1 --image=nginxx
kubectl describe pod kaputt1
Failed to pull image "nginxx": ... repository does not exist
  or may require authentication

Bedeutung: Das Image lässt sich nicht holen. Drei Ursachen, in dieser Häufigkeit: Tippfehler im Namen, kein Netz zur Registry, fehlende Zugangsdaten für eine private Registry.

Zwischenstufe: Kurz vorher steht ErrImagePull. BackOff heißt, dass Kubernetes es bereits mehrfach vergeblich versucht hat und die Abstände verlängert.

Fall 2: CrashLoopBackOff

kubectl run kaputt2 --image=busybox -- /bin/false
kubectl get pods -w

Der Zähler RESTARTS steigt, und die Pausen zwischen den Versuchen werden länger — 10 s, 20 s, 40 s, bis maximal 5 Minuten.

Bedeutung: Der Container startet erfolgreich und beendet sich dann. Das ist ein Anwendungsfehler, kein Kubernetes-Fehler. Typisch: fehlende Umgebungsvariable, Datenbank nicht erreichbar, Konfigurationsdatei nicht gefunden — oder schlicht ein Programm, das nach getaner Arbeit endet und deshalb gar kein Pod sein sollte, sondern ein Job.

Der entscheidende Befehl:

kubectl logs kaputt2 --previous

--previous zeigt die Ausgabe des bereits gestorbenen Durchlaufs. Ohne diesen Schalter siehst du die Logs des gerade startenden Containers — meist leer. Das ist der Grund, warum Leute stundenlang „keine Logs" melden, obwohl die Ursache dort steht.

Fall 3: Pending

Ein Deployment mit einer Anforderung, die kein Knoten erfüllen kann:

resources:
  requests:
    memory: "64Gi"
kubectl describe pod <name>
0/2 nodes are available: 2 Insufficient memory.

Bedeutung: Der Scheduler hat keinen passenden Knoten gefunden — und er sagt in den Events präzise, woran es lag. Andere häufige Begründungen:

  • node(s) had untolerated taint → Control Plane, siehe Folge 21
  • node(s) didn't match Pod's node affinity/selector → Label fehlt
  • pod has unbound immediate PersistentVolumeClaims → Speicher fehlt

Pending ist deshalb kein Fehler, sondern eine Auskunft. Man muss sie nur lesen.

Fall 4: Der gemeinste — Service ohne Endpoints

kubectl expose deployment web --port=80 --name=falsch --selector=app=gibtsnicht
kubectl get endpoints falsch
NAME     ENDPOINTS
falsch   <none>

Hier ist nichts kaputt. Die Pods laufen, der Service existiert, kein Pod meldet einen Fehler, in keinem Log steht etwas. Trotzdem antwortet niemand.

Der Selektor des Service passt auf kein einziges Pod-Label — und ein Service ohne passende Pods ist eine Adresse ins Leere.

Die zwei Befehle, die es aufklären:

kubectl get endpoints <service>              # leer?
kubectl get pods --show-labels               # welche Labels haben die Pods wirklich?

Zweite Variante desselben Falls: Die Labels passen, aber die Pods sind nicht Ready — dann fallen sie ebenfalls aus der Liste. Siehe Folge 19 über Probes.

Die Reihenfolge, die Zeit spart

Statuswort Zuerst ansehen
ImagePullBackOff Imagename buchstabieren, dann Registry-Zugang
CrashLoopBackOff kubectl logs --previous
Pending Events in describe — der Scheduler begründet sich
Running, aber keine Antwort kubectl get endpoints, dann Labels
ContainerCreating hängt Events — meist Netzwerk, Speicher oder Registry

Aus dem eigenen Aufbau

Beim Einrichten dieses Labors hingen alle Pods auf ContainerCreating:

plugin type="cilium-cni" failed (add): failed to find plugin
  "cilium-cni" in path [/usr/lib/cni]

Beide Knoten meldeten dabei fröhlich Ready — denn dafür genügt dem kubelet eine CNI-Konfigurationsdatei, es prüft nicht, ob die Programme dazu auffindbar sind. Die Wahrheit stand ausschließlich in den Events des Pods.

Merksatz: Ready heißt nicht funktioniert.

Zum Nachlesen

Eine geordnete Übersicht über die offizielle Dokumentation steht unter Nachlesen.

Befehle aus dieser Folge

  • kubectl get pods -o wide
  • kubectl describe pod <name>
  • kubectl logs <name> --previous
  • kubectl get events -A --sort-by=.lastTimestamp
  • kubectl get endpoints <service>
  • kubectl exec -it <name> -- sh

Begriffe

ImagePullBackOff
das Image laesst sich nicht holen - Name, Netz oder Zugangsdaten
CrashLoopBackOff
der Container startet, stirbt, startet - mit wachsender Pause dazwischen
Pending
der Scheduler hat keinen passenden Knoten gefunden und sagt in den Events warum
Events
die Chronik am Ende von describe - dort steht fast immer die Antwort
--previous
zeigt die Logs des vorherigen, bereits gestorbenen Containers

Übung — mach es selbst

Bau alle vier Fehler selbst — absichtlich.

kubectl run kaputt1 --image=nginxx
kubectl run kaputt2 --image=busybox -- /bin/false
kubectl expose deployment web --port=80 --name=falsch --selector=app=gibtsnicht

Für den dritten Fall (Pending) ein Deployment mit einer Anforderung, die kein Knoten erfüllen kann — etwa 64 GB Speicher.

Zu jedem Fall beantworten, ohne im Internet zu suchen:

  1. Welches Statuswort steht bei kubectl get pods?
  2. Welche Zeile in den Events nennt die Ursache?
  3. Mit welchem einzigen Befehl haettest du es am schnellsten gefunden?

Danach alles wieder loeschen und die Zeit stoppen: Wie lange brauchst du beim zweiten Durchgang? Wer unter zwei Minuten je Fall kommt, hat den Ablauf verinnerlicht — und genau das ist im Beruf die Faehigkeit, die zaehlt.