Introduction
La priorité et la préemption des pods Kubernetes sont une fonctionnalité du planificateur qui aide les opérateurs de cluster à protéger les charges de travail critiques lors des pénuries de ressources. Lorsqu'un cluster manque de capacité, le planificateur peut expulser des pods de priorité inférieure pour faire de la place à ceux de priorité supérieure. Ce mécanisme est puissant, mais il peut provoquer des perturbations inattendues s'il n'est pas planifié avec soin.
Cet article s'adresse aux développeurs, aux consultants DevOps et aux équipes techniques de startups qui doivent planifier la capacité d'un cluster en tenant compte de la priorité et de la préemption. Il relie les concepts fondamentaux des classes de priorité, des politiques de préemption, des demandes de ressources et de la capacité des nœuds à des commandes pratiques, des sorties attendues, des signaux d'échec et des décisions de récupération. Vous apprendrez à observer l'état actuel avant d'apporter des modifications, à limiter le rayon d'impact de toute intervention, à vérifier le résultat et à documenter les chemins de récupération.
L'objectif est la sécurité opérationnelle. Vous ne devez jamais appliquer un changement de priorité sans comprendre quels pods pourraient être expulsés en conséquence. Utilisez d'abord une inspection en lecture seule, protégez les valeurs sensibles avec des espaces réservés, modifiez un élément à la fois et vérifiez toujours que l'état attendu a été atteint. Cet article fournit un flux de travail structuré que vous pouvez adapter à vos propres clusters.
Inventaire des versions et de l'environnement
Avant d'utiliser la priorité et la préemption, confirmez la version de Kubernetes que vous exécutez et si la fonctionnalité est activée. La priorité et la préemption des pods sont stables et activées par défaut dans Kubernetes v1.14 et les versions ultérieures. Pour les versions antérieures, vous devrez peut-être activer la porte de fonctionnalité PodPriority sur le serveur d'API et le planificateur.
Vérifiez la version de votre cluster avec :
kubectl version --short
La sortie attendue comprend les versions client et serveur. Si la version du serveur est inférieure à v1.14, planifiez une mise à niveau ou vérifiez que la porte de fonctionnalité est explicitement activée.
Ensuite, vérifiez les PriorityClasses actuelles dans le cluster :
kubectl get priorityclass
Une sortie typique ressemble à :
NAME VALUE GLOBAL-DEFAULT AGE
system-cluster-critical 2000000000 false 30d
system-node-critical 2000001000 false 30d
Si aucune PriorityClass personnalisée n'existe, vous ne verrez que les deux classes système intégrées. Ces classes système sont utilisées par les composants critiques du cluster et ne doivent pas être attribuées aux charges de travail utilisateur.
Pour la planification de capacité, vous devez également connaître le total des ressources allouables sur vos nœuds :
kubectl describe nodes | grep -A 5 "Allocatable"
Cela affiche le CPU et la mémoire disponibles pour les pods sur chaque nœud. Comparez ces chiffres avec le total des demandes de ressources des pods en cours d'exécution :
kubectl get pods -A -o=jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.containers[*].resources.requests}{"\n"}{end}'
Cette commande imprime les demandes de ressources pour chaque conteneur. Additionnez-les par espace de noms ou par nœud pour comprendre l'utilisation actuelle. Par exemple, si trois pods sur un nœud demandent chacun 500m de CPU et que le CPU allouable du nœud est de 2000m, le nœud a encore 500m disponibles pour de nouveaux pods.
Lors de la planification des changements de priorité, identifiez les déploiements ou StatefulSets qui pourraient être affectés. Inspectez une charge de travail spécifique avec :
kubectl get deployment <nom> -o yaml
Recherchez priorityClassName dans le modèle de pod. S'il n'est pas défini, le pod reçoit la PriorityClass globalDefault si elle existe, sinon la priorité 0.
Gardez votre environnement de test local petit. Avant de modifier les priorités sur un cluster de production, reproduisez le scénario sur un cluster local à l'aide de kind ou minikube. Appliquez un manifeste à la fois, inspectez les ressources générées et vérifiez que la planification se comporte comme prévu. Utilisez kubectl port-forward pour tester les services localement avant de passer à un équilibreur de charge cloud ou à un contrôleur d'entrée.
Chemin de configuration sécurisé
Un chemin de configuration sécurisé pour la priorité et la préemption commence par la définition de PriorityClasses claires qui reflètent vos niveaux métier. Les niveaux typiques sont :
- Infrastructure critique (valeur >= 1000000000) : agents de surveillance, redirecteurs de journaux, proxys de maillage de services qui doivent s'exécuter sur chaque nœud.
- Applications de production (valeur autour de 100000 ou 10000) : services orientés utilisateur qui doivent rester disponibles mais peuvent tolérer une brève expulsion en faveur de l'infrastructure.
- Charges de travail par lots ou de développement (valeur 100 ou moins) : travaux facultatifs, déploiements de test et traitement en arrière-plan qui peuvent être expulsés sans impact.
La valeur est un entier de 32 bits. Des valeurs plus élevées signifient une priorité plus élevée. N'utilisez des valeurs supérieures à 1 milliard que pour les composants critiques du système ; les charges de travail utilisateur doivent rester en dessous de ce seuil.
Créez une PriorityClass pour les applications de production :
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: production-priority
value: 10000
globalDefault: false
description: "Priorité pour les applications de production"
Appliquez-la :
kubectl apply -f production-priority.yaml
Vérifiez qu'elle existe :
kubectl get priorityclass production-priority
Attribuez maintenant cette PriorityClass à un déploiement. Ajoutez priorityClassName: production-priority au modèle de pod :
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-frontend
spec:
replicas: 3
selector:
matchLabels:
app: web-frontend
template:
metadata:
labels:
app: web-frontend
spec:
priorityClassName: production-priority
containers:
- name: nginx
image: nginx:1.25
resources:
requests:
cpu: "200m"
memory: "256Mi"
Appliquez le déploiement et vérifiez que les pods sont créés avec la priorité définie :
kubectl apply -f web-frontend.yaml
kubectl get pods -l app=web-frontend -o wide
kubectl describe pod <nom-du-pod> | grep -i priority
La sortie de describe doit inclure une ligne comme :
Priority: 10000
Pour tester la préemption sans nuire aux charges de travail réelles, créez un pod de remplissage de faible priorité qui consomme une grande quantité de ressources, puis tentez de planifier un pod de haute priorité qui nécessite ces ressources. Par exemple, créez un pod de remplissage qui demande 1 CPU sur un nœud avec 2 CPU allouables. Créez ensuite un pod de haute priorité demandant 1,5 CPU. Le planificateur devrait expulser le pod de remplissage pour placer celui de haute priorité.
Voici un pod de remplissage avec priorité 0 (aucune classe explicite) :
apiVersion: v1
kind: Pod
metadata:
name: filler
spec:
containers:
- name: stress
image: polinux/stress
resources:
requests:
cpu: "1000m"
memory: "500Mi"
nodeSelector:
kubernetes.io/hostname: <nom-de-votre-nœud>
Et un pod de haute priorité :
apiVersion: v1
kind: Pod
metadata:
name: important-job
spec:
priorityClassName: production-priority
containers:
- name: app
image: nginx
resources:
requests:
cpu: "1500m"
memory: "500Mi"
nodeSelector:
kubernetes.io/hostname: <nom-de-votre-nœud>
Après avoir appliqué le pod de haute priorité, surveillez les événements :
kubectl get events --watch
Vous devriez voir des événements indiquant que le pod de remplissage a été préempté :
Preempted: pod/filler
Vérifiez maintenant que le pod de haute priorité est planifié et en cours d'exécution, tandis que le remplissage est terminé :
kubectl get pods
Testez toujours dans un espace de noms ou un cluster dédié pour éviter l'expulsion accidentelle de charges de travail importantes.
Vérification et diagnostic
Après avoir appliqué les configurations de priorité, vous devez vérifier que le planificateur se comporte comme prévu et diagnostiquer tout problème. Utilisez les commandes suivantes pour inspecter l'état et les événements.
Tout d'abord, vérifiez l'état de tous les pods :
kubectl get pods -o wide
Recherchez les pods bloqués à l'état Pending. Un pod en attente peut indiquer des ressources insuffisantes ou que la préemption ne se produit pas comme prévu.
Inspectez un pod en attente spécifique :
kubectl describe pod <nom-du-pod>
La section des événements montrera pourquoi le pod ne peut pas être planifié. Les messages courants incluent :
0/3 nodes are available: 3 Insufficient cpu.Preemption is not helpful for scheduling.
Le deuxième message apparaît lorsque le planificateur ne peut pas expulser les pods de priorité inférieure pour faire de la place, peut-être parce que le pod en attente a une priorité inférieure ou égale à celle des pods existants, ou parce que les budgets de perturbation de pods empêchent l'expulsion.
Vérifiez les journaux du planificateur pour les décisions de préemption. Si vous avez accès au plan de contrôle :
kubectl logs -n kube-system <nom-du-pod-planificateur> | grep -i preempt
Les journaux du planificateur incluent des entrées comme :
"Preempting" pod="namespace/name"
"Preemption succeeded"
"Preemption failed"
Si la préemption échoue, vérifiez si le pod a un priorityClassName défini et si la valeur de la PriorityClass est supérieure à celle des victimes. Vérifiez également si un budget de perturbation de pod (PDB) bloque l'expulsion :
kubectl get pdb -A
Vérifiez que les demandes et limites de ressources sont correctement configurées. Utilisez :
kubectl get pod <nom-du-pod> -o yaml | grep -A 5 resources
Si les demandes ne sont pas définies, le pod est traité comme demandant zéro ressource, ce qui peut entraîner une surallocation et une expulsion. Définissez toujours des demandes pour les charges de travail critiques.
Pour la planification de capacité, comparez l'utilisation réelle avec les demandes à l'aide de metrics-server (s'il est installé) :
kubectl top pods -A
Cela affiche l'utilisation du CPU et de la mémoire par pod. Si de nombreux pods utilisent beaucoup moins que leurs demandes, vous sur-demendez peut-être et provoquez une préemption inutile. Ajustez les demandes à des valeurs réalistes.
Modes de défaillance et récupération
La priorité et la préemption peuvent échouer de plusieurs manières. Comprendre ces modes de défaillance et disposer d'un plan de récupération est essentiel.
Mode de défaillance 1 : Le pod de haute priorité reste en attente
Si un pod de haute priorité est bloqué en attente, vérifiez les événements du planificateur :
kubectl describe pod <nom-du-pod> | tail -20
Causes possibles :
- Aucun pod de priorité inférieure sur les nœuds qui satisfont les contraintes de planification.
- La préemption est désactivée par la porte de fonctionnalité.
- Le budget de perturbation de pod empêche l'expulsion.
- Les sélecteurs de nœuds ou les règles d'affinité limitent le pod à des nœuds sans ressources suffisantes.
Récupération : ajustez les contraintes de planification du pod, augmentez la capacité du cluster ou assouplissez temporairement les PDB après avoir évalué les risques.
Mode de défaillance 2 : Charge de travail critique expulsée de manière inattendue
Si un pod de production est expulsé, vous le verrez dans un état Terminating ou un nouveau pod le remplacera. Vérifiez l'historique des événements :
kubectl get events --sort-by=.lastTimestamp | grep -i preempt
Pour récupérer, assurez-vous que la charge de travail critique a une PriorityClass suffisamment élevée. Créez une nouvelle PriorityClass avec une valeur plus élevée et attribuez-la. Par exemple :
kubectl create priorityclass critical-app --value=100000 --global-default=false
kubectl patch deployment <nom-du-déploiement> -p '{"spec":{"template":{"spec":{"priorityClassName":"critical-app"}}}}'
Vérifiez ensuite que les nouveaux pods s'exécutent avec la bonne priorité :
kubectl get pods -l app=<étiquette-app> -o wide
kubectl describe pod <nom-du-pod> | grep -i priority
Mode de défaillance 3 : Boucles de préemption
Parfois, deux déploiements de priorité égale peuvent se préempter mutuellement à plusieurs reprises s'ils demandent tous deux des ressources que l'autre détient. Cela peut provoquer une instabilité. Pour détecter cela, recherchez dans les journaux du planificateur des événements de préemption répétés pour les mêmes pods.
Prévenez cela en attribuant des priorités différentes aux charges de travail concurrentes ou en utilisant l'affinité de nœud pour les séparer. Utilisez un outil comme :
kubectl logs -n kube-system <nom-du-pod-planificateur> --since=1h | grep "Preemption"
Mode de défaillance 4 : La préemption ne se produit pas car la PriorityClass est manquante
Si un modèle de pod fait référence à une PriorityClass inexistante, le pod ne sera pas créé et le déploiement affichera une erreur :
kubectl describe deployment <nom-du-déploiement>
Vous verrez des événements comme :
Error creating: pods "<nom>" is forbidden: no PriorityClass with name production-priority was found
Récupération : créez la PriorityClass manquante ou corrigez la faute de frappe dans le déploiement.
Documentez toujours les étapes de récupération pour chaque mode de défaillance avant de déployer des changements de priorité en production. Utilisez des mécanismes de restauration comme kubectl rollout undo deployment/<nom> si nécessaire.
Liste de contrôle des opérations
Utilisez cette liste de contrôle avant et après la mise en œuvre des changements de priorité et de préemption.
Avant le changement :
- [ ] Enregistrez l'état actuel du cluster :
kubectl get nodes -o wide,kubectl get pods -A -o wide - [ ] Notez les PriorityClasses existantes :
kubectl get priorityclass - [ ] Identifiez tous les déploiements et pods qui pourraient être affectés.
- [ ] Vérifiez les demandes et limites de ressources :
kubectl get pods -A -o=jsonpath='{...}' - [ ] Passez en revue les budgets de perturbation de pods :
kubectl get pdb -A - [ ] Assurez-vous d'avoir un plan de restauration (par exemple, enregistrez les YAML actuels).
- [ ] Testez le changement dans un environnement non productif.
Appliquer le changement :
- [ ] Appliquez la nouvelle PriorityClass :
kubectl apply -f priorityclass.yaml - [ ] Patchez ou appliquez le déploiement avec
priorityClassName. - [ ] Utilisez
kubectl rollout status deployment/<nom>pour confirmer le déploiement.
Après le changement :
- [ ] Vérifiez que les pods s'exécutent :
kubectl get pods -o wide - [ ] Vérifiez la priorité des nouveaux pods :
kubectl describe pod <nom-du-pod> | grep Priority - [ ] Surveillez les événements pour une préemption inattendue :
kubectl get events --sort-by=.lastTimestamp - [ ] Si metrics-server est utilisé, comparez l'utilisation des ressources :
kubectl top pods -A - [ ] Mettez à jour la documentation avec le comportement observé.
Vérification de la récupération :
- [ ] Simulez une défaillance en créant un pod de faible priorité et un pod de haute priorité dans un espace de noms de test. Confirmez que la préemption fonctionne.
- [ ] Si la préemption ne fonctionne pas comme prévu, vérifiez les journaux du planificateur et les PDB.
- [ ] Vérifiez que la restauration rétablit l'état précédent : appliquez les YAML enregistrés ou
kubectl rollout undo.
Stockez toutes les commandes dans un runbook auquel votre équipe peut accéder. Utilisez des espaces réservés pour les valeurs sensibles et conservez les secrets dans des Secrets Kubernetes ou des gestionnaires de secrets externes.
Conclusion
La priorité et la préemption des pods Kubernetes sont un outil clé pour la planification de capacité, mais elles doivent être utilisées avec précaution. En définissant des PriorityClasses claires, en définissant des demandes de ressources appropriées et en testant le comportement de préemption dans un environnement contrôlé, vous pouvez vous assurer que les charges de travail critiques survivent aux pénuries de ressources tandis que les charges de travail de priorité inférieure sont expulsées gracieusement.
Cet article a fourni un flux de travail pratique : commencez par l'inventaire des versions et de l'environnement, passez à une configuration sécurisée, vérifiez le comportement avec des diagnostics, comprenez les modes de défaillance et suivez une liste de contrôle des opérations. Chaque étape comprend des commandes concrètes et des sorties attendues afin que vous puissiez reproduire les exemples dans votre propre cluster.
Comme prochaine étape, choisissez une vérification à faible risque dans l'article. Par exemple, créez deux pods de test avec des priorités différentes dans un espace de noms dédié et observez les événements de préemption. Enregistrez l'état actuel, exécutez les commandes documentées et comparez les résultats. Passez ensuite en revue vos déploiements de production pour détecter les priorityClassName et les demandes de ressources manquants.
Un flux de travail opérationnel fiable rend les défaillances visibles, protège les valeurs sensibles, limite les changements aux ressources prévues et définit la vérification de la récupération avant qu'un incident ne se produise. Avec les principes et les exemples de cet article, vous pouvez planifier la capacité en toute confiance en utilisant la priorité et la préemption des pods Kubernetes.