Un pod bloqué en Pending ou affichant des événements FailedScheduling signifie que le scheduler Kubernetes ne peut pas trouver un nœud adapté pour l’exécuter. Ce guide vous montre comment diagnostiquer et corriger les causes les plus courantes.
Symptôme
L’état du pod est Pending et n’avance pas vers Running. La commande kubectl describe pod affiche des événements comme :
Name: example-app-5f7c9d4bfb-7x8kq
Namespace: default
Status: Pending
Events:
Type Reason Age Message
---- ------ ---- -------
Warning FailedScheduling 3m 0/3 nodes are available:
insufficient cpu on 3 nodes
Autres messages possibles :
insufficient memory on 3 nodes
node has a taint...that the pod does not tolerate
pod has unbound immediate PersistentVolumeClaims
no nodes match the pod's node selector
pod affinity/anti-affinity not satisfied
exceeds quota
exceeds LimitRange
Pourquoi ça arrive
Classées par probabilité :
- CPU ou mémoire insuffisant sur tous les nœuds — Le pod demande plus de ressources que ce que n’importe quel nœud a disponible. Soit le cluster est sur-abonné, soit les requests du pod sont irréalistes.
- Node selector ou contrainte d’affinity non satisfait — Le pod est contraint à des nœuds spécifiques (par label ou règles d’affinity) et ces nœuds n’existent pas ou ne sont pas disponibles.
- Taints sur les nœuds que le pod ne tolère pas — Les nœuds du control plane et les autres nœuds spécialisés ont des taints. Les pods sans tolerations correspondantes ne peuvent pas s’y ordonnancer.
- PersistentVolumeClaim (PVC) en attente — Le PVC ne peut pas se lier à un PersistentVolume, donc le pod attend indéfiniment.
- Pod quota ou LimitRange dépassé — Le namespace a des quotas de ressources ou des limites qui empêchent la création de nouveaux pods.
- Topology spread constraints ou pod anti-affinity — Le pod exige une distribution entre nœuds ou ne peut pas s’exécuter sur le même nœud que d’autres pods, mais aucun nœud approprié n’existe.
Correction
1. CPU ou mémoire insuffisant sur tous les nœuds
Vérifiez les ressources disponibles :
kubectl top nodes
Exemple de sortie :
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
node-1 1900m 95% 3800Mi 95%
node-2 1800m 90% 3600Mi 90%
node-3 1950m 98% 3900Mi 98%
Tous les nœuds sont pleins. Voyez ce qui consomme les ressources :
kubectl top pod -A | sort --reverse --numeric-sort --key 3 | head -20
Option A: Réduisez ou supprimez les pods de faible priorité pour libérer de l’espace.
Option B: Augmentez les resource requests du pod s’ils sont trop élevés :
kubectl get pod <pod-name> -o yaml | grep -A 5 "resources:"
Si le pod demande 1000m CPU mais les nœuds n’ont que 100m libre, baissez les requests :
resources:
requests:
cpu: "100m" # Réduit de 500m
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
Appliquez et réessayez :
kubectl apply -f deployment.yaml
Option C: Ajoutez plus de nœuds au cluster.
Pour les clusters cloud, activez l’autoscaling :
# Exemple GKE
gcloud container clusters update <cluster-name> \
--enable-autoscaling \
--min-nodes 1 \
--max-nodes 10
Pour bare metal ou on-prem, ajoutez manuellement les nœuds :
# Suivez les instructions de votre fournisseur cloud ou outil de déploiement
2. Node selector ou contrainte d’affinity non satisfait
Vérifiez le node selector du pod :
kubectl get pod <pod-name> -o yaml | grep -A 5 "nodeSelector:"
Exemple :
nodeSelector:
disktype: ssd
gpu: "true"
Le pod ne s’exécutera que sur les nœuds ayant les deux labels. Vérifiez si des nœuds ont ces labels :
kubectl get nodes --show-labels | grep ssd
kubectl get nodes --show-labels | grep gpu
Si aucun nœud ne correspond, soit :
A. Ajoutez les labels aux nœuds existants :
kubectl label node <node-name> disktype=ssd gpu=true
B. Supprimez le nodeSelector du pod s’il n’est pas réellement nécessaire :
# Supprimez ou commentez nodeSelector
# nodeSelector:
# disktype: ssd
Pour les contraintes d’affinity (plus complexe que nodeSelector), vérifiez le spec pod :
kubectl get pod <pod-name> -o yaml | grep -A 20 "affinity:"
Exemple d’affinity nécessitant un label spécifique :
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
Si aucun nœud n’a le label requis, ajoutez-le ou assouplissez l’affinity à une préférence :
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution: # Changé de required
- preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
weight: 100
Appliquez le pod mis à jour :
kubectl apply -f deployment.yaml
kubectl rollout restart deployment/<deployment-name>
3. Taints sur les nœuds que le pod ne tolère pas
Les nœuds du control plane et les autres nœuds spécialisés ont des taints. Vérifiez-les :
kubectl describe node <node-name> | grep Taint
Exemple de sortie :
Taints: node-role.kubernetes.io/control-plane:NoSchedule
Ce taint signifie que les pods ne peuvent pas s’exécuter sur le control plane à moins qu’ils ne le tolèrent. Si votre pod devrait y être autorisé, ajoutez une toleration correspondante :
apiVersion: apps/v1
kind: Deployment
metadata:
name: special-app
spec:
template:
spec:
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Equal"
value: ""
effect: "NoSchedule"
containers:
- name: app
image: example:latest
Appliquez et réessayez :
kubectl apply -f deployment.yaml
Pour les taints personnalisés, le même pattern s’applique :
# Vérifier le taint
kubectl describe node <node-name> | grep Taint
# Exemple : my-taint=myvalue:NoSchedule
# Ajouter la toleration correspondante
tolerations:
- key: "my-taint"
operator: "Equal"
value: "myvalue"
effect: "NoSchedule"
4. PersistentVolumeClaim (PVC) en attente
Vérifiez si le PVC existe et est lié :
kubectl get pvc
# Sortie :
# NAME STATUS VOLUME CAPACITY ACCESS MODES
# my-pvc Pending <none> <none> RWO
Si le PVC est pending, il ne peut se lier à aucun PersistentVolume. Vérifiez pourquoi :
kubectl describe pvc <pvc-name>
Raisons courantes :
– Aucun PV n’existe : Créez un PV ou une StorageClass.
– StorageClass n’existe pas : Créez-en une ou assurez-vous que le cluster en a une par défaut.
Créez un PersistentVolume :
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data
EOF
Ou activez le provisioning dynamique en créant une StorageClass :
cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/host-path
EOF
Puis mettez à jour votre PVC pour utiliser cette StorageClass :
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: fast
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Appliquez et le PVC devrait se lier :
kubectl apply -f pvc.yaml
kubectl get pvc # Devrait maintenant être Bound
5. Pod quota ou LimitRange dépassé
Vérifiez si le namespace a des quotas de ressources :
kubectl get resourcequota -n <namespace>
kubectl describe resourcequota <quota-name> -n <namespace>
Exemple :
Name: cpu-quota
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 1000m 2000m
memory 1Gi 2Gi
pods 5 10
Votre nouveau pod pourrait dépasser le quota. Vérifiez les requests du pod :
kubectl get pod <pod-name> -o yaml | grep -A 5 "resources:"
Option A: Augmentez le quota :
kubectl edit resourcequota <quota-name>
Et augmentez les valeurs hard.
Option B: Réduisez les resource requests du pod :
resources:
requests:
cpu: "50m" # Réduit
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
Aussi vérifiez les contraintes LimitRange :
kubectl get limitrange -n <namespace>
kubectl describe limitrange <limit-name>
LimitRange pourrait appliquer des ressources minimales ou maximales. Ajustez votre pod pour tenir dans la plage.
Appliquez et réessayez :
kubectl apply -f deployment.yaml
6. Topology spread constraints ou pod anti-affinity
Vérifiez le spec pod pour topology spread ou anti-affinity :
kubectl get pod <pod-name> -o yaml | grep -A 15 "topologySpreadConstraints:\|affinity:"
Exemple de topology spread exigeant 3 zones :
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: example
Si le cluster n’a qu’1 zone ou pas assez de nœuds par zone, le pod ne peut pas s’ordonnancer. Soit :
A. Ajoutez des nœuds sur plusieurs zones :
kubectl get nodes -o wide | grep "REGION\|ZONE"
B. Assouplissez la contrainte :
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway # Changé de DoNotSchedule
Ou supprimez complètement la topology spread si elle n’est pas nécessaire.
Appliquez et réessayez :
kubectl apply -f deployment.yaml
Éviter la récidive
-
Définissez toujours les resource requests et limits :
resources: requests: cpu: "100m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi" -
Surveillez la capacité du cluster :
kubectl top nodes kubectl describe node <node-name> | grep -A 10 "Allocated" -
Utilisez les node labels et selectors stratégiquement, uniquement quand réellement nécessaire. Évitez de sur-contraindre les pods.
-
Comprenez les taints des nœuds avant d’ordonnancer :
kubectl describe node | grep Taint -
Planifiez le provisioning des PVC : Assurez-vous que StorageClass ou PersistentVolumes existent avant de créer des pods qui en ont besoin.
-
Définissez des quotas de ressources raisonnables pour les namespaces, pas trop serrés :
kubectl get resourcequota -A -
Utilisez l’autoscaling des clusters pour les clusters cloud pour ajouter des nœuds quand des pods sont pending :
# GKE, EKS, AKS, etc. fournissent une configuration d'autoscaling
FAQ
Comment savoir pourquoi un pod est bloqué en Pending ?
Exécutez kubectl describe pod <pod> et regardez la section Events. Elle affiche la raison exacte du scheduler, par ex. ‘Insufficient cpu’ ou ‘node has a taint’.
Quelle est la différence entre Pending et FailedScheduling ?
Pending signifie que le scheduler n’a pas encore assigné le pod à un nœud. FailedScheduling est un événement indiquant qu’une tentative d’ordonnancement a échoué. Vérifiez kubectl describe pod pour voir les événements.
Comment voir combien de CPU et mémoire sont disponibles sur les nœuds ?
Utilisez kubectl top nodes ou kubectl describe node pour voir les ressources allouées/disponibles. Aussi vérifiez kubectl get nodes pour voir le statut NotReady.
Qu’est-ce que les taints et tolerations, et pourquoi bloquent-elles les pods ?
Un taint marque un nœud comme inadapté pour certains pods. Une toleration sur un pod lui permet de s’exécuter sur les nœuds taintés. Vérifiez kubectl describe node | grep Taint et les tolerations de votre spec pod.
Comment ce guide a été vérifié
Rédigé à la main à partir de la documentation officielle, chaque commande revérifiée, puis relu une seconde fois avant publication. Dernière relecture le .
Sources officielles consultées pour cet article

