Cheveo Blog
debugging 10 min Lesezeit ·

Pod Pending in Kubernetes: 23 Ursachen, Decision-Tree, Fix-Workflow

Pod hängt im Status Pending? Die 23 häufigsten Ursachen in 5 Kategorien, mit kubectl-Befehlen, Decision-Tree und Workflow zur Diagnose in unter 5 Minuten.

Clemens Christen
Clemens Christen Certified Kubernetes Administrator (CKA)

TL;DR - Pending ist kein Bug, sondern ein Zustand: Kubernetes hat den Pod akzeptiert, kann oder will ihn aber gerade nicht starten. Die Ursache steht in 90% der Fälle direkt im Events-Bereich von kubectl describe pod - aber sie verteilt sich auf 23 verschiedene Patterns in 5 Kategorien. Dieser Workflow findet die richtige in unter 5 Minuten.

🔖 Nur die Befehle? Hier ist der interaktive Pod-Pending-Cheatsheet - mit Copy-Buttons, vollständigem 23-Ursachen-Index und Druck-Ansicht. Lesezeichen empfohlen.

Was Pending wirklich bedeutet

Pending ist die zweite Pod-Phase nach Created. Heißt:

  1. Kubernetes-API hat das Pod-Objekt akzeptiert
  2. Der Scheduler hat aber noch keinen Node ausgewählt - oder
  3. Der Kubelet auf dem zugewiesenen Node startet die Container noch nicht

In etwa 70% der Fälle hängt der Pod beim Scheduler. Die anderen 30% verteilen sich auf Volume-, Image- und Node-Health-Themen. Beide Ursachen sehen für den Operator gleich aus (STATUS: Pending), brauchen aber komplett unterschiedliche Workflows.

Wichtig: ein Pending-Pod verbraucht keine Cluster-Ressourcen außer einem Eintrag in etcd. Sie können ihn beliebig lange so liegen lassen, ohne Side-Effects - außer dass die App nicht läuft.

Der 3-Schritt-Workflow

Diese drei Befehle laufen immer zuerst, egal welche Ursache.

Schritt 1: Events lesen

kubectl describe pod <name> | tail -20

Scrolle direkt zum Events:-Bereich am Ende. Beispiel-Output:

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  2m    default-scheduler  0/5 nodes are available: 3 Insufficient cpu, 2 node(s) had untolerated taint {dedicated: gpu}.

Das ist die Antwort. Insufficient cpu plus untolerated taint sind zwei konkrete Ursachen aus unserer 23er-Liste.

Schritt 2: Scheduler-Events clusterweit

Wenn der Pod-Describe nichts hergibt - z. B. wenn das Event-Retention-Window abgelaufen ist:

kubectl get events --field-selector reason=FailedScheduling -A --sort-by=.lastTimestamp | tail -20

Findet alle Scheduling-Probleme cluster-weit, zeitlich sortiert. Hilft auch bei kaskadierten Problemen, wo ein Node-Ausfall plötzlich 30 Pods pending werden lässt.

Schritt 3: Node-Health prüfen

Bei Verdacht auf cluster-weite Probleme:

kubectl get nodes
kubectl describe node <node> | grep -A 10 "Conditions"

NotReady, DiskPressure, MemoryPressure oder PIDPressure sind die wichtigsten Conditions, die Pods am Starten hindern.

Die 23 Ursachen, kategorisiert

Kategorie 1: Resource-Constraints (4 Ursachen)

Der Scheduler findet keinen Node mit genug freien Ressourcen.

1-Tag Intensiv-Workshop

Kubernetes Debugging - systematisch statt raten

Echte Production-Incidents nachstellen, kubectl-Workflows verinnerlichen, Root-Causes in Minuten finden.

Workshop-Details ansehen

1.1 Insufficient CPU - kein Node hat genug freie CPU, summiert über alle bereits gescheduleten Pods.

kubectl describe node <node> | grep -A 5 "Allocated resources"
# CPU Requests: 3800m / 4000m (95%)

Fix: Pod-Requests senken (sind sie realistisch?), Node-Pool skalieren, oder Cluster Autoscaler/Karpenter einsetzen.

1.2 Insufficient Memory - dasselbe für RAM. Bei Burstable-QoS-Pods sieht man oft RAM-Overcommit, beim Scheduler zählen aber Requests, nicht Limits.

1.3 Insufficient ephemeral-storage - Node-Filesystem voll, Scheduler verweigert neue Pods. Klassiker auf Nodes mit großen Container-Images im Cache.

kubectl describe node <node> | grep -A 2 "ephemeral-storage"

Fix: Image-Garbage-Collection-Schwellen anpassen oder Node mit größerer Root-Disk neu starten.

1.4 Container-Requests > Node-Kapazität - ein einzelner Container fordert mehr als der größte Node insgesamt hat. Pod kann nirgendwo platziert werden, egal wie leer der Cluster ist.

resources:
  requests:
    memory: "32Gi"   # aber Node hat nur 16Gi total

Fix: Requests reduzieren oder Node-Pool mit größeren Instanzen anlegen.

Kategorie 2: Scheduler-Constraints (6 Ursachen)

Der Pod hat Regeln, die kein Node erfüllt.

2.1 NodeSelector-Mismatch - der Pod will auf einen Node mit Label tier: gpu, aber kein Node hat das Label.

kubectl get nodes -l tier=gpu
# No resources found

Fix: Node mit dem Label labeln (kubectl label node <node> tier=gpu) oder Selector im Manifest korrigieren.

2.2 NodeAffinity (required) erfüllt nicht - requiredDuringSchedulingIgnoredDuringExecution mit zu strikten Regeln, kein Node passt.

Events: 0/3 nodes are available: 3 node(s) didn't match Pod's node affinity/selector.

Fix: Affinity-Regeln entweder lockern, auf preferredDuringScheduling... umstellen, oder passende Nodes provisionieren.

2.3 Taint ohne passende Toleration - Node hat Taint (z. B. dedicated=gpu:NoSchedule), Pod hat keine matching Toleration.

kubectl describe nodes | grep -A 1 "Taints:"

Fix:

tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"

2.4 PodAntiAffinity - Pod darf nicht auf Nodes laufen, wo bereits gleichartige Pods sind. Bei requiredDuringSchedulingIgnoredDuringExecution über topologyKey: kubernetes.io/hostname mit 5 Replicas aber nur 3 Nodes → 2 Pods bleiben Pending.

Fix: Replicas reduzieren, mehr Nodes provisionieren, oder PodAntiAffinity auf preferred... weichmachen.

2.5 TopologySpreadConstraints maxSkew überschritten - Spread-Constraints (z. B. “max 2 Pods Unterschied zwischen Zonen”) können bei ungleich verteilten Nodes Pods blockieren.

topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule

Fix: whenUnsatisfiable: ScheduleAnyway, größeren maxSkew, oder Node-Verteilung über Zonen angleichen.

2.6 Pod-Topology-Constraint “DoNotSchedule” - Sonderfall der 2.5, wenn die Constraints buchstäblich kein Schedule erlauben.

Kategorie 3: Volume-Probleme (4 Ursachen)

Der Pod kommt nicht in Phase Running, weil ein Volume nicht bereit ist.

3.1 PVC nicht Bound - PersistentVolumeClaim hat keinen passenden PV gefunden.

kubectl get pvc -A | grep -v Bound

Häufige Ursachen: keine StorageClass mit default: true, falsche accessModes, falsche storageClassName-Referenz.

3.2 PVC bound, aber RWO-Volume schon woanders gemounted - der Pod soll auf Node-A, aber das RWO-Volume hängt noch an Node-B. Bei StatefulSet-Restarts klassisch.

Events: Multi-Attach error for volume "pvc-xxx" Volume is already exclusively attached to one node.

Fix: alten Pod erst sauber terminieren (oder Force-Delete), dann Volume freigeben lassen.

3.3 Volume-Topology-Konflikt - PV ist in Zone-A, Scheduler will Pod aber auf Node in Zone-B platzieren.

Events: 0/3 nodes are available: 3 node(s) had volume node affinity conflict.

Fix: volumeBindingMode: WaitForFirstConsumer in der StorageClass setzen - dann wird PV erst bei Pod-Scheduling erstellt, an der passenden Zone.

3.4 StorageClass nicht vorhanden - PVC referenziert storageClassName: gp3, aber Cluster kennt nur standard.

kubectl get sc

Fix: StorageClass anlegen, oder PVC umschreiben, oder StorageClass-Mapping in der Migration.

Kategorie 4: Image- und Container-Probleme (4 Ursachen)

Der Pod ist gescheduled, kommt aber nicht in Running.

4.1 ImagePullBackOff - Image existiert nicht, falsche Tag, oder Registry erreichbar aber langsam. Reason im Status: ImagePullBackOff.

kubectl describe pod <name> | grep -A 3 "Failed"
# Failed to pull image "myapp:v1.2.3": rpc error: ... not found

Fix: Image-Tag prüfen, in der Registry verifizieren, ggf. imagePullPolicy: IfNotPresent vs Always kontrollieren.

4.2 ErrImagePull - erster Pull-Versuch fehlgeschlagen (vor BackOff). Meist DNS-Probleme oder Registry-Auth-Fehler.

4.3 InvalidImageName - Image-Reference ist syntaktisch ungültig (Doppel-Doppelpunkte, ungültige Tags).

image: registry.io/foo::v1   # invalid - double colon

4.4 Fehlende imagePullSecrets - Private Registry, aber kein Secret oder falsches Secret referenziert.

Events: Failed to pull image: pull access denied, repository does not exist or may require authorization.

Fix:

spec:
  imagePullSecrets:
    - name: my-registry-secret

Plus passendes kubernetes.io/dockerconfigjson-Secret im Namespace.

Kategorie 5: Node-Health & Quota (5 Ursachen)

Cluster-weite oder Namespace-weite Probleme.

5.1 NodeNotReady - Node ist offline, hat Kubelet-Crash, oder Network-Plugin ist tot.

kubectl get nodes
# node-3   NotReady   <none>   3d   v1.30.1

Fix: Node-SSH, journalctl auf Kubelet, Network-Plugin-Pods checken.

5.2 DiskPressure - Kubelet hat Disk-Pressure-Eviction-Schwelle erreicht und blockiert neue Pods.

kubectl describe node <node> | grep -A 5 "Conditions"
# DiskPressure   True   ...

Fix: Disk aufräumen, Image-GC anstoßen, größere Disk, oder Eviction-Schwellen anpassen.

5.3 MemoryPressure / PIDPressure - dasselbe Pattern für RAM oder Process-IDs.

5.4 ResourceQuota überschritten - Namespace hat ResourceQuota, neuer Pod würde die überschreiten.

Events: exceeded quota: compute-quota, requested: requests.memory=2Gi, used: requests.memory=8Gi, limited: requests.memory=10Gi, requested would exceed quota.

Fix: Quota erhöhen, andere Pods reduzieren, oder Namespace-Strategie überarbeiten.

5.5 LimitRange-Verletzung - Namespace hat LimitRange, Pod-Requests/Limits passen nicht in die erlaubten Bereiche.

Fix: Pod-Manifest an LimitRange anpassen, oder LimitRange lockern.

Decision Tree

Events sagen "FailedScheduling"?
  ↓ ja
"Insufficient cpu/memory/storage"?     →  Kategorie 1 (Resources)
  ↓ nein
"didn't match Pod's node affinity"?    →  2.1 / 2.2 (Selector / Affinity)
  ↓ nein
"had untolerated taint"?               →  2.3 (Taint)
  ↓ nein
"didn't satisfy anti-affinity"?        →  2.4 (PodAntiAffinity)
  ↓ nein
"volume node affinity conflict"?       →  3.3 (Topology)
  ↓ nein
"unschedulable" + Quota-Message?       →  5.4 (ResourceQuota)
  ↓ nein
Events sagen "FailedMount" / PVC?      →  Kategorie 3 (Volumes)
  ↓ nein
Events sagen "ImagePullBackOff"?       →  Kategorie 4 (Images)
  ↓ nein
"node(s) had condition" Pressure?      →  5.2 / 5.3 (Node Pressure)
  ↓ nein
Kein Node in NodeNotReady?             →  5.1 (NodeNotReady)
                                        ↓ nein
                                          Selten: LimitRange (5.5) oder Topology Spread (2.5)

Was die Workshops nicht ersetzen

Dieser Workflow löst die 23 dokumentierten Ursachen. Was nicht drin steckt:

  • Custom Scheduler-Plugins - bei Volcano, Yunikorn oder eigenen Scheduler-Erweiterungen gibt es eigene Pending-Reasons, die nicht in dieser Liste auftauchen
  • Webhook-Admissions, die Pods stillschweigend rejecten - manche Validating-Webhooks setzen Pods auf Pending statt Failed; in den Logs des Webhook-Controllers nachsehen
  • Kubelet-Bugs unter Last - sehr selten, aber Kubelet 1.28-1.30 hatte Edge-Cases bei massivem Parallel-Scheduling
  • CSI-Driver-Bugs - PVC bleibt Pending obwohl alle Parameter stimmen, weil der CSI-Provisioner einen Internen Bug hat

Diese Pattern brauchen System-Verständnis und Tools wie kubectl get events --watch -A, journalctl -u kubelet auf den Nodes, und ein gutes Verständnis vom Scheduler-Framework.

Wie es weitergeht

Im Kubernetes Debugging Workshop spielen wir 8 echte Production-Incidents nach - inklusive zweier Pod-Pending-Edge-Cases (TopologySpread-Skew unter Skalierung und CSI-Driver-Hang während eines Node-Updates) - und drillen den Workflow, bis er sitzt. 1 Tag, 8 Stunden, danach lösen Sie Pod-Pending systematisch und nicht durch Raten.

Verwandt aus unserer Debugging-Serie:

1-Tag Intensiv-Workshop

Kubernetes Debugging - systematisch statt raten

Echte Production-Incidents nachstellen, kubectl-Workflows verinnerlichen, Root-Causes in Minuten finden.

Workshop-Details ansehen
Kostenfrei · 30 Minuten

Brauchen Sie eine zweite Meinung zu Ihrem Cluster?

Buchen Sie einen kostenfreien 30-Minuten Kubernetes Health-Check. Wir schauen uns Ihr Setup an und geben konkrete Hinweise, ohne Verkaufsgespräch.

Termin buchen