Veröffentlicht am

Pod Pending: keine Nodes, Quota oder Taint

Teilen:
Authors

Pod Pending: FailedScheduling lesen und beheben

TL;DR

Pending heißt: der Scheduler hat keinen Node akzeptiert. Der Container ist nicht gestartet. Logs gibt es nicht. Die Zeile, die den Grund nennt, steht in den Events:

kubectl describe pod POD

Ganz unten, FailedScheduling. Der Text ist die Ursache, nicht ein Hinweis. insufficient cpu oder insufficient memory ist Ressourcenmangel. untolerated taint ist ein Taint ohne Toleration. didn't match Pod's node affinity ist Selector oder Affinity. persistentvolumeclaim ist ein Volume, das nicht gebunden ist — dann weiter bei PVC Pending.

Die Meldung und der Fix

Events-TextUrsacheWas Sie ändern
0/N nodes: insufficient cpu / memoryRequests höher als freiRequest senken oder Node dazunehmen
untolerated taintNode lehnt den Pod abToleration setzen oder anderen Pool wählen
didn't match node affinity / selectorLabel fehltnodeSelector oder Affinity an das Label anpassen
pod has unbound immediate PersistentVolumeClaimsPVC nicht BoundStorageClass, siehe PVC-Artikel
exceeded quotaResourceQuota im Namespace vollQuota oder Requests anpassen

0/3 nodes are available zählt mit. Steht dahinter dreimal derselbe Grund, ist es ein Cluster-Thema. Steht dahinter ein Mix, erfüllt kein einzelner Node alle Bedingungen gleichzeitig.

Requests, nicht Limits, halten den Pod fest

Der Scheduler rechnet mit requests. Limits interessieren ihn nicht. Ein Pod mit requests.cpu: 2 und einem Node, auf dem nur 500m frei sind, bleibt Pending, auch wenn der Prozess später kaum CPU braucht. kubectl describe node NODE zeigt Allocated resources. Dort sehen Sie, was schon reserviert ist, nicht was wirklich verbraucht wird.

Wer nach einem OOMKilled Request und Limit gemeinsam verdoppelt, füllt die Reservierung. Der nächste Pod findet keinen Platz, obwohl kubectl top noch Luft zeigt. Für den Start reicht ein Request in der Nähe des Normalverbrauchs. Das Limit darf darüber liegen.

Ein leerer Request ist auch ein Problem, nur später: der Scheduler packt den Pod überall hin, und unter Last verdrängt ihn das Kubelet. Für alles, was in Produktion läuft, Request setzen.

Taints und Pools

Control-Plane-Nodes tragen node-role.kubernetes.io/control-plane:NoSchedule. Ein Pod ohne Toleration kommt dort nicht hin. Dasselbe gilt für Pools mit workload=gpu oder dedicated=batch, wenn der Betreiber sie so markiert hat.

kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
kubectl get pod POD -o jsonpath='{.spec.tolerations}{"\n"}{.spec.nodeSelector}{"\n"}'

Die Toleration muss Key, Effect und bei Equal auch den Value treffen. Exists ohne Value gilt für jeden Value dieses Keys. Ein Tippfehler im Key ist still: der Pod bleibt Pending, der Node sieht gesund aus.

Quota im Namespace

exceeded quota kommt nicht vom Node, sondern vom Namespace. kubectl describe quota -n NAMESPACE zeigt used gegen hard. CPU, Memory, Pod-Anzahl und oft requests.storage stehen getrennt. Ein neues Replica kann an pods: 10 scheitern, während CPU noch frei ist.

Was Pending nicht ist

Steigt der Status auf ContainerCreating und bleibt dort, ist der Pod geschedult. Dann sind Image, Volume-Mount oder ein Init-Container das Thema, nicht der Scheduler. Stirbt er nach dem Start, ist es CrashLoopBackOff. Pending endet in dem Moment, in dem ein Node zugewiesen ist. kubectl get pod POD -o wide hat dann einen Wert in der Spalte NODE.

Quellen

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen