Introduction
Les classes de priorité Kubernetes influencent la façon dont l'ordonnanceur trie les pods en attente et quels pods sont évincés lorsqu'un cluster manque de ressources. Une configuration de priorité inadéquate peut affamer les charges de travail critiques, provoquer des tempêtes de préemption bruyantes ou créer une latence d'ordonnancement difficile à tracer. Cet article vous montre comment optimiser les classes de priorité pour de meilleures performances à l'aide d'exemples pratiques, de commandes et d'étapes de vérification que vous pouvez exécuter sur un cluster en direct ou dans un environnement de test local.
Vous apprendrez à inventorier votre configuration de priorité actuelle, à appliquer des modifications en toute sécurité, à diagnostiquer le comportement d'ordonnancement, à gérer les modes de défaillance courants et à suivre une liste de vérification opérationnelle reproductible. Chaque exemple utilise un manifeste concret, une commande kubectl et une sortie attendue afin que vous puissiez reproduire les résultats.
Inventaire des versions et de l'environnement
Avant de modifier quoi que ce soit, confirmez ce que vous exécutez. PriorityClass est une API stable (scheduling.k8s.io/v1) disponible depuis Kubernetes 1.14. Vérifiez la version de votre cluster :
kubectl version --short
La sortie attendue montre à la fois les versions client et serveur. Par exemple :
Client Version: v1.27.3
Kustomize Version: v5.0.1
Server Version: v1.27.3
Votre cluster doit avoir le contrôleur d'admission PriorityClass activé. Dans la plupart des services Kubernetes gérés (EKS, GKE, AKS), il est activé par défaut. Pour vérifier, exécutez :
kubectl api-versions | grep scheduling.k8s.io
Si vous voyez scheduling.k8s.io/v1 dans la sortie, vous êtes prêt. Sinon, vérifiez le drapeau --enable-admission-plugins du kube-apiserver et assurez-vous que Priority est listé.
Ensuite, listez les PriorityClasses existants pour voir le paysage actuel :
kubectl get priorityclass
Exemple de sortie :
NAME VALUE GLOBAL-DEFAULT AGE
system-cluster-critical 2000000000 false 12d
system-node-critical 2000001000 false 12d
default 0 false 12d
high-priority 1000 false 2h
Notez la colonne VALUE : un nombre plus élevé signifie une priorité plus élevée. Les classes intégrées system-cluster-critical et system-node-critical ont des valeurs très élevées pour protéger les pods système. La PriorityClass default avec la valeur 0 est appliquée aux pods qui ne spécifient pas de priorityClassName. Si vous voyez GLOBAL-DEFAULT comme true, cela signifie que cette PriorityClass est utilisée lorsqu'aucun priorityClassName n'est défini et qu'aucun défaut n'est défini autrement.
Pour comprendre quels pods utilisent actuellement une priorité particulière, utilisez :
kubectl get pods -A -o custom-columns=NAME:.metadata.name,NAMESPACE:.metadata.namespace,PRIORITY:.spec.priorityClassName
Cela donne un aperçu rapide de la distribution des priorités à travers les namespaces. Extrait d'exemple :
NAME NAMESPACE PRIORITY
nginx-deployment-7d9f-abcde default high-priority
redis-0 redis <none>
Une entrée <none> signifie qu'aucun priorityClassName n'est défini, donc le pod reçoit le défaut global s'il est défini, sinon la priorité 0.
Vérifiez également si certains nœuds sont sous pression de ressources qui pourrait déclencher la préemption :
kubectl top nodes
Exemple :
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
minikube 250m 12% 900Mi 62%
Une pression élevée sur la mémoire ou le CPU augmente la probabilité d'événements de préemption, ce qui est directement lié au comportement des PriorityClass.
Portée de l'impact et chemin de récupération
Les modifications des PriorityClass affectent les décisions d'ordonnancement à l'échelle du cluster. Documentez toujours l'état actuel avant toute modification. Par exemple, sauvegardez les manifestes PriorityClass existants :
kubectl get priorityclass high-priority -o yaml > high-priority-backup.yaml
Examinez la sauvegarde pour comprendre les champs exacts que vous allez modifier.
Chemin de configuration sûr
Modifier une PriorityClass ou attribuer une priorité différente à une charge de travail peut avoir des effets immédiats : des pods peuvent être évincés, réordonnancés ou empêchés d'être ordonnancés. Suivez un processus contrôlé.
Étape 1 : Créer une PriorityClass de test
Commencez avec une nouvelle PriorityClass plutôt que de modifier une existante. Cela limite l'impact et permet un retour en arrière facile en supprimant la classe.
Exemple de manifeste test-priority.yaml :
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: test-priority
value: 100
preemptionPolicy: PreemptLowerPriority
globalDefault: false
description: "Priorité temporaire pour tester le comportement d'ordonnancement"
Appliquez-le :
kubectl apply -f test-priority.yaml
Vérifiez :
kubectl get priorityclass test-priority
Sortie :
NAME VALUE GLOBAL-DEFAULT AGE
test-priority 100 false 10s
Étape 2 : Déployer un pod utilisant la PriorityClass de test
Créez un pod qui utilise cette priorité :
apiVersion: v1
kind: Pod
metadata:
name: test-priority-pod
spec:
priorityClassName: test-priority
containers:
- name: nginx
image: nginx:latest
Appliquez et observez l'ordonnancement :
kubectl apply -f test-priority-pod.yaml
kubectl get pod test-priority-pod -o wide
La sortie attendue montre le pod en cours d'exécution et son nœud assigné :
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-priority-pod 1/1 Running 0 15s 10.244.1.5 worker-1 <none> <none>
Vérifiez les événements pour les détails de la décision d'ordonnancement :
kubectl describe pod test-priority-pod | grep -A5 Events
Recherchez un événement Scheduled sans avertissement.
Étape 3 : Tester le comportement de préemption (optionnel)
Pour voir comment la priorité affecte la préemption, créez une autre PriorityClass avec une valeur plus élevée et un pod qui peut déclencher l'éviction.
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority-test
value: 1000
preemptionPolicy: PreemptLowerPriority
Déployez un pod avec cette classe qui demande plus de CPU que ce qui est disponible. Par exemple, sur un nœud avec 2 CPU au total et 1,5 CPU déjà utilisés par d'autres pods, demandez 1 CPU. L'ordonnanceur peut évincer les pods de priorité inférieure pour faire de la place.
apiVersion: v1
kind: Pod
metadata:
name: high-demand-pod
spec:
priorityClassName: high-priority-test
containers:
- name: stress
image: polinux/stress
resources:
requests:
cpu: "1000m"
Après application, surveillez la préemption :
kubectl get events --sort-by=.metadata.creationTimestamp | grep Preempted
Si la préemption se produit, vous verrez des événements comme :
3s Normal Preempted pod/low-priority-pod Preempted by default/high-demand-pod on node worker-1
Cela vérifie que la priorité est respectée.
Étape 4 : Supprimer les ressources de test
Après vérification, nettoyez :
kubectl delete pod test-priority-pod high-demand-pod
kubectl delete priorityclass test-priority high-priority-test
C'est le chemin sûr : créez des ressources isolées, testez, puis supprimez.
Réglage des valeurs de PriorityClass pour la performance
La sélection de la valeur de priorité impacte la latence d'ordonnancement et l'équité. L'ordonnanceur traite les pods dans l'ordre de priorité ; les pods de priorité plus élevée sont considérés en premier, ce qui peut réduire leur latence d'ordonnancement. Cependant, définir des valeurs trop élevées pour des charges de travail non critiques peut retarder les pods critiques.
Choix des valeurs
Kubernetes attend que les valeurs de PriorityClass soient inférieures ou égales à 1 000 000 000 (un milliard). Les valeurs plus élevées sont réservées aux classes système critiques. Un modèle courant :
- 0 : charge de travail utilisateur par défaut
- 100-1000 : charges de travail utilisateur normales avec de légères différenciations (par exemple, 100 pour le batch, 500 pour le web, 1000 pour la base de données)
- 10000-100000 : charges de travail utilisateur à haute priorité (par exemple, API en temps réel)
- 1000000 : add-ons critiques pour le cluster
- 2000000000 et plus : system-node-critical et system-cluster-critical (intégrés)
Évitez de placer des charges de travail utilisateur dans les millions car elles peuvent préempter les composants système et causer de l'instabilité.
Exemple : Ajuster un déploiement de production
Supposons que vous ayez un déploiement api-server utilisant actuellement la priorité par défaut. Vous voulez lui donner une priorité plus élevée pour réduire la latence d'ordonnancement pendant les périodes de pointe. D'abord, observez son comportement d'ordonnancement actuel :
kubectl get pods -l app=api-server -o wide
Notez les heures de démarrage des pods et les éventuelles durées d'attente. Créez ensuite une nouvelle PriorityClass :
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: api-high
value: 5000
preemptionPolicy: PreemptLowerPriority
Appliquez-la et mettez à jour le déploiement :
kubectl apply -f priorityclass-api-high.yaml
kubectl patch deployment api-server -p '{"spec":{"template":{"spec":{"priorityClassName":"api-high"}}}}'
Cela déclenche une mise à jour progressive. Surveillez le déploiement :
kubectl rollout status deployment/api-server
Sortie attendue :
deployment "api-server" successfully rolled out
Maintenant, mesurez la latence d'ordonnancement avant et après. Vous pouvez utiliser les métriques de l'ordonnanceur Kubernetes si vous avez Prometheus ou utiliser les horodatages des événements de pod. Un moyen rapide :
kubectl get events --field-selector involvedObject.name=api-server-xxxxx | grep Scheduled
Comparez le temps entre la création du pod et l'événement programmé.
Surveillance de l'impact de la préemption
La préemption peut provoquer des évictions en cascade. Surveillez le taux d'événements de préemption :
kubectl get events --all-namespaces --field-selector reason=Preempted -w
Si vous voyez un pic, demandez-vous si vos valeurs de priorité sont trop agressives ou si la capacité du cluster doit être mise à l'échelle.
Vérification et diagnostic
Après avoir modifié les priorités, vérifiez que le comportement souhaité se produit et diagnostiquez tout retard ou échec d'ordonnancement inattendu.
Vérifier l'état de l'ordonnancement des pods
Listez les pods triés par classe de priorité pour voir si les pods de haute priorité sont ordonnancés en premier :
kubectl get pods -A -o custom-columns=NAME:.metadata.name,PRIORITY:.spec.priorityClassName,STATUS:.status.phase --sort-by=.spec.priority
Ce n'est pas directement pris en charge ; vous pouvez utiliser kubectl get pods -A -o json et traiter avec jq :
kubectl get pods -A -o json | jq -r '.items[] | [.metadata.name, .spec.priorityClassName, .status.phase] | @tsv' | sort
Mais si vous avez la valeur de priorité, vous pouvez joindre manuellement.
Commandes de diagnostic
kubectl describe pod <pod-name>montre les événements, y compris la préemption et les échecs d'ordonnancement.kubectl logs <pod-name> --previousaide si le pod a planté après l'ordonnancement.kubectl get events --sort-by=.metadata.creationTimestampdonne un flux d'événements à l'échelle du cluster pour les décisions d'ordonnancement.kubectl get nodes -o widemontre la capacité des nœuds et les ressources allouables.kubectl top nodesetkubectl top pods -Arévèlent l'utilisation des ressources qui influence l'ordonnancement.
Exemple : Diagnostiquer un pod en attente
Un pod peut rester en attente malgré une haute priorité. Enquêtez avec :
kubectl describe pod high-priority-pending-pod
Recherchez des événements comme :
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 2m default-scheduler 0/3 nodes are available: 1 Insufficient cpu, 2 node(s) had taint {dedicated: reserved}, that the pod didn't tolerate.
Cela indique que la priorité seule ne remplace pas les teintes ou les pénuries de ressources ; la préemption n'évince que les pods de priorité inférieure s'ils sont sur des nœuds éligibles et que le nouveau pod tolère les teintes.
Utilisation des journaux de l'ordonnanceur
Si vous avez accès aux journaux de l'ordonnanceur (par exemple, dans le namespace kube-system), vous pouvez activer la journalisation verbeuse pour voir les décisions de priorité :
kubectl logs -n kube-system kube-scheduler-minikube -v=4
Recherchez des lignes comme :
I0720 10:00:00.123456 1 schedule_one.go:243] "Attempting to schedule pod" pod="default/high-priority-pod"
I0720 10:00:00.125000 1 schedule_one.go:270] "Pod qualifies for preemption" pod="default/high-priority-pod"
Cela confirme que l'ordonnanceur a envisagé la préemption pour le pod de haute priorité.
Pièges courants et comment les éviter
De nombreux problèmes découlent d'une mauvaise compréhension de la sémantique des PriorityClass ou de l'ignorance des conditions du cluster. Voici les erreurs les plus fréquentes.
Piège 1 : Définir globalDefault incorrectement
Ce qui se passe : Si vous définissez globalDefault: true sur une PriorityClass de valeur élevée, tous les pods sans priorityClassName obtiennent cette priorité élevée, provoquant une préemption inattendue et éventuellement l'éviction de pods système.
Pourquoi cela arrive : Malentendu que globalDefault s'applique à l'échelle du cluster lorsqu'aucune classe de priorité n'est spécifiée.
Comment éviter : Une seule PriorityClass peut avoir globalDefault: true. Si vous avez besoin d'un défaut, utilisez la valeur 0 ou une valeur faible. Vérifiez avec kubectl get priorityclass -o wide et vérifiez la colonne GLOBAL-DEFAULT.
Récupération : Mettez à jour la PriorityClass pour définir globalDefault: false (ou supprimez-la), puis redémarrez les pods affectés afin qu'ils reprennent le défaut correct.
Piège 2 : Trop de niveaux de priorité
Ce qui se passe : Créer des dizaines de PriorityClasses avec des valeurs fines peut rendre le comportement d'ordonnancement imprévisible et difficile à raisonner.
Pourquoi cela arrive : Les équipes attribuent une priorité unique par microservice sans politique globale.
Comment éviter : Définissez un petit ensemble de niveaux de priorité (par exemple, 0, 100, 1000, 10000) et documentez leur utilisation prévue. Appliquez par politique ou par revue.
Récupération : Consolidez les PriorityClasses, mettez à jour les déploiements pour utiliser les niveaux consolidés, puis supprimez les classes inutilisées.
Piège 3 : Ignorer la politique de préemption
Ce qui se passe : Un pod avec preemptionPolicy: PreemptLowerPriority évince les pods de priorité inférieure même lorsque le cluster aurait pu être mis à l'échelle, provoquant des perturbations.
Pourquoi cela arrive : Par défaut, la préemption est activée et les opérateurs peuvent ne pas réaliser l'impact.
Comment éviter : Pour les charges de travail non critiques, définissez preemptionPolicy: Never pour les empêcher de préempter les autres. Ou utilisez la mise à l'échelle automatique du cluster pour ajouter des nœuds avant la préemption.
Récupération : Changez la preemptionPolicy de la PriorityClass en Never et réappliquez ; les pods évincés peuvent ne pas être restaurés automatiquement, vous devrez peut-être les réordonnancer.
Piège 4 : Ne pas tenir compte des Pod Disruption Budgets (PDBs)
Ce qui se passe : La préemption peut évincer des pods même si cela viole les PDB, mais l'ordonnanceur essaie de l'éviter. Si le PDB est trop strict, les pods de haute priorité peuvent rester en attente.
Pourquoi cela arrive : Les PDB limitent les perturbations volontaires, y compris la préemption, et l'ordonnanceur les respecte dans une certaine mesure.
Comment éviter : Alignez les PDB avec les niveaux de priorité. Par exemple, autorisez une certaine perturbation pour les pods de basse priorité, mais protégez les hautes priorités avec minAvailable.
Récupération : Ajustez le PDB ou autorisez temporairement la perturbation, puis réessayez l'ordonnancement.
Piège 5 : Demandes de ressources non définies
Ce qui se passe : La préemption est basée sur les demandes de ressources, pas sur l'utilisation réelle. Si les pods n'ont pas de demandes définies, l'ordonnanceur ne peut pas déterminer si l'éviction libérera suffisamment de ressources, donc la préemption peut ne pas se produire.
Pourquoi cela arrive : Les développeurs omettent resources.requests en pensant que les limites suffisent.
Comment éviter : Définissez toujours des demandes pour les pods qui peuvent être préemptés ou qui peuvent nécessiter une préemption. Utilisez LimitRange pour appliquer des défauts.
Récupération : Ajoutez des demandes aux spécifications de pod et redéployez.
Modes de défaillance et récupération
Le réglage des PriorityClass peut conduire à une instabilité du cluster s'il n'est pas géré avec soin. Voici des scénarios de défaillance spécifiques et les étapes de récupération.
Scénario 1 : Un pod de haute priorité ne peut pas être ordonnancé
Symptômes : Le pod reste en attente, kubectl describe montre FailedScheduling avec "Insufficient" ressources malgré la préemption activée.
Diagnostic : Vérifiez s'il y a des pods de priorité inférieure sur des nœuds qui sont éligibles. Exécutez :
kubectl get pods -A -o json | jq -r '.items[] | select(.spec.priorityClassName!="" and .spec.priorityClassName!="system-node-critical" and .spec.priorityClassName!="system-cluster-critical") | [.metadata.namespace, .metadata.name, .spec.priorityClassName, .spec.nodeName] | @tsv'
Vérifiez également kubectl get events pour les tentatives de préemption.
Récupération : Supprimez manuellement certains pods de priorité inférieure pour libérer des ressources, ou ajoutez un nouveau nœud. Assurez-vous que les demandes du pod de haute priorité sont exactes.
Scénario 2 : Tempête de préemption
Symptômes : Évictions rapides de nombreux pods, thrashing du cluster.
Diagnostic : Exécutez kubectl get events --field-selector reason=Preempted -w pour voir la préemption continue.
Récupération : Réduisez immédiatement la valeur de priorité de la PriorityClass incriminée ou définissez preemptionPolicy: Never dessus. Mettez à l'échelle les nœuds du cluster si possible. Réappliquez les modifications et surveillez.
Scénario 3 : Pods système préemptés
Symptômes : Des pods système critiques (par exemple, kube-proxy, coredns) sont évincés, provoquant des problèmes de réseau ou de DNS.
Cause : PriorityClass définie par l'utilisateur avec une valeur supérieure aux priorités système (par exemple, > 2000000000) ou globalDefault mal configuré.
Récupération : Supprimez ou modifiez la PriorityClass incriminée pour avoir une valeur inférieure. Les pods système seront réordonnancés automatiquement si leurs contrôleurs fonctionnent. Assurez-vous que les PriorityClasses système ne sont pas modifiées.
Stratégie de retour en arrière
Gardez toujours une sauvegarde des manifestes PriorityClass avant les modifications. Pour revenir en arrière :
kubectl apply -f backup-priorityclass.yaml
Pour les pods, vous devrez peut-être les recréer pour qu'ils prennent en compte le changement de priorité (la suppression d'un pod entraîne sa recréation par son contrôleur).
Liste de vérification opérationnelle
Utilisez cette liste lors du réglage des performances des PriorityClass dans un cluster de production.
- [ ] Enregistrez les PriorityClasses actuelles :
kubectl get priorityclass -o yaml > priorityclasses-backup.yaml - [ ] Identifiez la charge de travail et son niveau de priorité requis. Attribuez un responsable : par exemple, Priya Shah, responsable de l'ingénierie, révise tous les trimestres.
- [ ] Créez une nouvelle PriorityClass avec une valeur de test et
preemptionPolicy: PreemptLowerPriority(ouNeversi approprié). Appliquez-la. - [ ] Déployez un pod de test utilisant la nouvelle PriorityClass dans un namespace non-productif d'abord.
- [ ] Vérifiez l'ordonnancement :
kubectl get pod test-pod -o wideetkubectl describe pod test-podpour les événements. - [ ] Testez la préemption si applicable : créez un pod de priorité inférieure, observez les événements d'éviction.
- [ ] Mesurez la latence d'ordonnancement avant et après en utilisant les horodatages des événements de pod.
- [ ] Mettez à jour la charge de travail de production avec le nouveau
priorityClassNamevia une mise à jour progressive. - [ ] Surveillez le déploiement :
kubectl rollout status deployment/<name>. - [ ] Surveillez les tempêtes de préemption :
kubectl get events --field-selector reason=Preempted -w. - [ ] Validez les demandes de ressources sur tous les pods affectés.
- [ ] Confirmez que les PDB ne bloquent pas la préemption nécessaire.
- [ ] Nettoyez les ressources de test.
- [ ] Documentez le changement dans le livre de bord du cluster.
Partie responsable : le responsable de l'ingénierie de plateforme (ou un SRE désigné) doit approuver les changements de priorité pour les namespaces de production. Cette revue de décision a lieu au moins mensuellement ou après tout incident lié à l'ordonnancement.
Conclusion
Le réglage des PriorityClass Kubernetes consiste à équilibrer la criticité des charges de travail avec la stabilité du cluster. En suivant un processus structuré d'inventaire, de configuration sûre, de vérification et de récupération, vous pouvez améliorer les performances d'ordonnancement sans provoquer de préemption involontaire.
Commencez par l'observation, apportez des modifications incrémentales et ayez toujours un plan de retour en arrière. Les exemples et les listes de vérification de cet article vous donnent une base pratique pour optimiser le comportement des priorités dans votre cluster.