Aller au contenu
Conteneurs & Orchestration medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Préparer une maintenance de cluster Kubernetes

15 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 peut se permettre de rebooter directement. Sur Kubernetes, un nœud héberge potentiellement des dizaines de pods qui servent du trafic en production. Un redémarrage brutal provoque :

  • 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.

É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.34.3
ks-worker1 Ready,SchedulingDisabled <none> 42h v1.34.3
ks-worker2 Ready <none> 42h v1.34.3

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.

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.

La commande kubectl drain 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)
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.
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).

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).

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 (ajoutez --force si oui).

  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 être Ready et les ressources CPU/mémoire doivent revenir à des niveaux normaux au fur et à mesure que le scheduler lui assigne de nouveaux pods.

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.

SymptômeCause probableSolution
drain bloqué indéfinimentPDB avec ALLOWED DISRUPTIONS: 0Vérifier les réplicas et les ressources sur les autres nœuds
cannot delete Pods not managed by...Pod 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

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn