Introduction
La priorité et la préemption des pods sont des fonctionnalités critiques de planification de Kubernetes qui vous aident à exécuter des charges de travail critiques lorsque les ressources du cluster sont rares. Mais des erreurs de configuration peuvent silencieusement casser la planification, évincer les mauvais pods ou laisser des pods de haute priorité bloqués en état Pending. Ce guide passe en revue les erreurs courantes, les correctifs pratiques et les étapes de vérification avec des commandes et des exemples concrets. Il est destiné aux développeurs, aux ingénieurs DevOps et aux équipes plateforme qui exploitent des clusters Kubernetes en production.
Nous mettons l'accent sur la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés au lieu de secrets dans les exemples, vérifier le résultat et documenter les chemins de récupération. Chaque correctif inclut la sortie ou le signal attendu pour que vous sachiez s'il a fonctionné.
Inventaire de la version et de l'environnement
Avant de changer quoi que ce soit, confirmez la version de votre cluster, la configuration du planificateur et les définitions de ressources pertinentes. Le comportement de la priorité et de la préemption a évolué au fil des versions de Kubernetes ; par exemple, les PriorityClasses non préemptives sont devenues stables en 1.24. Vérifiez toujours ce que votre cluster prend en charge.
Vérifier la version du cluster :
kubectl version --short
La sortie attendue montre les versions client et serveur, par exemple Server Version: v1.27.3.
Vérifier si l'API PriorityClass est disponible :
kubectl api-versions | grep scheduling.k8s.io
La sortie attendue inclut scheduling.k8s.io/v1.
Lister les PriorityClasses existantes :
kubectl get priorityclass
La sortie attendue inclut les noms, les valeurs et les indicateurs globalDefault. Si cette commande échoue ou ne renvoie rien, aucune PriorityClass n'existe encore.
Vérifier la configuration du planificateur : Si vous utilisez un planificateur personnalisé ou avez modifié les paramètres de kube-scheduler, vérifiez que la préemption n'est pas désactivée. Dans la politique du planificateur ou la KubeSchedulerConfiguration, assurez-vous que disablePreemption: false (la valeur par défaut). Pour les clusters utilisant le planificateur par défaut, c'est rarement un problème, mais des configurations personnalisées peuvent le définir à true.
Prérequis :
- Accès administrateur du cluster pour créer des PriorityClasses et modifier des charges de travail.
- kubectl configuré avec le contexte approprié.
- Compréhension de vos demandes de ressources et de la capacité des nœuds.
Observation en lecture seule avant les modifications :
kubectl get pods -o wide --all-namespaces | grep -i pending
Cela montre les pods actuellement bloqués en état Pending, un premier symptôme courant.
kubectl describe pod <pod-name> -n <namespace>
Recherchez des événements comme 0/3 nodes are available: 3 Insufficient cpu. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod. Cela vous indique si la préemption est même tentée.
Exemple d'inventaire de l'environnement :
- Version Kubernetes : v1.26.5
- Planificateur : kube-scheduler par défaut
- PriorityClasses définies : high-priority (valeur 1000), default (valeur 0), low-priority (valeur -10)
- Capacité des nœuds : 3 nœuds worker, chacun 4 vCPU / 8 Go de RAM
- Charges de travail : web (low-priority), api (high-priority), batch (medium-priority)
Gardez les tests locaux petits avant de déployer des changements à l'échelle du cluster. Appliquez un manifeste à la fois et inspectez les résultats.
Chemin de configuration sûr
Pour utiliser correctement la priorité des pods, vous devez définir des PriorityClasses et les référencer dans les spécifications des pods. Les erreurs courantes incluent l'absence de globalDefault, un mauvais preemptionPolicy et des valeurs de priorité qui ne correspondent pas au comportement prévu.
Étape 1 : Créer une PriorityClass
Exemple de PriorityClass pour les charges de travail critiques :
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000
globalDefault: false
preemptionPolicy: PreemptLowerPriority
description: "Pour les pods API critiques qui doivent être planifiés même sous pression de ressources."
Appliquez-la :
kubectl apply -f high-priority-class.yaml
Sortie attendue : priorityclass.scheduling.k8s.io/high-priority created.
Vérifiez :
kubectl get priorityclass high-priority -o yaml
Vérifiez que value et preemptionPolicy sont corrects.
Erreur courante : Définir preemptionPolicy: Never alors que vous avez réellement besoin de préemption. Si un pod de haute priorité a preemptionPolicy: Never, il n'évincera pas les pods de priorité inférieure et peut rester en Pending. Utilisez Never uniquement pour les pods qui ne doivent jamais provoquer d'éviction, comme les add-ons de cluster qui peuvent attendre.
Étape 2 : Référencer la PriorityClass dans un Pod ou un Deployment
Exemple de spécification de pod :
apiVersion: v1
kind: Pod
metadata:
name: api-pod
spec:
priorityClassName: high-priority
containers:
- name: api
image: nginx
resources:
requests:
cpu: "2"
memory: "1Gi"
Appliquez et vérifiez :
kubectl apply -f api-pod.yaml
kubectl get pod api-pod -o yaml | grep priorityClassName
La sortie attendue inclut priorityClassName: high-priority.
Erreur courante : Mal orthographier le priorityClassName ou référencer une PriorityClass inexistante. Le pod sera rejeté avec une erreur comme PriorityClass "high-priorty" not found. Vérifiez toujours que le nom correspond exactement.
Étape 3 : Définir une valeur par défaut globale (facultatif)
Si vous voulez que tous les pods sans priorityClassName reçoivent une priorité par défaut, créez une PriorityClass avec globalDefault: true. Une seule peut être la valeur par défaut globale par cluster. Exemple :
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: default-priority
value: 0
globalDefault: true
preemptionPolicy: PreemptLowerPriority
Appliquez et vérifiez :
kubectl apply -f default-priority.yaml
kubectl get priorityclass
La sortie doit montrer default-priority avec GLOBAL DEFAULT à true.
Erreur courante : Avoir plusieurs PriorityClasses avec globalDefault: true. Le serveur API rejette la seconde avec une erreur. Une seule peut être la valeur par défaut globale.
Vérification de la configuration sûre
Après l'application, testez la planification dans un namespace contrôlé. Créez un pod de basse priorité qui consomme des ressources, puis un pod de haute priorité qui devrait le préempter.
Exemple de pod de basse priorité (utilise toute la capacité du nœud) :
apiVersion: v1
kind: Pod
metadata:
name: low-priority-pod
namespace: test-preemption
spec:
priorityClassName: low-priority
containers:
- name: stress
image: polinux/stress
resources:
requests:
cpu: "2"
memory: "1Gi"
Créez le namespace et le pod :
kubectl create namespace test-preemption
kubectl apply -f low-priority-pod.yaml
Attendez qu'il soit en état Running.
Maintenant, créez un pod de haute priorité qui demande plus que disponible :
apiVersion: v1
kind: Pod
metadata:
name: high-priority-pod
namespace: test-preemption
spec:
priorityClassName: high-priority
containers:
- name: api
image: nginx
resources:
requests:
cpu: "1"
memory: "512Mi"
Appliquez :
kubectl apply -f high-priority-pod.yaml
Vérifiez le statut :
kubectl get pods -n test-preemption
Attendu : high-priority-pod devient Running, et low-priority-pod est en Terminating ou Evicted. Sinon, inspectez les événements avec kubectl describe pod high-priority-pod -n test-preemption.
Vérification et diagnostics
Lorsque les pods ne sont pas planifiés comme prévu, rassemblez systématiquement des diagnostics.
1. Vérifier le statut du pod et les événements
kubectl get pods -n <namespace> -o wide
kubectl describe pod <pod-name> -n <namespace>
Recherchez des événements mentionnant la préemption, la priorité ou des ressources insuffisantes.
Exemple d'événement problématique :
0/3 nodes are available: 3 Insufficient cpu. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod.
Cela signifie que le planificateur n'a pas trouvé de pods de priorité inférieure à évincer pour faire de la place. Les causes incluent :
- Aucun pod de priorité inférieure n'existe sur les nœuds.
- Les pods de priorité inférieure ont
preemptionPolicy: Never(ils ne peuvent donc pas être préemptés) ou sont dans un PodDisruptionBudget qui empêche l'éviction. - Le pod de haute priorité lui-même a
preemptionPolicy: Never. - Les nœuds ont des taints ou d'autres contraintes empêchant la planification même après préemption.
2. Vérifier les valeurs et politiques des PriorityClasses
kubectl get priorityclass <name> -o yaml
Vérifiez value, preemptionPolicy et globalDefault.
Erreur courante : Valeurs de priorité mal définies. Une valeur numérique plus élevée signifie une priorité plus élevée. Si votre classe "haute" priorité a la valeur 10 et "basse" a 1000, vous avez inversé les priorités. Utilisez une échelle claire, par exemple 1000 pour critique, 100 pour normal, -10 pour best-effort.
3. Inspecter les journaux du planificateur (si vous y avez accès)
Si vous utilisez kube-scheduler comme pod statique, affichez les journaux :
kubectl logs -n kube-system kube-scheduler-<node-name> | grep -i preempt
Recherchez des lignes comme Attempting to preempt pods for pod ... ou des erreurs sur la recherche de victimes.
Pour les clusters gérés (EKS, GKE, AKS), les journaux du planificateur peuvent être disponibles via la journalisation du fournisseur cloud.
4. Vérifier les PodDisruptionBudgets
Les PodDisruptionBudgets (PDB) peuvent bloquer la préemption si l'éviction violerait le budget.
kubectl get pdb -n <namespace>
Si un pod de priorité inférieure est protégé par un PDB avec minAvailable: 1, le planificateur peut ne pas l'évincer, ce qui laisse le pod de priorité supérieure en Pending.
Exemple : Un déploiement avec une réplique et un PDB minAvailable: 1. Le pod unique ne peut pas être évincé, donc aucune préemption ne se produit.
5. Vérifier les demandes de ressources et l'allocatable du nœud
Parfois, la préemption échoue car le pod entrant demande plus de ressources que tout nœud ne peut fournir même après avoir évincé tous les pods de priorité inférieure.
kubectl describe node <node-name> | grep -A5 "Allocated resources"
Comparez les demandes du pod avec la capacité allocatable du nœud.
Erreur courante : Cela se produit avec des demandes surdimensionnées ; réduisez les demandes de ressources du pod ou ajoutez des nœuds.
Modes de défaillance et récupération
Voici des scénarios de défaillance spécifiques et des actions de récupération étape par étape.
Défaillance 1 : Pod de haute priorité bloqué en Pending avec "No preemption victims found"
Symptôme : L'événement dit No preemption victims found for incoming pod.
Cause : Aucun pod de priorité inférieure sur les nœuds qui satisfont d'autres contraintes de planification, ou les pods de priorité inférieure sont non préemptifs.
Correctif :
- Vérifiez les valeurs de priorité :
kubectl get priorityclass. - Assurez-vous que les pods de priorité inférieure existent et sont préemptibles (preemptionPolicy par défaut à PreemptLowerPriority).
- Si vous devez évincer des pods de même priorité, vous pouvez utiliser une éviction manuelle ou l'autoscaling du cluster.
- Considérez si le pod de haute priorité pourrait tolérer un autre nœud (tolérations, nodeSelector).
Vérification : Après ajustement, observez le pod :
kubectl get pod <name> -n <namespace> -w
Il doit passer à Running.
Défaillance 2 : Éviction involontaire de pods critiques
Symptôme : Un pod critique est évincé par un pod de priorité supérieure de manière inattendue.
Cause : Le pod critique avait une priorité basse ou aucune priorité (par défaut 0), et un nouveau pod de priorité supérieure est arrivé.
Correctif :
- Examinez les priorityClassNames des pods existants.
- Créez ou attribuez une PriorityClass appropriée aux pods critiques (par exemple, valeur 10000) et mettez à jour leurs déploiements.
- Envisagez de définir
preemptionPolicy: Neverpour les pods qui ne doivent jamais préempter les autres, mais notez que cela les empêche aussi d'être préemptés (ils deviennent non préemptifs dans les deux sens). - Utilisez des PodDisruptionBudgets pour protéger les pods critiques contre les interruptions volontaires, mais notez que les PDB n'empêchent pas la préemption dans tous les cas (la préemption n'est pas une interruption volontaire). Pour des garanties plus fortes, utilisez une PriorityClass avec une valeur élevée et assurez-vous qu'aucun pod de priorité supérieure n'est sans nécessité.
Vérification : Vérifiez que le pod critique reste Running lors du prochain événement de mise à l'échelle.
Défaillance 3 : Erreur PriorityClass introuvable
Symptôme : Lors de l'application d'un manifeste de pod, vous obtenez :
Error from server (NotFound): priorityclasses.scheduling.k8s.io "my-priority" not found
Correctif : Créez d'abord la PriorityClass, ou corrigez la référence de nom dans la spécification du pod.
Vérification : kubectl get priorityclass montre la classe attendue.
Défaillance 4 : La préemption ne se produit pas en raison de la préemption désactivée dans le planificateur
Symptôme : Même avec des PriorityClasses correctes, aucune préemption ne se produit ; les pods de haute priorité restent en Pending.
Cause : kube-scheduler peut avoir disablePreemption: true dans sa configuration.
Correctif :
- Vérifiez la configuration du planificateur (dans kube-system, configmap ou manifeste de pod statique).
- Définissez
disablePreemption: false(ou supprimez la ligne). - Redémarrez kube-scheduler.
Vérification : Après redémarrage, observez les journaux du planificateur pour les tentatives de préemption.
Défaillance 5 : La préemption provoque des évictions en cascade
Symptôme : Plusieurs pods sont évincés en réaction en chaîne lorsqu'un seul pod de haute priorité est planifié.
Cause : La préemption peut évincer un pod, mais si les ressources sont encore insuffisantes, elle en évince davantage. Cela peut se produire si le pod de haute priorité demande beaucoup de ressources.
Correctif :
- Dimensionnez correctement les demandes du pod de haute priorité.
- Ajoutez plus de nœuds ou utilisez l'autoscaler du cluster.
- Utilisez les priorités avec soin : n'attribuez une haute priorité qu'aux charges de travail vraiment critiques.
- Envisagez d'utiliser
preemptionPolicy: Neverpour les pods de haute priorité qui peuvent attendre.
Vérification : Surveillez le nombre de pods et les événements d'éviction avec kubectl get events --sort-by=.lastTimestamp.
Liste de contrôle des opérations
Utilisez cette liste de contrôle pour résoudre systématiquement les problèmes de priorité et de préemption des pods.
| Étape | Action | Commande / Exemple | Résultat attendu |
|---|---|---|---|
| 1 | Vérifier la version du cluster et l'API | kubectl version --short et kubectl api-versions | grep scheduling.k8s.io | Version serveur >=1.14 et API scheduling présente |
| 2 | Lister les PriorityClasses | kubectl get priorityclass | Toutes les classes attendues avec des valeurs correctes |
| 3 | Vérifier les pods en attente | kubectl get pods --all-namespaces | grep Pending | Identifier les pods nécessitant une attention |
| 4 | Décrire un pod en attente | kubectl describe pod <name> -n <ns> | Rechercher des événements liés à la préemption |
| 5 | Inspecter le YAML de la PriorityClass | kubectl get priorityclass <name> -o yaml | Vérifier value, preemptionPolicy, globalDefault |
| 6 | Vérifier les PodDisruptionBudgets | kubectl get pdb -n <ns> | Identifier les PDB qui peuvent bloquer l'éviction |
| 7 | Vérifier la config du planificateur (si personnalisé) | kubectl -n kube-system get configmap kube-scheduler -o yaml ou inspecter le manifeste du pod statique | Assurer disablePreemption: false |
| 8 | Examiner les ressources du nœud | kubectl describe node <node> | Comparer allocatable vs demandé |
| 9 | Tester la préemption dans un namespace isolé | Créer des pods basse et haute priorité comme montré | Le pod haute priorité s'exécute, le pod basse priorité est évincé |
| 10 | Documenter les étapes de récupération | Enregistrer ce qui a été changé et comment revenir en arrière | Runbook mis à jour |
Remplacez <name>, <ns>, <node> par vos noms de ressources réels. Cette liste de contrôle vous aide à couvrir les points de défaillance courants sans manquer de diagnostics critiques.
Conclusion
La priorité et la préemption des pods sont puissantes mais doivent être configurées avec soin. Des erreurs courantes comme des valeurs de priorité inversées, des PriorityClasses manquantes, des politiques de préemption mal configurées et des demandes de ressources supérieures à la capacité du nœud peuvent provoquer des échecs de planification ou des évictions inattendues. En observant systématiquement l'état du cluster, en appliquant des changements minimaux et en vérifiant avec des commandes concrètes, vous pouvez résoudre la plupart des problèmes sans conjectures.
Prochaines étapes : commencez par une vérification à faible risque dans un namespace de test, enregistrez l'état actuel, appliquez une PriorityClass et simulez un scénario de préemption comme décrit. Surveillez les résultats et ajustez. Rappelez-vous que la préemption est un dernier recours ; pour les charges de travail critiques, dimensionnez correctement les demandes de ressources, utilisez l'autoscaling du cluster et définissez des priorités appropriées pour minimiser les perturbations.
Un flux de travail opérationnel fiable rend les défaillances visibles, protège les valeurs sensibles, limite les modifications aux ressources prévues et définit la vérification de la récupération avant qu'un incident ne force une décision.