Introduction
Les budgets de perturbation de pods (Pod Disruption Budgets, PDB) sont une protection essentielle de Kubernetes : ils limitent le nombre de pods pouvant être indisponibles simultanément lors de perturbations volontaires telles que les drainages de nœuds, l'autoscaling de cluster ou les mises à jour progressives. Bien configurés, les PDB garantissent la disponibilité de votre application pendant la maintenance. Mal configurés, ils peuvent bloquer les drainages de nœuds, empêcher la progression des déploiements ou échouer silencieusement, laissant vos charges de travail vulnérables.
Cet article s'adresse aux développeurs, ingénieurs DevOps et équipes plateforme qui exploitent des clusters Kubernetes en production. Il passe en revue les erreurs PDB les plus courantes, comment les déboguer avec kubectl, et des correctifs pratiques validés sur Kubernetes 1.28 à 1.30. Vous apprendrez :
- Comment les PDB interagissent avec les évictions et les perturbations volontaires
- Quels champs sont obligatoires et lesquels sont mutuellement exclusifs
- Comment interpréter la sortie de
kubectl get pdbet les événements - Comment récupérer d'un PDB qui bloque la maintenance
- Comment tester le comportement des PDB en toute sécurité avec un cluster local
L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des valeurs de remplacement plutôt que des secrets, vérifier le résultat et documenter la récupération si l'état attendu n'est pas atteint.
Inventaire des versions et de l'environnement
Avant de déboguer un PDB, confirmez la version de votre cluster et la version de l'API PDB utilisée. Les PDB sont stables depuis policy/v1 dans Kubernetes 1.21, mais les clusters plus anciens peuvent encore utiliser policy/v1beta1, qui est dépréciée et supprimée dans 1.25. Vérifiez vos ressources d'API :
kubectl api-resources | grep poddisruptionbudget
Sortie attendue sur un cluster moderne :
poddisruptionbudgets pdb policy/v1 true PodDisruptionBudget
Si vous voyez policy/v1beta1, prévoyez une mise à niveau. La sémantique est identique pour les champs discutés ici, mais les administrateurs de cluster doivent migrer les manifestes vers policy/v1 pour éviter des ruptures futures.
Prérequis pour ce guide :
kubectlconfiguré avec accès à un espace de noms de test- Un cluster en cours d'exécution (kind, minikube ou cloud) avec Kubernetes 1.25+
- Compréhension de base des déploiements, ReplicaSets et opérations sur les nœuds
Commencez par une observation en lecture seule. Ne modifiez jamais un PDB ou ses charges de travail avant de comprendre l'état actuel. Capturez les informations suivantes dans un fichier de notes :
kubectl get pdb -n <namespace> -o wide
kubectl get pods -n <namespace> -o wide
kubectl get events -n <namespace> --sort-by=.lastTimestamp | grep -i pdb
Par exemple, un PDB sain lié à un déploiement avec 3 réplicas pourrait afficher :
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
my-app-pdb 1 N/A 2 5m
Si le déploiement a déjà perdu des pods en raison d'une panne de nœud, ALLOWED DISRUPTIONS peut tomber à 0 ou même afficher un nombre négatif ? Non, le statut du PDB ne devient jamais négatif. Si les pods sains actuels sont inférieurs au budget, ALLOWED DISRUPTIONS devient 0 et les évictions volontaires supplémentaires sont bloquées.
Vérification pratique : Sur un cluster local, créez un déploiement simple et un PDB, puis drainez un nœud pour observer le PDB en action. Utilisez kind ou minikube :
kubectl create deployment web --image=nginx --replicas=3
kubectl apply -f - <<EOF
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: web
EOF
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
Observez la commande de drainage : elle n'évincera qu'un pod à la fois, attendant que les pods de remplacement soient prêts avant d'évincer le suivant.
Gardez le test local petit : appliquez un seul manifeste, inspectez les ressources générées et vérifiez le trafic avant de passer à un équilibreur de charge cloud ou à un contrôleur d'ingress.
Chemin de configuration sûr
Les erreurs de configuration des PDB proviennent souvent d'une mauvaise compréhension des deux champs mutuellement exclusifs : minAvailable et maxUnavailable. Vous devez spécifier exactement l'un d'eux. Si vous définissez les deux, le serveur d'API rejette le manifeste avec :
The PodDisruptionBudget "web-pdb" is invalid: spec: Invalid value: core.PodDisruptionBudgetSpec{...}: minAvailable and maxUnavailable cannot be both set
Si vous omettez les deux, vous verrez :
The PodDisruptionBudget "web-pdb" is invalid: spec: Invalid value: core.PodDisruptionBudgetSpec{...}: minAvailable or maxUnavailable must be specified
Lequel utiliser ?
minAvailableest un nombre absolu ou un pourcentage de pods qui doivent rester disponibles. Exemple :minAvailable: 2signifie qu'au moins 2 pods doivent être sains et prêts à tout moment. Il exprime directement la disponibilité, ce qui facilite le raisonnement sur la capacité du service.maxUnavailableest le nombre maximal de pods pouvant être indisponibles. Exemple :maxUnavailable: 1autorise au plus 1 pod en panne. C'est pratique lorsque vous pensez en termes d'impact de perturbation.
Pour la plupart des charges de travail sans état, minAvailable: 1 est une valeur par défaut sûre si vous avez au moins 2 réplicas. Pour les applications avec état ayant des exigences de quorum (par exemple etcd, bases de données), définissez minAvailable à la taille du quorum.
Voici un manifeste PDB complet et prêt pour la production avec des paramètres raisonnables :
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
namespace: production
spec:
minAvailable: 50%
selector:
matchLabels:
app: api
tier: backend
Supposons que le déploiement a 6 pods. Un minAvailable: 50% signifie que 3 pods doivent toujours être prêts. Le PDB autorise au plus 3 perturbations volontaires à tout moment (en supposant que les 6 soient actuellement sains). Si un pod plante en raison d'un bogue d'application, ne laissant que 5 sains, les perturbations autorisées tombent à 2. Les drainages de nœuds n'évinceront que 2 pods puis se bloqueront jusqu'à ce que le pod en panne récupère ou soit remplacé.
Le sélecteur doit correspondre aux pods. Si le sélecteur du PDB ne correspond à aucun pod, le statut du PDB affiche ALLOWED DISRUPTIONS: 0 même si des pods existent. Par exemple, une faute de frappe courante :
selector:
matchLabels:
app: web # Le déploiement étiquette les pods avec app: frontend
Le PDB n'aura aucun effet et vous pourriez ne pas le remarquer jusqu'à ce qu'une fenêtre de maintenance échoue. Vérifiez toujours :
kubectl get pdb web-pdb -o yaml
Regardez status.currentHealthy et status.desiredHealthy. Si currentHealthy est 0 mais que des pods existent, votre sélecteur est incorrect.
Autre écueil : Les PDB ne s'appliquent pas aux pods nus ni aux pods non contrôlés par un contrôleur de niveau supérieur comme Deployment ou StatefulSet. Ils ne s'appliquent pas non plus aux pods de daemonset. Utilisez des Deployments ou StatefulSets pour les pods que vous souhaitez protéger.
Migration de v1beta1 vers v1 : Si votre cluster utilise encore policy/v1beta1, changez l'apiVersion et assurez-vous que les champs spec sont identiques. La seule différence est la version du groupe d'API. Il n'y a pas de dépréciation de champ au sein des PDB. Testez d'abord dans un environnement de préproduction :
kubectl apply --dry-run=client -f pdb.yaml
kubectl apply -f pdb.yaml
kubectl get pdb
Vérification et diagnostic
Une fois un PDB appliqué, vous devez vérifier qu'il fonctionne comme prévu et déboguer tout problème. La commande principale est :
kubectl get pdb -n <namespace>
Colonnes de sortie :
NAME: nom du PDBMIN AVAILABLE: valeur deminAvailableMAX UNAVAILABLE: valeur demaxUnavailableALLOWED DISRUPTIONS: combien de pods supplémentaires peuvent être perturbés volontairement à ce momentAGE: âge du PDB
Par exemple :
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
zookeeper 2 N/A 1 3d
Cela signifie que 2 pods doivent rester disponibles. Parmi les pods sains actuels, un de plus peut être évincé sans violer le budget.
Pour plus de détails, y compris le sélecteur et le statut :
kubectl describe pdb zookeeper -n <namespace>
Regardez la section Events pour les tentatives d'éviction récentes. Vous pourriez voir des messages comme :
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning EvictionBlocked 10m disruption-controller Cannot evict pod as it would violate the pod's disruption budget.
Si vous voyez EvictionBlocked, ce n'est pas nécessairement une erreur : cela signifie que le PDB fait son travail. Cependant, si vous attendiez une éviction réussie et qu'elle ne l'a pas été, vous devez rechercher pourquoi le PDB pense que le budget serait violé.
Vérifiez le nombre de pods sains actuels :
kubectl get pods -l app=zookeeper -o wide
Si un pod est en CrashLoopBackOff ou Pending, il n'est pas compté comme sain. Par conséquent, le ALLOWED DISRUPTIONS du PDB peut être 0 et aucune éviction supplémentaire ne peut avoir lieu. Dans ce cas, corrigez d'abord le pod en mauvaise santé.
Débogage avec kubectl drain : Lorsqu'un drainage de nœud est bloqué, vous pouvez voir :
error when evicting pods/<pod-name> -n <namespace> (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
Pour résoudre, vous avez quelques options :
- Attendre et augmenter l'échelle : Si l'application peut gérer plus de réplicas, augmentez les réplicas du déploiement pour qu'après éviction, le budget soit toujours satisfait.
kubectl scale deployment zookeeper --replicas=4
Attendez que le nouveau pod soit prêt, puis réessayez le drainage.
- Assouplir temporairement le PDB : Si vous devez absolument évincer plus de pods que permis (par exemple, maintenance d'urgence), vous pouvez patcher le PDB pour un
maxUnavailableplus élevé ou unminAvailableplus bas. Par exemple, définissez temporairementminAvailable: 1:
kubectl patch pdb zookeeper -p '{"spec":{"minAvailable":1}}'
Après la maintenance, revenez à la valeur d'origine. Cela devrait être un dernier recours et nécessiter une approbation de changement.
- Supprimer le PDB : Si le PDB n'est plus nécessaire ou est mal configuré au-delà de toute réparation, supprimez-le :
kubectl delete pdb zookeeper
Cela supprime toute protection. Recréez-le avec la configuration correcte ensuite.
Simuler une perturbation localement : Pour tester le comportement du PDB sans affecter la production, utilisez un outil comme kubectl drain sur un nœud de test, ou utilisez l'API d'éviction directement via un petit script. Voici un extrait Python utilisant le client kubernetes :
from kubernetes import client, config
config.load_kube_config()
v1 = client.PolicyV1Api()
body = client.V1Eviction(metadata=client.V1ObjectMeta(name="my-pod", namespace="default"))
try:
v1.create_namespaced_pod_eviction("my-pod", "default", body)
print("Eviction succeeded")
except client.exceptions.ApiException as e:
print(f"Eviction failed: {e}")
Si le PDB bloque l'éviction, vous obtiendrez une erreur 429 Too Many Requests du serveur d'API. Cela confirme que le PDB fonctionne.
Erreur de diagnostic courante : Supposer que le PDB bloque les évictions de l'API d'éviction mais pas de kubectl delete pod. En fait, kubectl delete pod est une suppression directe et contourne le PDB. Les PDB ne s'appliquent qu'aux perturbations volontaires initiées via l'API d'éviction, utilisée par kubectl drain, l'autoscaler de cluster et certains opérateurs. Si vous supprimez un pod manuellement, le PDB ne l'arrêtera pas. C'est voulu : le PDB protège contre les pannes involontaires et la maintenance, pas contre les suppressions administratives. Pour imposer la disponibilité même en cas de suppression manuelle, vous avez besoin de politiques supplémentaires comme Kyverno ou OPA Gatekeeper.
Modes de défaillance et récupération
Examinons trois modes de défaillance courants et comment s'en remettre.
Mode de défaillance 1 : Le PDB avec zéro perturbation autorisée bloque toute maintenance
Symptôme : kubectl get pdb affiche ALLOWED DISRUPTIONS: 0, et les drainages de nœuds sont bloqués. kubectl describe pdb montre des événements EvictionBlocked pour chaque pod.
Cause : Le minAvailable ou maxUnavailable du PDB est réglé de manière trop stricte pour le nombre de réplicas actuel. Par exemple, un déploiement avec 3 réplicas et un PDB minAvailable: 3 signifie que les 3 doivent être opérationnels en permanence. Si un pod tombe en panne, les perturbations autorisées deviennent 0 et aucune éviction ne peut avoir lieu. C'est souvent une mauvaise configuration : vous vouliez minAvailable: 2 mais avez mis 3.
Récupération :
- Identifiez le PDB mal configuré :
kubectl get pdb -A
- Vérifiez le nombre de réplicas du déploiement et la spécification du PDB :
kubectl get deploy <deployment-name> -o yaml
kubectl get pdb <pdb-name> -o yaml
- Corrigez le PDB avec une valeur raisonnable. Si vous avez 3 réplicas,
minAvailable: 2est typique :
kubectl patch pdb <pdb-name> --type merge -p '{"spec":{"minAvailable":2}}'
- Vérifiez que les perturbations autorisées sont maintenant > 0 :
kubectl get pdb <pdb-name>
Mode de défaillance 2 : Le sélecteur du PDB ne correspond à aucun pod
Symptôme : Le PDB existe, mais ALLOWED DISRUPTIONS est 0 même si des pods sont en cours d'exécution. Aucun événement de blocage d'éviction n'apparaît.
Cause : Les étiquettes du selector ne correspondent pas aux étiquettes des pods. Par exemple, le déploiement étiquette les pods avec app: frontend, mais le sélecteur du PDB recherche app: web.
Récupération :
- Comparez les étiquettes des pods et le sélecteur du PDB :
kubectl get pods --show-labels
kubectl get pdb <pdb-name> -o jsonpath='{.spec.selector}'
- Mettez à jour le sélecteur du PDB pour qu'il corresponde. Cela nécessite souvent de modifier le PDB car le
selectorest immuable après la création. Supprimez et recréez :
kubectl delete pdb <pdb-name>
kubectl apply -f corrected-pdb.yaml
- Confirmez que
currentHealthydans le statut du PDB est maintenant > 0 :
kubectl get pdb <pdb-name> -o yaml
Mode de défaillance 3 : Le PDB bloque la mise à jour progressive ou le drainage de nœud pendant une panne
Symptôme : Lors d'un incident, vous devez drainer un nœud immédiatement, mais le PDB empêche l'éviction, causant des retards. Vous pourriez voir des erreurs comme :
error when evicting pods/... : Cannot evict pod as it would violate the pod's disruption budget.
Cause : Le PDB remplit son rôle, mais l'urgence opérationnelle exige une dérogation temporaire.
Récupération (avec prudence) :
- Documentez l'incident et obtenez l'approbation pour assouplir le PDB.
- Ajustez temporairement le PDB pour autoriser plus de perturbations. Par exemple, définissez
minAvailable: 0(désactivez effectivement la protection) ou supprimez le PDB.
kubectl patch pdb <pdb-name> --type merge -p '{"spec":{"minAvailable":0}}'
# ou
kubectl delete pdb <pdb-name>
- Effectuez le drainage/la maintenance.
- Restaurez immédiatement le PDB à sa configuration d'origine.
- Examinez pourquoi l'urgence s'est produite et si le réglage du PDB était trop restrictif pour les opérations réelles.
Prévention : Définissez minAvailable de manière appropriée pour vos objectifs de disponibilité. Testez les procédures de drainage en préproduction. Utilisez maxUnavailable au lieu de minAvailable si vous préférez penser en termes de nombre de pods pouvant être en panne à la fois. Pour un service à 3 réplicas, maxUnavailable: 1 et minAvailable: 2 sont équivalents.
Liste de contrôle opérationnelle
Utilisez cette liste de contrôle pour vous assurer que vos PDB sont correctement déployés et maintenus.
Liste de contrôle avant déploiement du PDB
- [ ] Confirmez que la version du cluster prend en charge
policy/v1(Kubernetes 1.21+). - [ ] Identifiez la charge de travail (Deployment, StatefulSet, Operator) et ses étiquettes.
- [ ] Décidez entre
minAvailableetmaxUnavailableen fonction du SLO de disponibilité. - [ ] Rédigez le manifeste du PDB avec un sélecteur correspondant aux étiquettes du modèle de pod de la charge de travail.
- [ ] Définissez une valeur raisonnable : pour N réplicas,
minAvailable: N-1oumaxUnavailable: 1pour les applications sans état ; pour les applications avec état, utilisez la taille du quorum. - [ ] Appliquez d'abord avec un essai à blanc :
kubectl apply -f pdb.yaml --dry-run=client
- [ ] Appliquez le PDB et vérifiez le statut :
kubectl apply -f pdb.yaml
kubectl get pdb
- [ ] Vérifiez que
ALLOWED DISRUPTIONSest supérieur à 0 lorsque tous les pods sont sains.
Audit périodique du PDB
- [ ] Listez tous les PDB du cluster :
kubectl get pdb -A
- [ ] Pour chaque PDB, vérifiez que le sélecteur correspond aux pods prévus :
kubectl get pods -l <selector> -n <namespace>
- [ ] Confirmez que
currentHealthydans le statut du PDB est égal au nombre de pods prêts désirés (ou dans une plage acceptable). - [ ] Vérifiez si un PDB bloque la maintenance : vérifiez
ALLOWED DISRUPTIONSet les journaux de drainage des nœuds. - [ ] Supprimez les PDB obsolètes qui n'ont plus de charges de travail correspondantes.
Aide-mémoire des commandes de dépannage
| Tâche | Commande |
|---|---|
| Lister les PDB avec statut | kubectl get pdb -n <namespace> |
| Décrire un PDB et ses événements | kubectl describe pdb <name> -n <namespace> |
| Voir le YAML du PDB | kubectl get pdb <name> -n <namespace> -o yaml |
| Vérifier les pods correspondant au sélecteur | kubectl get pods -l <label-key>=<value> -n <namespace> |
| Simuler une éviction (Python) | Utilisez l'extrait d'API d'éviction ci-dessus |
| Désactiver temporairement le PDB | kubectl patch pdb <name> --type merge -p '{"spec":{"minAvailable":0}}' |
| Supprimer le PDB | kubectl delete pdb <name> -n <namespace> |
| Observer les événements de drainage | kubectl drain <node> --ignore-daemonsets --delete-emptydir-data et observez |
Conclusion
Les budgets de perturbation de pods sont un mécanisme petit mais puissant pour garder vos applications disponibles pendant les opérations volontaires sur le cluster. Les erreurs les plus courantes — sélecteurs mal configurés, objectifs de disponibilité impossibles et mauvaise version d'API — peuvent être évitées par une revue attentive des manifestes et des audits réguliers.
Rappelez-vous de ces pratiques clés :
- Spécifiez toujours soit
minAvailablesoitmaxUnavailable, pas les deux. - Assurez-vous que le sélecteur du PDB correspond exactement aux étiquettes des pods contrôlés par votre Deployment ou StatefulSet.
- Vérifiez régulièrement
kubectl get pdb; une chute soudaine deALLOWED DISRUPTIONSà 0 indique un problème sous-jacent. - Traitez l'assouplissement du PDB comme un dernier recours lors d'incidents ; documentez et revenez rapidement.
- Testez le comportement du PDB dans un cluster de préproduction en utilisant
kubectl drainou l'API d'éviction.
En suivant les étapes de vérification et de récupération de ce guide, vous pouvez maintenir un environnement Kubernetes résilient où les fenêtres de maintenance se déroulent sans heurts et la disponibilité des applications reste dans les SLO.
Comme prochaine étape, choisissez une vérification à faible risque dans la liste de contrôle opérationnelle pour un PDB de votre cluster, enregistrez l'état actuel, exécutez la vérification documentée et comparez le résultat avec le signal attendu. Ensuite, examinez les dépendances telles que le nombre de réplicas du déploiement et la santé des nœuds.