Layer 8Ehrlicher Tech-Support
SoftwareSchweregrad: LästigPending / FailedScheduling

Kubernetes: Pod hängt in Pending — kein Knoten passt

Der Pod steht auf Pending und startet nie? Kubernetes hat ihn angenommen, aber keinen passenden Knoten gefunden. So liest du die Begründung aus.

Aufwand:
ca. 20 Min.
Voraussetzung:
kubectl, Lesezugriff auf den Namensraum, Lesezugriff auf die Knoten des Clusters
Gilt für:
Kubernetes mit dem Standard-Zuteiler kube-scheduler

Das Symptom

kubectl get pods zeigt in der Spalte STATUS seit Minuten oder Stunden dasselbe Wort: Pending. Die Spalte mit den Neustarts steht auf null, denn es gab nichts neu zu starten. Logs gibt es keine, weil kein Container existiert, der etwas hätte sagen können. Der Pod ist nicht abgestürzt, nicht abgelehnt, nicht kaputt — er steht einfach da. Besonders gern passiert das direkt nach dem Ausrollen einer neuen Anwendung, nach dem Hochsetzen der Ressourcenanforderungen oder nachdem jemand einen Knoten in Wartung genommen hat.

Die „Layer 8“-Wahrheit

Pending ist keine Fehlermeldung, sondern eine Wartemarke. Die Dokumentation definiert die Phase ausdrücklich als „vom Cluster angenommen, aber noch nicht eingerichtet und lauffähig gemacht“ und rechnet dabei zwei Dinge zusammen: die Zeit, die der Pod auf seine Zuteilung wartet, und die Zeit, in der Images heruntergeladen werden. Der zweite Fall löst sich von selbst. Der erste nicht. Denn der Zuteiler arbeitet in zwei Schritten — erst filtert er alle Knoten heraus, auf denen der Pod überhaupt laufen könnte, dann bewertet er die Übriggebliebenen. Bleibt nach dem Filtern nichts übrig, ist der Pod schlicht nicht zuteilbar, und die Dokumentation sagt klar, was dann geschieht: Er bleibt unzugeteilt, bis der Zuteiler ihn unterbringen kann. Es läuft keine Uhr. Es kommt kein Abbruch. Es passiert nichts.

Der eigentliche Fehler auf Schicht 8 ist deshalb nicht die Konfiguration, sondern das Raten. Fast jeder öffnet an dieser Stelle das Manifest und dreht wahllos an Zahlen, obwohl die Antwort bereits vorliegt: Der Zuteiler schreibt seine Begründung in die Ereignisse des Pods, meistens als FailedScheduling, und dort steht dann nüchtern, wie viele Knoten aus welchem Grund ausgeschieden sind — zu wenig Prozessor, zu wenig Speicher, eine Markierung ohne passende Duldung, ein Volume, das sich nicht binden lässt. Ein einziger kubectl describe pod ersetzt eine halbe Stunde Vermutungen.

Und dann die drei Klassiker, die nichts mit Platzmangel zu tun haben und trotzdem zu Pending führen. Erstens Anforderungen, die nie zu einem Knoten passen können: Zugeteilt wird nach requests, nicht nach dem, was ein Programm tatsächlich verbraucht — wer vier Kerne anfordert, findet auf einem Zwei-Kern-Knoten niemals Platz, egal wie leer der ist. Zweitens Markierungen, die einen Knoten Pods abstoßen lassen, solange der Pod keine passende Duldung mitbringt — der Knoten ist dann sichtbar frei und trotzdem nicht zu haben. Drittens ein Volume, das keinen Partner findet — Ansprüche bleiben laut Dokumentation unbegrenzt ungebunden, wenn kein passendes Volume existiert, und mit der Bindungsart WaitForFirstConsumer sieht das dann aus, als warteten Pod und Volume höflich aufeinander. Kubernetes hat in keinem dieser Fälle einen Fehler gemacht. Es hat nur getan, worum es gebeten wurde, und wartet geduldig darauf, dass jemand die Bitte für erfüllbar erklärt.

Die echte, verifizierte Lösung

1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:

  1. 1.

    Den Zustand und die Ereignisse des Pods ansehen

    Der Einstieg in jede Pod-Fehlersuche, und die Dokumentation nennt ihn genau so: Der erste Schritt beim Untersuchen eines Pods ist, ihn sich anzusehen. Die Übersicht zeigt die Phase, der zweite Befehl den aktuellen Zustand und die letzten Ereignisse — dort steht die Begründung des Zuteilers im Klartext, meist als Ereignis mit dem Grund FailedScheduling.

    kubectl get pods
    kubectl describe pod POD-NAME
    
  2. 2.

    Die Meldungen des Zuteilers gezielt herausfiltern

    Ereignisse sind flüchtig und gehen in langen describe-Ausgaben unter. Der erste Befehl zeigt die Ereignisse zu genau diesem Pod, der zweite alle Zuteilungsfehlschläge im Namensraum. In der Meldung steht regelmäßig, wie viele Knoten aus welchem Grund ausgeschieden sind — das ist die Antwort, die man sonst zu erraten versucht.

    kubectl events --for pod/POD-NAME
    kubectl get events --field-selector reason=FailedScheduling
    
  3. 3.

    Die angeforderten Ressourcen gegen den freien Platz halten

    Anforderungen sind der Maßstab der Zuteilung, nicht der tatsächliche Verbrauch. Die Dokumentation sagt es unmissverständlich: Wenn du die Ressourcenanforderung für Container in einem Pod angibst, benutzt der kube-scheduler diese Angabe, um zu entscheiden, auf welchem Knoten der Pod platziert wird. Der erste Befehl zeigt, was der Pod verlangt, der zweite unter Allocated resources, was auf dem Knoten schon vergeben ist. Zur Einordnung der Einheiten: Laut Dokumentation entspricht 1 CPU-Einheit einem physischen oder virtuellen Prozessorkern, Speicher wird in Bytes gemessen und darf Suffixe wie Mi oder Gi tragen.

    kubectl get pod POD-NAME -o yaml
    kubectl describe node NODE-NAME
    
  4. 4.

    Markierungen und Duldungen nebeneinanderlegen

    Der erste Befehl listet alle Knoten mit ihren Markierungen, der zweite zeigt die Duldungen des Pods. Die Dokumentation beschreibt das Zusammenspiel so: Eine oder mehrere Markierungen werden auf einen Knoten angewandt; das kennzeichnet, dass der Knoten keine Pods annehmen soll, die die Markierungen nicht dulden. Und weiter: Duldungen erlauben die Zuteilung, garantieren sie aber nicht — der Zuteiler bewertet im Rahmen seiner Aufgabe auch andere Größen.

    kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
    kubectl get pod POD-NAME -o yaml
    
  5. 5.

    Das Volume prüfen, sofern der Pod eines verlangt

    Steht der Anspruch nicht auf Bound, startet der Pod nicht. Die Dokumentation beschreibt den Vorgang als Regelkreis in der Steuerungsebene, der neue Ansprüche beobachtet, ein passendes Volume sucht — sofern möglich — und beide aneinander bindet. Bleibt STATUS auf Pending, fehlt schlicht ein passendes Volume. Der dritte Befehl zeigt die Bindungsart der Speicherklasse: Bei WaitForFirstConsumer ist ein wartender Anspruch normal, bei Immediate ist er ein Befund.

    kubectl get pvc
    kubectl describe pvc PVC-NAME
    kubectl get storageclass
    
  6. 6.

    Die Ursache beheben, statt den Pod neu zu erzeugen

    Je nach Befund: Anforderungen auf ein realistisches Maß senken, überflüssige Pods entfernen oder einen Knoten hinzufügen — die Dokumentation nennt genau diese drei Wege, wenn Prozessor- oder Speichervorrat im Cluster erschöpft sind. Bei Markierungen entweder eine passende Duldung in den Pod schreiben oder die Markierung entfernen. Bei hostPort empfiehlt die Dokumentation, stattdessen ein Service-Objekt zu verwenden, weil hostPort in den meisten Fällen unnötig ist. Löschen und neu anlegen hilft nicht: Der neue Pod trifft auf denselben Cluster.

    kubectl get pods --watch
    

Häufige Fragen (FAQ)

?Was bedeutet der Zustand Pending genau?

Pending ist eine von fünf Phasen, die ein Pod annehmen kann, und die Kubernetes-Dokumentation definiert sie wörtlich so: Der Pod wurde vom Kubernetes-Cluster angenommen, aber einer oder mehrere der Container wurden noch nicht eingerichtet und lauffähig gemacht. Das schließt die Zeit ein, die ein Pod auf seine Zuteilung wartet, ebenso wie die Zeit für das Herunterladen der Container-Images über das Netz. Übersetzt heißt das: Der Cluster kennt deinen Pod und hat ihn nicht abgelehnt — er hat ihn nur nirgends untergebracht. Die Seite zur Pod-Fehlersuche wird noch deutlicher: Bleibt ein Pod in Pending hängen, bedeutet das, dass er keinem Knoten zugeteilt werden kann; in der Regel liegt das an unzureichenden Ressourcen der einen oder anderen Art, die die Zuteilung verhindern.

?Warum sagt mir niemand, welcher Knoten warum ausgeschieden ist?

Doch, das sagt jemand — der Zuteiler selbst, und zwar in den Ereignissen des Pods. Die Kubernetes-Dokumentation zur Pod-Fehlersuche verweist genau darauf: Sieh dir die Ausgabe des oben genannten describe-Befehls an, dort sollten Meldungen des Zuteilers stehen, warum er deinen Pod nicht zuteilen kann. Wie er zu diesem Urteil kommt, beschreibt die Seite zum kube-scheduler: Knoten in einem Cluster, die die Zuteilungsanforderungen eines Pods erfüllen, heißen feasible, also geeignet. Die Auswahl läuft in zwei Schritten ab — beim Filtern wird die Menge der Knoten bestimmt, auf denen die Zuteilung des Pods möglich ist, beim Bewerten werden die übrig gebliebenen in eine Rangfolge gebracht. Und dann der Satz, um den es hier geht: Ist die Liste nach dem Filtern leer, ist dieser Pod (noch) nicht zuteilbar; ist keiner der Knoten geeignet, bleibt der Pod unzugeteilt, bis der Zuteiler ihn unterbringen kann. Es gibt also keine Zeitüberschreitung, nach der irgendetwas passiert. Der Pod wartet.

?Der Cluster sieht doch leer aus — trotzdem Pending. Was fehlt?

Dann ist es fast nie der Platz, sondern eine der drei anderen Sperren. Erstens Markierungen: Die Dokumentation beschreibt sie als das Gegenstück zur Knotenaffinität — sie erlauben es einem Knoten, eine Menge von Pods abzustoßen. Bei der Wirkung NoSchedule werden keine neuen Pods auf dem markierten Knoten zugeteilt, sofern sie keine passende Duldung mitbringen. Zweitens Speicher: Verlangt der Pod ein Volume, das nicht gebunden werden kann, geht es nicht weiter — die Dokumentation formuliert das so, dass Ansprüche unbegrenzt ungebunden bleiben, wenn kein passendes Volume existiert. Kommt dazu die Bindungsart WaitForFirstConsumer, verzögert sie laut Dokumentation Bindung und dynamische Bereitstellung eines Volumes, bis ein Pod erzeugt wird, der den Anspruch benutzt — Pod und Volume warten dann scheinbar aufeinander. Drittens hostPort: Die Dokumentation weist darauf hin, dass es beim Binden eines Pods an einen hostPort nur eine begrenzte Zahl von Plätzen gibt, an denen dieser Pod zugeteilt werden kann — pro Knoten genau einen.

Belege

Diese Seite ist gegen die folgenden Primärquellen geprüft – Hersteller, Standard oder Gesetzestext. Wer es nicht glaubt, muss es nicht: Da steht, wo es nachzulesen ist.

Zuletzt geprüft am . Dokumentation altert – ein Datum daneben ist der einzige ehrliche Umgang damit.

Auch zu finden unter

Verwandte Fehler

SWLästigCrashLoopBackOff

Kubernetes: Pod in CrashLoopBackOff

CrashLoopBackOff ist kein Fehler von Kubernetes, sondern die Meldung, dass dein Container beim Start abbricht. So kommst du an die Ursache.

SWAnfängerfehlerImagePullBackOff

Kubernetes: ImagePullBackOff und ErrImagePull

Der Pod wartet, weil das Abbild nicht kommt: falscher Name, falsches Tag, fehlende Zugangsdaten. So liest du die Ursache statt zu raten.