Mise à jour d’un cluster Kubernetes

Dans mon laboratoire local, cela fait plus d’un an qu’un cluster Kubernetes de test fonctionne sur des machines virtuelles. Tout ce temps, il a servi de bac à sable pour tester les configurations en toute sécurité avant de les déployer en production. Depuis, le cluster est un peu resté bloqué dans le passé : il fonctionne toujours sous la version v1.31, ce qui est considéré comme obsolète (Legacy) et privé de support officiel face aux versions actuelles, la lignée v1.35 étant déjà disponible.

Comme l’environnement de travail approche lui aussi des dates limites de mise à jour, c’est le moment idéal pour tester un cycle complet de mise à niveau de Kubernetes dans des conditions domestiques sécurisées. La procédure de mise à jour via l’utilitaire kubeadm suit une logique stricte. Pour que tout se passe sans douleur et sans casser le cluster, il suffit de respecter rigoureusement deux règles fondamentales :
La séquence des versions mineures. Kubernetes ne pardonne pas les sauts de version. Essayer de passer directement de la 1.31 à la 1.33 va casser le cluster à coup sûr. On avance étape par étape : 1.31 → 1.32 → 1.33, et ainsi de suite.
– La hiérarchie des composants (le Control Plane en premier). On commence par mettre à jour complètement le nœud Master (k8sm) : l’API server, le scheduler et la base de données etcd. Une fois que le « cerveau » du cluster est à jour, on s’occupe des nœuds Workers, strictement l’un après l’autre.

Évidemment, mettre à jour un cluster de production à haute charge avec des centaines de pods sous un trafic réel est un art d’administration système à part entière avec son lot de pièges. Mais aujourd’hui, nous allons analyser le processus de base classique.

Alors, on se sert un café ou un thé bien fort, on ouvre les terminaux et c’est parti !

Étape 0. Préparation : Création d’une copie de sauvegarde

Exécuté sur le Master k8sm avant le début de tout travail

Bien que cela puisse sembler non critique sur un cluster de test, la création d’une sauvegarde de la base de données du cluster (etcd) avant une mise à jour est une règle d’or et une habitude obligatoire pour les environnements de Production.
Étant donné qu’etcd est déployé comme un pod statique (static pod) isolé et non comme un service système de l’OS, l’utilitaire de gestion etcdctl n’est pas installé par défaut sur le système.

1. Installation du client etcd :
sudo apt-get install -y etcd-client

Cette commande installe l’utilitaire nécessaire pour interagir avec la base de données du cluster directement depuis la ligne de commande du Master.
Si le client etcd n’est pas disponible pour une raison ou une autre dans votre version, il est possible d’utiliser le binaire de Kubernetes

ETCD_VER=v3.5.16
curl -L https://github.com/etcd-io/etcd/releases/download/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz | tar xz
sudo mv etcd-v*/etcdctl /usr/local/bin/
2.Création d’une copie de sauvegarde (Snapshot) :
sudo ETCDCTL_API=3 etcdctl snapshot save /tmp/etcd-backup-$(date +%F).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Cette commande se connecte à l’instance locale d’etcd, en utilisant les certificats système de Kubernetes pour l’autorisation, et crée un instantané complet de l’état actuel du cluster.
Le fichier de sauvegarde sera enregistré dans le dossier /tmp/ avec l’indication de la date actuelle (par exemple, /tmp/etcd-backup-2026-06-18.db). En cas de panne critique lors de la mise à jour, ce fichier permettra de restaurer complètement le Control Plane.

3. Vérification de l’état initial du cluster avant le début des travaux :
kubectl get nodes

 

Étape 1. Master : mise à jour du dépôt

Exécuté uniquement sur k8sm

sudo sed -i 's/v1.31/v1.32/g' /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
apt-cache madison kubeadm

Nous trouvons la version la plus récente pour la 1.32 (par exemple 1.32.13-1.1). Cette version sera à remplacer à l’étape suivante à la place de ci-dessous.

Si apt-cache madison kubeadm | grep 1.32 ne montre rien, cela signifie que le fichier kubernetes.list n’a pas encore été modifié ou que apt-get update n’a pas été exécuté après la modification. Il faut vérifier le contenu du fichier :

cat /etc/apt/sources.list.d/kubernetes.list

 

Étape 2. Master : mise à jour du Control Plane

Exécuté uniquement sur k8sm

1. Mise à jour de kubeadm :
sudo apt-mark unhold kubeadm
sudo apt-get install -y kubeadm=<version>
sudo apt-mark hold kubeadm

Dans mon cas

sudo apt-mark unhold kubeadm
sudo apt-get install -y kubeadm=1.32.13-1.1
sudo apt-mark hold kubeadm
2. Vérification du plan de mise à jour :
sudo kubeadm upgrade plan

Cette commande effectue les vérifications préalables (pre-flight checks). Elle n’apporte aucune modification au cluster, mais vérifie l’état des certificats, la compatibilité des configurations et montre quels composants système spécifiques (CoreDNS, kube-proxy, etc.) seront mis à jour. La commande affichera beaucoup de texte, mais la partie la plus importante est celle-ci :

3. Application de la mise à jour du Control Plane :

Si la vérification a réussi, nous exécutons la mise à jour

sudo kubeadm upgrade apply v1.32.13

Notez que la version est indiquée ici avec le préfixe v et sans le suffixe du paquet (par exemple, v1.32.13, et non 1.32.13-1.1), exactement comme cela a été proposé à l’étape précédente lors de la vérification du plan de mise à jour. C’est une étape clé de la mise à niveau : le processus remplace automatiquement les pods statiques des composants principaux du cluster (API server, controller-manager, scheduler et la base de données etcd) par les nouvelles versions.

L’utilitaire vous demandera une confirmation avant de lancer le processus. Si tout se passe bien, vous verrez s’afficher le message SUCCESS :

4. Vidange du nœud Master (Drain) :
kubectl drain k8sm --ignore-daemonsets --delete-emptydir-data

Avant de mettre à jour le démon système (kubelet), le nœud doit être préparé pour la maintenance en « expulsant » ses charges de travail en toute sécurité.
Le drapeau --ignore-daemonsets permet d’ignorer les composants système (par exemple, les plug-ins réseau) qui sont gérés via DaemonSet.
Le drapeau --delete-emptydir-data est nécessaire pour éviter de bloquer le processus si le nœud contient des pods avec des volumes locaux temporaires (emptyDir).

5. Mise à jour de kubelet et kubectl :
sudo apt-mark unhold kubelet kubectl
sudo apt-get install -y kubelet=1.32.13-1.1 kubectl=1.32.13-1.1
sudo apt-mark hold kubelet kubectl

D’abord, nous levons le blocage des paquets (unhold), puis nous installons leurs nouvelles versions et nous les figeons à nouveau (hold). C’est une pratique obligatoire qui garantit que le gestionnaire de paquets du système, apt, ne mettra pas à jour ces composants automatiquement par accident à l’avenir, ce qui pourrait compromettre la stabilité du cluster.

6. Redémarrage de kubelet :
sudo systemctl daemon-reload
sudo systemctl restart kubelet

Après l’installation du nouveau fichier binaire kubelet, il est nécessaire de recharger la configuration du système d’initialisation systemd et de redémarrer le service lui-même pour que les modifications prennent effet.

7. Retour du Master en service (Uncordon) :
kubectl uncordon k8sm

Cette commande supprime le statut SchedulingDisabled du nœud, permettant ainsi au cluster de planifier et de lancer à nouveau des pods sur celui-ci.

Vérification du résultat :
kubectl get nodes

Le nœud k8sm doit avoir le statut Ready et afficher la nouvelle version v1.32.13. Les nœuds Workers (k8sw1, k8sw2) resteront pour l’instant sur l’ancienne version v1.31.8. C’est le comportement attendu, car la colonne VERSION de cette sortie affiche la version de kubelet de chaque nœud spécifique, et les nœuds Workers seront mis à jour lors de l’étape suivante.

 

Étape 3. Nœuds Workers

Exécuté l’un après l’autre : dans mon cas, d’abord k8sw1, puis k8sw2

Attention : Répétez les étapes ci-dessous pour chaque nœud Worker séparément. Il est extrêmement important de ne pas mettre à jour plusieurs Workers en même temps, afin d’éviter que vos applications ne se retrouvent sans aucune réplique active, ce qui provoquerait des interruptions de service.

3.1. Vidange du nœud Worker (Drain) :

Exécuté sur le Master k8sm

kubectl drain k8sw1 --ignore-daemonsets --force --delete-emptydir-data

Cette commande transfère en toute sécurité toutes les charges de travail (pods) de k8sw1 vers d’autres nœuds disponibles.

Le drapeau --force permet de supprimer de force les pods qui ont été lancés directement sur le nœud, sans contrôleurs (Deployment/ReplicaSet).
Le drapeau --delete-emptydir-data est nécessaire pour que les pods utilisant des volumes locaux temporaires (emptyDir) ne bloquent pas le processus d’expulsion automatique en attendant une confirmation manuelle.

3.2. Mise à jour des dépôts :

Exécuté via SSH directement sur le Worker k8sw1

sudo sed -i 's/v1.31/v1.32/g' /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update

Comme sur le Master, il est nécessaire de basculer le gestionnaire de paquets du worker vers le dépôt de la branche cible (v1.32) et de mettre à jour l’index local des paquets.

3.3. Mise à jour de kubeadm :

Exécuté sur le Worker k8sw1

sudo apt-mark unhold kubeadm
sudo apt-get install -y kubeadm=1.32.13-1.1
sudo apt-mark hold kubeadm

La version actuelle de l’utilitaire kubeadm est installée, laquelle gérera le processus de mise à jour de la configuration du nœud lui-même.

3.4. Mise à jour de la configuration du nœud :

Exécuté sur le Worker k8sw1

sudo kubeadm upgrade node

Cette commande applique les mises à jour locales au nœud Worker. Contrairement au Master, elle ne met pas à jour les composants du Control Plane, mais aligne simplement la configuration locale de kubelet avec les exigences de la nouvelle version du cluster.

3.5. Mise à jour de kubelet et kubectl :

Exécuté sur le Worker k8sw1
sudo apt-mark unhold kubelet kubectl
sudo apt-get install -y kubelet=1.32.13-1.1 kubectl=1.32.13-1.1
sudo apt-mark hold kubelet kubectl
Mise à jour de l’agent système principal (kubelet), qui gère directement le cycle de vie des conteneurs sur cette machine, et du client de ligne de commande.

3.6. Redémarrage de kubelet :

Exécuté sur le Worker k8sw1

sudo systemctl daemon-reload
sudo systemctl restart kubelet

Application du fichier binaire mis à jour et des nouvelles configurations via le redémarrage du service système.

3.7. Retour du Worker en service (Uncordon) :

Exécuté sur le Master k8sm

kubectl uncordon k8sw1

Cette commande supprime le statut de blocage de la planification (SchedulingDisabled) du nœud, permettant à l’ordonnanceur de Kubernetes d’y assigner à nouveau des pods.

🔁 Répétition de la procédure : Après avoir terminé avec succès les étapes 3.1 à 3.7 pour k8sw1, répétez ce même cycle pour le worker suivant — k8sw2 (n’oubliez pas de modifier le nom du nœud dans les commandes drain et uncordon).

Vérification finale du cluster

Exécuté sur le Master k8sm après la mise à jour de tous les nœuds

kubectl get nodes

Assurez-vous que tous les nœuds du cluster (le Master et les nœuds Workers) sont en statut Ready et affichent la version mise à jour v1.32.x. Si c’est le cas — le processus de mise à jour de Kubernetes est terminé avec succès !

Voilà. Les trois nœuds sont au statut Ready, et la version de tout le cluster est désormais uniformément passée à v1.32.13. Le cluster a été migré avec succès vers la nouvelle branche mineure sans perte de connectivité ni d’interruption de service. La mise à jour vers la v1.33 se déroule de manière similaire, bien qu’avec quelques réserves. En particulier, chaque nouvelle version mineure impose des exigences plus strictes quant à la version du runtime de conteneurs, ce qui fait qu’un containerd obsolète peut bloquer le démarrage de kubelet. De plus, Kubernetes supprime progressivement les API internes obsolètes. Il est donc recommandé, avant les étapes suivantes, de vérifier la compatibilité des manifestes et, si nécessaire, de mettre à jour containerd lui-même avec la commande sudo apt-get install --only-upgrade containerd.io.

Bonne chance !

👤

📁