Erreurs de planification Kubernetes expliquées : solutions et meilleures pratiques
Kubernetes est la norme de facto pour l'orchestration des applications conteneurisées. Bien que sa nature déclarative simplifie le déploiement, le dépannage des raisons pour lesquelles un Pod refuse de démarrer — en particulier les échecs de planification — est un obstacle courant pour les opérateurs de cluster et les développeurs. Un Pod qui reste dans l'état Pending pendant une période prolongée indique que le planificateur Kubernetes ne peut pas trouver de nœud approprié pour l'exécuter.
Comprendre les erreurs de planification est crucial pour maintenir la disponibilité des applications et optimiser l'utilisation du cluster. Ce guide décomposera systématiquement les causes les plus fréquentes d'échecs de planification, telles que les ressources insuffisantes, les règles d'affinité incorrectes et les Taint restrictifs, en fournissant des solutions claires et des meilleures pratiques pour garantir que vos charges de travail atterrissent avec succès sur les nœuds disponibles.
Diagnostic des Pods en attente : la première étape
Avant de tenter des corrections, vous devez diagnostiquer avec précision pourquoi le planificateur échoue. L'outil principal pour cette investigation est kubectl describe pod.
Lorsqu'un Pod est bloqué dans l'état Pending, la section Events de la sortie de la commande describe contient des informations critiques détaillant le processus de décision de planification et tout rejet.
Utilisation de kubectl describe pod
Ciblez toujours le Pod problématique :
kubectl describe pod <nom-du-pod> -n <namespace>
Examinez la sortie, en portant une attention particulière à la section Events en bas. Les messages ici indiqueront explicitement la contrainte qui a empêché la planification. Les messages courants sont souvent liés à Insufficient cpu, Insufficient memory, ou à des échecs de prédicat spécifiques.
Catégories courantes d'erreurs de planification et solutions
Les échecs de planification entrent généralement dans trois catégories principales : Contraintes de ressources, Contraintes de politique (Affinité/Anti-Affinité) et Configuration des nœuds (Taint/Tolerations).
1. Contraintes de ressources (ressources insuffisantes)
C'est la cause la plus fréquente. Le planificateur nécessite un nœud capable de satisfaire les requêtes définies dans la spécification du Pod. Si aucun nœud n'a suffisamment de CPU ou de mémoire allouable disponible, le Pod restera en attente (Pending).
Identification du problème
La section Events affichera des messages tels que :
0/3 nodes are available: 3 Insufficient cpu.0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't match node selector.
Solutions pour les pénuries de ressources
- Réduire les requêtes du Pod : Si les requêtes du Pod sont excessivement élevées, essayez de réduire les
requestsde CPU ou de mémoire dans le YAML du Pod ou du Deployment. - Augmenter la capacité du cluster : Ajoutez plus de nœuds au cluster Kubernetes.
- Nettoyer les charges de travail existantes : Terminez les Pods de priorité inférieure ou non essentiels sur les nœuds existants pour libérer des ressources. (Utilisez
kubectl drainou ajustez les requêtes de ressources sur les déploiements existants). - Utiliser les Limit Ranges : Si votre namespace manque de limites de ressources définies, implémentez des objets
LimitRangepour empêcher des Pods uniques d'accaparer les ressources.
2. Sélecteurs de nœuds et règles d'affinité/anti-affinité
Kubernetes permet un contrôle granulaire sur l'emplacement où les Pods peuvent ou doivent être placés à l'aide de nodeSelector, nodeAffinity, et podAffinity/podAntiAffinity.
Discordance du sélecteur de nœud
Si vous définissez un nodeSelector qui ne correspond à aucun label présent sur aucun nœud disponible, le Pod ne peut pas être planifié.
Extrait YAML d'exemple (Cause d'échec) :
spec:
nodeSelector:
disktype: ssd-fast
containers: [...] # Le Pod reste en attente si aucun nœud n'a disktype=ssd-fast
Solution : Assurez-vous que le label spécifié dans nodeSelector existe sur au moins un nœud (kubectl get nodes --show-labels) et que la casse correspond exactement.
Contraintes d'affinité de nœud
nodeAffinity offre des règles plus flexibles (par exemple, requiredDuringSchedulingIgnoredDuringExecution ou preferredDuringSchedulingIgnoredDuringExecution). Si une règle required ne peut pas être satisfaite, le Pod reste en attente.
Conseil de diagnostic : Lors de l'utilisation de règles d'affinité complexes, la section Events indique souvent : node(s) didn't match node selector.
Affinité et Anti-Affinité de Pod
Ces règles contrôlent le placement par rapport aux autres Pods. Si, par exemple, une règle d'Anti-Affinité exige qu'un Pod ne s'exécute pas sur un nœud hébergeant un service spécifique, mais que tous les nœuds hébergent déjà ce service, la planification échouera.
Solution : Examinez attentivement la clé de topologie et le sélecteur dans vos règles d'affinité. Si une règle d'anti-affinité est trop restrictive, relâchez l'exigence ou vérifiez que les Pods cibles sélectionnés par la règle s'exécutent bien sur les nœuds que vous souhaitez éviter.
3. Taints et Tolérations
Les Taints sont appliqués directement aux nœuds pour repousser les Pods, tandis que les Tolérations sont ajoutées aux spécifications des Pods pour leur permettre d'accéder aux nœuds taints.
- Taint : Repousse les Pods sauf s'ils ont une tolération correspondante.
- Toleration : Permet à un Pod d'être planifié sur un nœud avec un taint correspondant.
Identification du rejet par Taint
Les Events indiqueront explicitement la raison du rejet :
0/3 nodes are available: 2 node(s) had taint {dedicated: special-workload, effect: NoSchedule}, that the pod didn't tolerate.
Solutions pour les Taints et les Tolérations
Vous avez deux voies principales :
-
Modifier le Pod (recommandé pour les Pods applicatifs) : Ajoutez les
tolerationsrequises à la spécification du Pod qui correspondent au taint du nœud.Exemple de Tolération :
yaml spec: tolerations: - key: "dedicated" operator: "Equal" value: "special-workload" effect: "NoSchedule" containers: [...] -
Modifier le Nœud (recommandé pour les administrateurs de cluster) : Supprimez le taint du nœud si la restriction n'est plus nécessaire.
```bash
Pour supprimer un taint
kubectl taint nodes
dedicated:special-workload:NoSchedule-
```
Alerte Meilleure Pratique : Évitez de tolérer le taint global
node-role.kubernetes.io/master:NoSchedulesur les Pods applicatifs, sauf si vous planifiez intentionnellement des composants critiques du plan de contrôle sur les nœuds maîtres.
Contraintes de planification avancées
Des contraintes moins courantes, mais importantes, peuvent également bloquer la planification :
Contraintes de volume de stockage
Si un Pod demande un PersistentVolumeClaim (PVC) qui ne peut pas être actuellement lié à un nœud disponible (par exemple, en raison d'exigences spécifiques du provisionneur de stockage ou de l'indisponibilité du volume), le Pod peut rester en attente.
Diagnostic : Vérifiez d'abord l'état du PVC (kubectl describe pvc <nom-du-pvc>). Si le PVC est bloqué dans l'état Pending, la planification du Pod est interrompue jusqu'à ce que le volume soit disponible.
DaemonSets et Topologies de Répartition
Les DaemonSets ne seront planifiés que sur les nœuds correspondant à leurs critères de sélection (le cas échéant). Si un cluster est partitionné ou si un nouveau nœud ne correspond pas au sélecteur du DaemonSet, il ne s'exécutera pas.
Contraintes de répartition de topologie (si définies) garantissent une distribution uniforme. Si la distribution actuelle empêche le placement sur n'importe quel nœud tout en respectant les contraintes de répartition, la planification échouera.
Meilleures pratiques pour une planification réussie
Pour minimiser les problèmes de planification, adoptez ces meilleures pratiques opérationnelles :
- Définir explicitement les requêtes de ressources : Définissez toujours des
requests(et deslimitsoptionnels) raisonnables pour le CPU et la mémoire. Cela permet au planificateur d'évaluer avec précision la capacité des nœuds. - Utiliser des labels de nœud pour le zonage : Implémentez un étiquetage cohérent des nœuds (par exemple,
hardware=gpu,zone=us-east-1a) et utiliseznodeSelectorounodeAffinitypour diriger les charges de travail vers le matériel approprié. - Documenter les Taints et les Tolérations : Si des nœuds sont taints pour la maintenance ou la ségrégation matérielle, documentez ces taints de manière centralisée. Assurez-vous que les manifestes d'application nécessitant un accès aux ressources taints incluent les tolérations correspondantes.
- Surveiller l'autoscaler de cluster (si utilisé) : Si vous vous fiez à des solutions de mise à l'échelle, assurez-vous qu'elles fonctionnent. Un manque de capacité qui devrait déclencher la mise à l'échelle peut échouer silencieusement, laissant les Pods en attente.
- Examiner les logs du planificateur (avancé) : Pour des investigations approfondies, examinez les logs du composant
kube-schedulerlui-même, car il enregistre chaque tentative de planification et chaque raison de rejet.
Conclusion
Les erreurs de planification Kubernetes, bien que frustrantes, sont presque toujours attribuables à une inadéquation entre ce dont le Pod a besoin (requêtes, affinité, tolérations) et ce que les nœuds offrent (capacité, labels, absence de taints). En utilisant systématiquement kubectl describe pod pour inspecter les Events et en abordant les limitations de ressources, les incompatibilités d'affinité ou les barrières de Taint, vous pouvez résoudre rapidement les Pods en attente et garantir le bon fonctionnement de votre orchestration de conteneurs.