Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Diagnostiquer un Pod Pending Kubernetes

15 min de lecture

logo kubernetes

Un pod en Pending est un pod accepté par l’API server dont un ou plusieurs conteneurs n’ont pas encore été créés. Dans la pratique, cela correspond très souvent à un problème de scheduling (aucun nœud acceptable trouvé), mais la phase Pending peut aussi couvrir d’autres étapes préalables au démarrage effectif. Ce guide vous donne une méthodologie en 4 étapes pour identifier la cause et débloquer la situation.

  • Comprendre pourquoi un pod reste en Pending et ce que fait le scheduler
  • Identifier les 7 causes principales d’un pod Pending
  • Appliquer une méthodologie de diagnostic reproductible en 4 étapes
  • Utiliser kubectl describe pod et kubectl get events pour trouver la cause réelle
  • Reproduire et résoudre un pod Pending sur un cluster de test
  • Un cluster Kubernetes fonctionnel (v1.28+)
  • kubectl configuré et connecté au cluster
  • Des droits de lecture sur les pods, nœuds et événements
  • Connaissances de base sur les Pods et le scheduling

Pending est une phase officielle du cycle de vie d’un Pod. Elle signifie que le Pod a été accepté par l’API server, mais qu’un ou plusieurs conteneurs n’ont pas encore été créés. Cela inclut le temps de scheduling (trouver un nœud) et le temps de préparation (téléchargement des images, par exemple). Dans ce guide, nous nous concentrons sur le cas le plus fréquent : le pod reste bloqué parce que le scheduler ne trouve pas de nœud acceptable.

Le scheduler Kubernetes (kube-scheduler) évalue chaque pod en attente et cherche un nœud qui satisfait toutes les contraintes :

ContrainteCe que le scheduler vérifie
RessourcesLe nœud a-t-il assez de CPU et mémoire disponibles (requests) ?
Taints/TolerationsLe pod tolère-t-il les taints du nœud ?
Node SelectorLe nœud a-t-il les labels demandés ?
Node AffinityLe nœud correspond-il aux règles d’affinité ?
Pod Affinity/Anti-AffinityLe placement est-il compatible avec les autres pods ?
PVCLe volume demandé est-il disponible dans la même zone ?
Topology constraintsLes contraintes de répartition topologique sont-elles respectées ?

Si aucun nœud ne passe tous les filtres, le pod reste Pending et un événement FailedScheduling est émis.

Voici les causes les plus fréquentes, classées par ordre de probabilité :

#CauseSymptôme typiqueOù chercher
1Ressources insuffisantesInsufficient cpu ou Insufficient memorykubectl describe pod → Events
2Taint sans tolerationhad untolerated taintkubectl describe pod → Events
3Node selector / node affinity impossibledidn't match Pod's node affinity/selectorkubectl describe pod → Events
4PVC non lié (unbound PVC)pod has unbound immediate PersistentVolumeClaimskubectl describe pod + kubectl get pvc
5Pod anti-affinity / topology spread trop strictscontrainte de placement non satisfaisablekubectl describe pod → Events
6Quota ou admission bloquantsexceeded quota ou refus de créationévénements / retour API
7Priorité / préemption insuffisantele scheduler ne peut pas libérer de place utilekubectl describe pod → Events
  1. Identifier les pods Pending

    Listez les pods et repérez ceux dont le STATUS est Pending :

    Fenêtre de terminal
    kubectl get pods -A --field-selector=status.phase=Pending

    Si la commande ne retourne rien mais qu’un pod semble bloqué, vérifiez aussi les événements récents :

    Fenêtre de terminal
    kubectl get events -A --field-selector reason=FailedScheduling --sort-by='.lastTimestamp'

    Notez le nom du pod, son namespace et depuis combien de temps il est en Pending.

  2. Lire les événements du pod

    La commande essentielle pour un pod Pending est kubectl describe pod, section Events :

    Fenêtre de terminal
    kubectl describe pod <pod> -n <namespace>

    Le message de l’événement FailedScheduling vous dit exactement pourquoi le scheduler n’a trouvé aucun nœud. Exemples :

    0/3 nodes are available: 1 node(s) had untolerated taint
    {node-role.kubernetes.io/control-plane: }, 2 Insufficient memory.

    Ce message signifie : 3 nœuds évalués, 1 écarté pour taint control-plane, 2 écartés pour manque de mémoire.

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

    Celui-ci signifie : aucun nœud n’a les labels demandés par le nodeSelector ou la nodeAffinity.

  3. Croiser avec l’état des nœuds et des ressources

    Selon le message d’erreur, vérifiez :

    Pour les ressources insuffisantes :

    Fenêtre de terminal
    # Voir la capacité et l'utilisation de chaque nœud
    kubectl top nodes
    # Détail des allocations sur un nœud
    kubectl describe node <node-name> | grep -A10 "Allocated resources"

    Pour les taints :

    Fenêtre de terminal
    # Voir les taints de chaque nœud
    kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints

    Pour les labels (nodeSelector/nodeAffinity) :

    Fenêtre de terminal
    # Voir les labels des nœuds
    kubectl get nodes --show-labels
    # Vérifier un label spécifique
    kubectl get nodes -l <label-key>=<label-value>

    Pour les PVC :

    Fenêtre de terminal
    # Voir l'état des PVC du namespace
    kubectl get pvc -n <namespace>

    Un PVC en Pending empêche le pod de démarrer — il faut d’abord résoudre le PVC.

    Pour les quotas :

    Fenêtre de terminal
    # Voir les quotas du namespace
    kubectl describe resourcequota -n <namespace>
  4. Corriger et vérifier

    Selon la cause identifiée :

    CauseAction corrective
    Ressources insuffisantesRéduire les requests du pod, ou ajouter des nœuds au cluster
    Taint sans tolerationAjouter la toleration dans le manifeste, ou retirer la taint du nœud
    Node Selector incorrectCorriger le nodeSelector ou ajouter le label au nœud
    PVC non liéCréer le PV manquant, vérifier la StorageClass, ou corriger la zone
    Anti-affinity / topology spreadAssouplir les règles (preferredDuringScheduling au lieu de required)
    Quota / admissionAugmenter le quota, ou réduire l’utilisation existante
    Priorité insuffisanteAugmenter la PriorityClass du pod, ou libérer de la capacité

    Après correction, vérifiez que le pod quitte l’état Pending :

    Fenêtre de terminal
    kubectl get pods -n <namespace> -w

    Le pod doit passer de PendingContainerCreatingRunning.

Créez un pod qui demande plus de CPU que ce que le cluster peut fournir :

Fenêtre de terminal
kubectl apply -f- <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: pending-resources
namespace: default
spec:
containers:
- name: app
image: nginx:1.27
resources:
requests:
cpu: "100"
memory: "1Gi"
EOF

Le pod demande 100 CPU — aucun nœud ne peut satisfaire cette demande.

Diagnostic :

Fenêtre de terminal
kubectl describe pod pending-resources | tail -10

Vous verrez un événement FailedScheduling avec le message Insufficient cpu.

Solution : réduire les requests.cpu à une valeur réaliste (par exemple 100m pour 0,1 CPU).

Fenêtre de terminal
kubectl apply -f- <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: pending-selector
namespace: default
spec:
nodeSelector:
disk: ssd-nvme
containers:
- name: app
image: nginx:1.27
EOF

Si aucun nœud n’a le label disk=ssd-nvme, le pod restera Pending.

Diagnostic :

Fenêtre de terminal
kubectl describe pod pending-selector | tail -10
kubectl get nodes --show-labels | grep ssd-nvme

Solution : ajouter le label au nœud, ou supprimer le nodeSelector :

Fenêtre de terminal
kubectl label node <node-name> disk=ssd-nvme
Fenêtre de terminal
kubectl apply -f- <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: pending-taint
namespace: default
spec:
containers:
- name: app
image: nginx:1.27
EOF

Si tous les nœuds workers ont une taint et que le pod n’a pas la toleration correspondante, il restera Pending.

Reproduisons la situation :

Fenêtre de terminal
# Ajouter une taint à tous les nœuds workers
kubectl taint nodes -l '!node-role.kubernetes.io/control-plane' maintenance=true:NoSchedule
# Vérifier que le pod est Pending
kubectl describe pod pending-taint | tail -10

Solution : ajouter la toleration dans le manifeste, ou retirer la taint :

Fenêtre de terminal
# Retirer la taint
kubectl taint nodes -l '!node-role.kubernetes.io/control-plane' maintenance=true:NoSchedule-
Fenêtre de terminal
kubectl apply -f- <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-inexistant
namespace: default
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "storage-class-inexistante"
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
name: pending-pvc
namespace: default
spec:
containers:
- name: app
image: nginx:1.27
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc-inexistant
EOF

Le PVC référence une StorageClass qui n’existe pas — il reste en Pending, et le pod aussi.

Diagnostic :

Fenêtre de terminal
kubectl get pvc pvc-inexistant
kubectl describe pod pending-pvc | tail -10

Vous verrez pod has unbound immediate PersistentVolumeClaims.

Fenêtre de terminal
kubectl delete pod pending-resources pending-selector pending-taint pending-pvc --force --grace-period=0 2>/dev/null
kubectl delete pvc pvc-inexistant 2>/dev/null
kubectl taint nodes -l '!node-role.kubernetes.io/control-plane' maintenance=true:NoSchedule- 2>/dev/null

Quand un Deployment augmente son nombre de replicas, le scheduler traite les pods un par un. Si le cluster est proche de la saturation, les premiers pods sont placés mais les derniers restent Pending. Les événements montrent Insufficient cpu ou Insufficient memory.

Si vous utilisez un mécanisme d’autoscaling des nœuds (Cluster Autoscaler, Karpenter…), les pods Pending peuvent déclencher l’ajout de capacité automatiquement. Le délai dépend fortement de l’implémentation et de l’infrastructure sous-jacente.

Un PDB ne cause pas directement un pod Pending. Mais lors d’un drain de nœud, si le PDB empêche l’éviction, les pods restent sur le nœud drainé et les nouveaux pods créés pour les remplacer peuvent rester Pending par manque de ressources sur les nœuds restants.

Si vous avez défini des contraintes de répartition topologique (topologySpreadConstraints) avec whenUnsatisfiable: DoNotSchedule, le scheduler refuse de placer le pod si la répartition ne peut pas être respectée. Les événements indiqueront les contraintes non satisfaites.

SymptômePremière actionCommande
Pending + Insufficient cpu/memoryVérifier les allocations nœudskubectl describe node <node> → Allocated resources
Pending + untolerated taintVérifier les taintskubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
Pending + didn't match node affinity/selectorVérifier les labels nœudskubectl get nodes --show-labels
Pending + unbound PersistentVolumeClaimsVérifier le PVCkubectl get pvc -n <namespace>
Pending + exceeded quotaVérifier le ResourceQuotakubectl describe resourcequota -n <namespace>
Pending + aucun eventScheduler en panne ?kubectl get pods -n kube-system -l component=kube-scheduler
Pod disparaît au lieu de rester PendingVérifier si un webhook le supprimekubectl get events -n <namespace> --sort-by='.lastTimestamp'
  • Pending signifie qu’un ou plusieurs conteneurs n’ont pas encore été créés — dans la plupart des cas, c’est parce que le scheduler n’a pas trouvé de nœud acceptable
  • kubectl describe pod est la commande clé — la section Events contient le message FailedScheduling qui explique exactement ce qui bloque
  • Insufficient cpu/memory est la cause la plus fréquente — vérifiez les requests du pod et les Allocated resources des nœuds
  • Les taints bloquent silencieusement : un nœud peut avoir de la capacité mais refuser le pod s’il n’a pas la bonne toleration
  • Un PVC non lié bloque le pod — résolvez d’abord le PVC (StorageClass absente, pas de PV disponible, mauvaise zone)
  • Sur un cluster avec PodPriority, un pod peut rester Pending si sa priorité est trop faible pour déclencher une préemption utile
  • Après correction, le pod doit transiter de PendingContainerCreatingRunning
  • Mettez en place une alerte sur les pods Pending prolongé — c’est un symptôme fiable de problème de capacité ou de configuration

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn