Aller au contenu
English
Conteneurs & Orchestration medium

Préparer une maintenance de cluster Kubernetes

35 min de lecture

logo kubernetes

Pour intervenir sur un nœud Kubernetes sans couper le service, suivez toujours le même workflow : cordondrain → intervention → uncordon. Ce guide détaille chaque étape, explique comment les PodDisruptionBudgets protègent vos applications pendant l'opération, et couvre les cas particuliers (DaemonSets, pods orphelins, volumes locaux).

  • Appliquer le workflow complet de maintenance d'un nœud Kubernetes
  • Comprendre la différence entre cordon (bloquer le scheduling) et drain (évacuer les pods)
  • Configurer un PodDisruptionBudget pour protéger vos applications pendant le drain
  • Gérer les cas particuliers : DaemonSets, pods sans contrôleur, données locales (emptyDir)
  • Vérifier que le service est restauré après la maintenance

Sur un serveur classique, on redémarre directement. Sur Kubernetes, un nœud héberge potentiellement des dizaines de Pods qui servent du trafic en production, et un redémarrage brutal a trois conséquences immédiates :

  • Des coupures de service si les pods n'ont pas de réplicas sur d'autres nœuds
  • Des pertes de données si les pods utilisent des volumes locaux (emptyDir)
  • Des alertes inutiles dans le monitoring

Le workflow cordon → drain → uncordon résout ces trois problèmes en évacuant proprement les pods avant l'intervention.

Quatre étapes, toujours les mêmes, et leur ordre n'est pas négociable : on empêche l'arrivée de nouveaux pods, puis on évacue ceux qui sont là, puis on intervient, puis on rouvre. Sauter la première revient à voir de nouveaux pods atterrir sur le nœud pendant qu'on l'évacue.

ÉtapeCommandeCe qui se passe
1. Bloquer le schedulingkubectl cordon <noeud>Le nœud est marqué SchedulingDisabled, plus aucun nouveau pod n'y sera planifié
2. Évacuer les podskubectl drain <noeud>Les pods sont évincés via l'API d'éviction, en respectant les PDB
3. Intervenir(reboot, mise à jour, réparation)Le nœud est vide, vous pouvez intervenir en sécurité
4. Remettre en servicekubectl uncordon <noeud>Le nœud redevient Ready et accepte de nouveaux pods

La commande kubectl cordon marque le nœud comme SchedulingDisabled. Les pods déjà présents continuent de tourner, mais le scheduler ne placera plus de nouveaux pods sur ce nœud. Les DaemonSets sont une exception : leurs pods ignorent l'état SchedulingDisabled et continuent de fonctionner normalement sur le nœud.

Fenêtre de terminal
kubectl cordon <nom-du-noeud>

Vérification :

Fenêtre de terminal
kubectl get nodes
NAME STATUS ROLES AGE VERSION
ks-cp1 Ready control-plane 42h v1.37.0
ks-worker1 Ready,SchedulingDisabled <none> 42h v1.37.0
ks-worker2 Ready <none> 42h v1.37.0

Le nœud ks-worker1 affiche SchedulingDisabled dans la colonne STATUS.

Comprendre les PodDisruptionBudgets (PDB) avant le drain

Section intitulée « Comprendre les PodDisruptionBudgets (PDB) avant le drain »

Avant de drainer un nœud, vérifiez les PodDisruptionBudgets en place. Un PDB définit le nombre minimum de pods d'une application qui doivent rester disponibles pendant une disruption volontaire (comme un drain).

Un PDB protège une application en disant à Kubernetes : "ne supprime pas plus de X pods à la fois". Pendant un kubectl drain, l'API d'éviction respecte ces budgets et bloque le drain si l'éviction violerait le PDB.

Exemple : un Deployment avec 3 réplicas et un PDB minAvailable: 2 signifie que le drain ne pourra évacuer qu'un seul pod de cette application à la fois. Les deux autres doivent rester disponibles.

Un PDB se déclare à côté de l'application qu'il protège, jamais sur le nœud : il exprime une exigence de disponibilité, pas une contrainte d'infrastructure. Deux champs s'excluent, minAvailable et maxUnavailable : choisissez celui qui exprime le plus naturellement votre besoin.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: mon-app-pdb
namespace: default
spec:
minAvailable: 2
selector:
matchLabels:
app: mon-app

Les deux options principales :

ChampSignificationExemple
minAvailableNombre minimum (ou %) de pods qui doivent rester disponibles2 ou "50%"
maxUnavailableNombre maximum (ou %) de pods qui peuvent être indisponibles1 ou "25%"
Fenêtre de terminal
kubectl get pdb -A
NAMESPACE NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
default mon-app-pdb 2 N/A 1 5m

La colonne ALLOWED DISRUPTIONS indique combien de pods peuvent encore être évincés sans violer le budget. Si elle affiche 0, le drain sera bloqué pour cette application.

Un détail de diagnostic qui coûte cher quand on l'ignore : le message d'erreur ne nomme jamais le PDB. Un drain empêché par un budget ne dit pas « bloqué par un PodDisruptionBudget », il se contente d'attendre. Avec --timeout, vous obtenez ceci, qui parle du délai et pas de la cause :

error when evicting pods/"app-69ccd78fc8-qgtmr" -n "production":
global timeout reached: 25s

Sans --timeout, il n'y a même pas ce message : la commande attend indéfiniment. Le réflexe est donc de vérifier kubectl get pdb -A avant de lancer le drain, et non après avoir attendu dix minutes.

C'est l'étape qui déplace réellement la charge, et la seule qui peut provoquer une interruption si elle est mal préparée. kubectl drain ne supprime pas les pods brutalement : il passe par l'API d'éviction, celle-là même que les PodDisruptionBudgets savent refuser. C'est ce qui distingue un drain d'un kubectl delete pod en masse, et c'est ce qui le rend sûr.

La commande combine deux actions :

  1. cordon le nœud (si pas déjà fait)
  2. Évacue tous les pods via l'API d'éviction (qui respecte les PDB)

Deux options reviennent si systématiquement qu'elles font partie de la commande. Sans elles, drain refuse de commencer et renvoie la liste de ce qui le gêne : c'est d'ailleurs une bonne façon de découvrir ce que le nœud héberge.

Fenêtre de terminal
kubectl drain <nom-du-noeud> --ignore-daemonsets --delete-emptydir-data

Les deux flags les plus courants :

FlagPourquoi
--ignore-daemonsetsLes pods DaemonSet ne peuvent pas être déplacés (ils existent sur chaque nœud par définition). Sans ce flag, drain refuse de continuer.
--delete-emptydir-dataAutorise la suppression de pods qui utilisent emptyDir (volumes locaux éphémères). À utiliser uniquement si vous acceptez la perte de ces données.

Deux de ces options méritent d'être posées par réflexe sur un cluster de production. --dry-run=client montre ce qui serait évacué sans rien toucher, et --timeout évite d'attendre indéfiniment devant un drain que rien ne débloquera.

FlagUsage
--timeout=300sDurée maximale d'attente (défaut : infini)
--grace-period=30Durée de terminaison gracieuse par pod
--forceSupprime les pods sans contrôleur (orphelins)
--dry-run=clientSimule le drain sans rien exécuter
--pod-selector=app=XNe draine que les pods correspondant au sélecteur

Commencez toujours par un dry-run pour voir ce qui sera impacté :

Fenêtre de terminal
kubectl drain <nom-du-noeud> --ignore-daemonsets --delete-emptydir-data --dry-run=client

Cette commande liste les pods qui seraient évacués sans rien modifier.

Fenêtre de terminal
kubectl drain <nom-du-noeud> --ignore-daemonsets --delete-emptydir-data

Résultat attendu :

node/ks-worker1 cordoned
evicting pod default/mon-app-xyz-abc
evicting pod kube-system/coredns-5d78c9869d-abc
pod/mon-app-xyz-abc evicted
pod/coredns-5d78c9869d-abc evicted
node/ks-worker1 drained

Kubernetes replanifie automatiquement les pods évincés sur les nœuds restants (si les ressources le permettent).

Avant de drainer, assurez-vous que les autres nœuds peuvent accueillir ce que celui-ci héberge. Le drain réussira de toute façon, puisque son travail est d'évincer ; ce sont les pods évincés qui resteront en Pending, et vous aurez alors une panne au lieu d'une maintenance.

Pods sans contrôleur (orphelins) : si un pod n'est géré par aucun Deployment, ReplicaSet, StatefulSet, DaemonSet ou Job, drain refuse de le supprimer car il ne sera pas recréé. Utilisez --force en dernier recours (le pod sera définitivement supprimé).

Pods StatefulSet : ils sont supprimés un à un (pas en parallèle) et recréés dans l'ordre par le contrôleur StatefulSet. Vérifiez que les PVC (PersistentVolumeClaims) sont accessibles depuis les autres nœuds.

Pods avec emptyDir : les données dans emptyDir sont perdues quand le pod est évincé. Si ces données sont importantes, sauvegardez-les avant le drain ou migrez vers un PersistentVolume.

Pods avec stockage local attaché au nœud (hostPath, local PV) : ces pods sont liés à un nœud précis. Après éviction, le scheduler ne pourra pas les replanifier sur un autre nœud (le volume n'y est pas accessible). Pour ces workloads, prévoyez soit un retour sur le même nœud après maintenance, soit une migration vers un PersistentVolume réseau (NFS, Ceph, cloud provider).

Le nœud est maintenant vide (sauf les DaemonSets). Vous pouvez :

  • Redémarrer le nœud (sudo reboot)
  • Mettre à jour le système (apt upgrade, dnf update)
  • Mettre à jour le kubelet et les composants Kubernetes
  • Réparer un problème matériel ou de disque
  • Changer la configuration du kubelet

Pendant l'intervention, vérifiez que les pods évincés sont bien replanifiés sur les autres nœuds :

Fenêtre de terminal
kubectl get pods -A -o wide | grep -v Running

Si des pods sont en Pending, c'est que les nœuds restants manquent de ressources.

Étape 4 : remettre le nœud en service avec uncordon

Section intitulée « Étape 4 : remettre le nœud en service avec uncordon »

Après l'intervention, remettez le nœud en service :

Fenêtre de terminal
kubectl uncordon <nom-du-noeud>

Vérification :

Fenêtre de terminal
kubectl get nodes

Le nœud doit afficher Ready (sans SchedulingDisabled).

Un uncordon rouvre le nœud aux prochains placements, il ne rapatrie personne. Les pods évincés tournent désormais ailleurs et y resteront jusqu'à leur prochain redémarrage. Si la répartition vous importe, c'est au rééquilibrage qu'il faut penser, pas au uncordon.

Voici le workflow complet pour une maintenance du nœud ks-worker1 :

  1. Vérifier l'état initial du cluster

    Fenêtre de terminal
    kubectl get nodes
    kubectl get pods -A -o wide --field-selector spec.nodeName=ks-worker1

    Notez les pods présents sur le nœud pour vérifier ensuite qu'ils ont bien été replanifiés.

  2. Vérifier les PDB existants

    Fenêtre de terminal
    kubectl get pdb -A

    Si ALLOWED DISRUPTIONS est à 0 pour une application, le drain sera bloqué. Assurez-vous que les réplicas sont suffisants.

  3. Simuler le drain

    Fenêtre de terminal
    kubectl drain ks-worker1 --ignore-daemonsets --delete-emptydir-data --dry-run=client

    Vérifiez la liste des Pods qui seront évincés. Si un Pod sans contrôleur apparaît, décidez s'il est acceptable de le perdre : personne ne le recréera, et c'est --force qui l'assume.

  4. Exécuter le drain

    Fenêtre de terminal
    kubectl drain ks-worker1 --ignore-daemonsets --delete-emptydir-data

    Attendez que tous les pods soient évincés. Si le drain bloque, vérifiez les PDB et les ressources sur les autres nœuds.

  5. Vérifier que les pods sont replanifiés

    Fenêtre de terminal
    kubectl get pods -A -o wide | grep -v Running

    Tous les pods doivent être Running sur d'autres nœuds (sauf ceux en cours de démarrage).

  6. Intervenir sur le nœud

    Effectuez la maintenance prévue (reboot, mise à jour, réparation).

  7. Remettre le nœud en service

    Fenêtre de terminal
    kubectl uncordon ks-worker1
  8. Vérifier le retour à la normale

    Fenêtre de terminal
    kubectl get nodes
    kubectl top nodes

    Le nœud doit repasser Ready, et sa consommation CPU et mémoire doit remonter progressivement à mesure que le scheduler lui assigne de nouveaux Pods. Une consommation qui reste plate signale un nœud encore cordonné.

Kubernetes distingue deux types de disruptions :

TypeExemplesProtégé par les PDB ?
Volontairekubectl drain, suppression d'un Deployment, mise à jour rollingOui
InvolontairePanne matérielle, kernel panic, nœud qui disparaît du réseauNon (mais comptabilisé dans le budget)

Les PDB ne protègent que contre les disruptions volontaires. Une panne matérielle évincera les pods sans consulter les PDB. Cependant, les disruptions involontaires comptent quand même dans le budget disponible : si un pod tombe à cause d'une panne, ALLOWED DISRUPTIONS diminue, ce qui peut bloquer un drain ultérieur. C'est pourquoi il est important de combiner PDB avec des réplicas suffisants et de l'anti-affinité pour répartir les pods sur plusieurs nœuds.

La plupart de ces symptômes se produisent pendant l'opération, au pire moment. Les lire une fois à froid vaut mieux que de les découvrir un soir de maintenance : trois d'entre eux se règlent par un flag qu'il suffisait d'ajouter.

SymptômeCause probableSolution
drain bloqué indéfiniment, ou global timeout reachedPDB avec ALLOWED DISRUPTIONS: 0Vérifier les réplicas et les ressources sur les autres nœuds
cannot delete Pods that declare no controllerPod orphelin (sans contrôleur)Ajouter --force si le pod peut être perdu
cannot delete DaemonSet-managed PodsDaemonSet détectéAjouter --ignore-daemonsets
cannot delete Pods with local storagePod avec emptyDirAjouter --delete-emptydir-data (les données seront perdues)
Pods en Pending après drainPas assez de ressources sur les autres nœudsAjouter un nœud ou réduire les requests
Nœud reste SchedulingDisabled après uncordonuncordon pas exécuté ou erreurRelancer kubectl uncordon <noeud>
PVC inaccessible après évictionVolume local (hostPath/local PV)Replanifier le pod sur le même nœud ou migrer vers un PV réseau
  • Le workflow est toujours le même : cordondrain → intervention → uncordon. Ne sautez jamais le drain pour gagner du temps
  • kubectl drain utilise l'API d'éviction qui respecte les PodDisruptionBudgets, c'est ce qui protège vos applications
  • --ignore-daemonsets est souvent nécessaire, car drain refuse d'évacuer les pods DaemonSet. --delete-emptydir-data ne doit être utilisé que si vous acceptez explicitement la perte des données stockées dans emptyDir
  • Faites toujours un --dry-run=client avant le drain réel pour voir quels pods seront impactés
  • Les pods évincés ne reviennent pas automatiquement sur le nœud après uncordon, seuls les nouveaux pods ou ceux en Pending y seront planifiés
  • Un PDB avec minAvailable: 1 sur un Deployment à 1 réplica bloquera le drain indéfiniment, assurez-vous que vos applications critiques ont au moins 2 réplicas
  • Vérifiez les ressources sur les autres nœuds avant de drainer : si les pods ne peuvent pas être replanifiés, ils resteront en Pending

Sept questions sur ce qui se passe vraiment pendant une maintenance : ce qu'un cordon ne fait pas, pourquoi un drain reste muet quand un budget le bloque, et ce qu'un uncordon ne rapatrie pas.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

7 questions
5 min.
80% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn