## 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 :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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` :

```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 :

```bash
kubectl apply -f test-priority.yaml
```

Vérifiez :

```bash
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é :

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-priority-pod
spec:
  priorityClassName: test-priority
  containers:
  - name: nginx
    image: nginx:latest
```

Appliquez et observez l'ordonnancement :

```bash
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 :

```bash
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.

```yaml
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.

```yaml
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 :

```bash
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 :

```bash
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 :

```bash
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 :

```yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: api-high
value: 5000
preemptionPolicy: PreemptLowerPriority
```

Appliquez-la et mettez à jour le déploiement :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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> --previous` aide si le pod a planté après l'ordonnancement.
- `kubectl get events --sort-by=.metadata.creationTimestamp` donne un flux d'événements à l'échelle du cluster pour les décisions d'ordonnancement.
- `kubectl get nodes -o wide` montre la capacité des nœuds et les ressources allouables.
- `kubectl top nodes` et `kubectl top pods -A` ré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 :

```bash
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é :

```bash
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 :

```bash
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 :

```bash
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` (ou `Never` si 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 wide` et `kubectl describe pod test-pod` pour 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 `priorityClassName` via 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.