## 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 :** ```bash 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 :** ```bash kubectl api-versions | grep scheduling.k8s.io ``` La sortie attendue inclut `scheduling.k8s.io/v1`. **Lister les PriorityClasses existantes :** ```bash 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 :** ```bash 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. ```bash kubectl describe pod -n ``` 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 : ```yaml 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 : ```bash kubectl apply -f high-priority-class.yaml ``` Sortie attendue : `priorityclass.scheduling.k8s.io/high-priority created`. Vérifiez : ```bash 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 : ```yaml 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 : ```bash 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 : ```yaml apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: default-priority value: 0 globalDefault: true preemptionPolicy: PreemptLowerPriority ``` Appliquez et vérifiez : ```bash 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) : ```yaml 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 : ```bash 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 : ```yaml 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 : ```bash kubectl apply -f high-priority-pod.yaml ``` Vérifiez le statut : ```bash 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 ```bash kubectl get pods -n -o wide kubectl describe pod -n ``` 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 ```bash kubectl get priorityclass -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 : ```bash kubectl logs -n kube-system kube-scheduler- | 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. ```bash kubectl get pdb -n ``` 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. ```bash kubectl describe node | 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 :** 1. Vérifiez les valeurs de priorité : `kubectl get priorityclass`. 2. Assurez-vous que les pods de priorité inférieure existent et sont préemptibles (preemptionPolicy par défaut à PreemptLowerPriority). 3. Si vous devez évincer des pods de même priorité, vous pouvez utiliser une éviction manuelle ou l'autoscaling du cluster. 4. 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 : ```bash kubectl get pod -n -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 :** 1. Examinez les priorityClassNames des pods existants. 2. Créez ou attribuez une PriorityClass appropriée aux pods critiques (par exemple, valeur 10000) et mettez à jour leurs déploiements. 3. Envisagez de définir `preemptionPolicy: Never` pour 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). 4. 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 :** 1. Vérifiez la configuration du planificateur (dans kube-system, configmap ou manifeste de pod statique). 2. Définissez `disablePreemption: false` (ou supprimez la ligne). 3. 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: Never` pour 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 -n ` | Rechercher des événements liés à la préemption | | 5 | Inspecter le YAML de la PriorityClass | `kubectl get priorityclass -o yaml` | Vérifier value, preemptionPolicy, globalDefault | | 6 | Vérifier les PodDisruptionBudgets | `kubectl get pdb -n ` | 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 ` | 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 ``, ``, `` 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.