
kubeadm est l'outil officiel pour bootstrapper un cluster Kubernetes conforme aux standards upstream. Ce guide vous accompagne dans l'installation d'un cluster multi-nœuds sur des machines virtuelles KVM, de la préparation des VMs jusqu'au déploiement d'applications. Vous apprendrez à configurer containerd, initialiser le control plane, joindre des workers et maintenir votre cluster.
Autant lever le malentendu tout de suite. Ce guide construit un cluster robuste pour le lab, la validation technique et la préparation CKA, pas un cluster de production stricte. Il y manque, dans le désordre, un miroir de registre privé avec sa politique d'images, une sauvegarde etcd externalisée et chiffrée, de la supervision, une gestion centralisée des journaux, et un durcissement aligné sur un référentiel. Chacun de ces points fait l'objet d'une leçon ailleurs dans ce parcours : ce que vous montez ici en est le socle, pas l'aboutissement.
kubeadm vs autres solutions
Section intitulée « kubeadm vs autres solutions »Le tableau ci-dessous situe kubeadm parmi les outils qui montent des clusters. Lisez-le en gardant une idée en tête : kubeadm n'est pas en concurrence avec les distributions, il est ce sur quoi plusieurs d'entre elles reposent. Le choisir directement, c'est accepter d'assembler soi-même ce qu'elles livrent pré-assemblé, en échange d'un Kubernetes strictement conforme à l'upstream et d'une compréhension de chaque pièce.
| Critère | kubeadm | k0s | k3s | Kubespray | RKE2 |
|---|---|---|---|---|---|
| Type | Bootstrap tool | Distribution | Distribution | Playbooks Ansible | Distribution |
| Orientation | Standard upstream | Edge, prod, CI | Edge, IoT, dev | Prod, multi-cloud | Enterprise, sécurité |
| Installation | Commandes | k0sctl (YAML) | Script unique | Ansible | Script |
| CNI défaut | Aucun | kube-router | Flannel | Configurable | Canal |
| HA native | Manuel | ✅ Multi-controller | ✅ Multi-server | ✅ Ansible | ✅ Intégrée |
| Profil CIS | Manuel | Manuel | Manuel | Selon config | ✅ Intégré |
| Cas d'usage | Bare metal, formation | Edge, CI/CD, prod | Edge, IoT, dev | Prod automatisée | Conformité, prod |
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »Ce guide vous permettra de maîtriser l'installation et la maintenance d'un cluster Kubernetes avec kubeadm. À la fin, vous saurez :
- Provisionner des VMs KVM pour héberger le cluster, en comprenant pourquoi chaque configuration est nécessaire
- Installer containerd et les composants Kubernetes, en configurant correctement le cgroup driver pour éviter les problèmes de stabilité
- Initialiser un cluster avec kubeadm, en comprenant le rôle de chaque option et composant
- Joindre des nœuds workers au cluster et diagnostiquer les échecs de jointure
- Configurer la haute disponibilité avec plusieurs control planes et un load balancer
- Mettre à jour le cluster vers une nouvelle version en respectant les règles de version skew
- Sauvegarder et restaurer etcd, la base de données critique du cluster
- Dépanner les problèmes courants avec une méthodologie structurée
Prérequis
Section intitulée « Prérequis »Pourquoi ces ressources matérielles ?
Section intitulée « Pourquoi ces ressources matérielles ? »Avant de créer vos VMs, comprenez pourquoi Kubernetes impose des minimums stricts. Le control plane héberge l'API server, etcd, le scheduler et le controller-manager : ces composants consomment de la mémoire même au repos. Avec moins de 2 Go de RAM, etcd refusera de démarrer ou crashera sous charge. Les workers exécutent vos conteneurs applicatifs : 2 vCPU permettent de faire tourner plusieurs pods sans contention excessive.
| Rôle | CPU | RAM | Disque | Quantité | Pourquoi ces specs |
|---|---|---|---|---|---|
| Control plane | 2 vCPU | 2 Go | 20 Go | 1 (ou 3 pour HA) | etcd + API server + scheduler + controller-manager |
| Worker | 2 vCPU | 2 Go | 20 Go | 2+ | kubelet + pods applicatifs |
Pour un environnement de production, doublez ces valeurs minimum. En environnement de test ou pour la préparation CKA, ces minimums suffisent.
Logiciels requis sur l'hyperviseur
Section intitulée « Logiciels requis sur l'hyperviseur »Vous aurez besoin d'un hyperviseur Linux avec KVM pour créer les machines virtuelles. Si vous n'avez pas de serveur dédié, votre poste de travail suffit, à condition d'avoir assez de mémoire : 16 Go pour faire tourner trois VM simultanément.
- KVM/QEMU et libvirt installés (le cœur de la virtualisation)
- virt-manager ou virsh pour gérer les VMs (interface graphique ou CLI)
- Une image cloud Ubuntu 24.04 ou Rocky Linux 9 (pré-configurée pour cloud-init)
Ports réseau à ouvrir
Section intitulée « Ports réseau à ouvrir »La communication entre composants Kubernetes passe par des ports bien définis. Avec un pare-feu entre les VM, iptables, firewalld ou un équipement réseau, vous devez les ouvrir explicitement. Sur un réseau local sans pare-feu, cette étape ne sert à rien.
| Port | Composant | Qui se connecte | Pourquoi |
|---|---|---|---|
| 6443 | kube-apiserver | kubectl, kubelet, autres control planes | Point d'entrée de toute communication avec le cluster |
| 2379-2380 | etcd | API server, autres etcd (HA) | Base de données du cluster, réplication HA |
| 10250 | kubelet | API server, metrics-server | Gestion des pods, récupération des logs et métriques |
| 10257 | kube-controller-manager | Prometheus (optionnel) | Métriques du controller |
| 10259 | kube-scheduler | Prometheus (optionnel) | Métriques du scheduler |
| 179 | Calico BGP | Autres nœuds Calico | Routage BGP entre nœuds (si vous utilisez Calico) |
Création des machines virtuelles avec KVM
Section intitulée « Création des machines virtuelles avec KVM »kubeadm ne provisionne pas de machines : il faut donc les fabriquer avant lui.
Cette section monte trois VM sous KVM, un choix qui n'a rien d'obligatoire,
n'importe quel hyperviseur ou serveur physique conviendrait. Ce qui compte est
le résultat : trois systèmes joignables entre eux, avec un utilisateur
disposant de sudo et une adresse stable. Si vous disposez déjà de machines,
passez directement à la section suivante.
Architecture du lab
Section intitulée « Architecture du lab »Le schéma ci-dessous représente l'architecture cible. Un nœud control plane, cp1, héberge les composants de gestion, et deux workers, worker1 et worker2, exécutent vos applications. Tous sont sur le réseau virtuel par défaut de libvirt, virbr0 en 192.168.122.0/24.
Cette architecture suffit pour apprendre Kubernetes et préparer la CKA. En production, on ajoute deux control planes de plus pour la haute disponibilité, traitée dans une section dédiée.
Télécharger et préparer les images cloud
Section intitulée « Télécharger et préparer les images cloud »Les images cloud sont des disques système préconfigurés pour s'initialiser via cloud-init. Elles démarrent en quelques secondes et se configurent seules au premier amorçage. On emploie ici le backing file de QCOW2 : l'image de base reste intacte et chaque VM ne stocke que ses différences, ce qui économise du disque et accélère la création.
Ubuntu 24.04 LTS est recommandée pour sa stabilité et son support jusqu'en 2029. Son image cloud embarque déjà cloud-init et les modules noyau nécessaires.
# Télécharger l'image cloud Ubuntu (environ 700 Mo)wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img \ -O /var/lib/libvirt/images/ubuntu-24.04-cloud.img
# Créer un snapshot pour chaque VM (20 Go max, mais démarre petit)# Le backing file (-b) permet de partager l'image de base entre toutes les VMsqemu-img create -f qcow2 -b /var/lib/libvirt/images/ubuntu-24.04-cloud.img \ -F qcow2 /var/lib/libvirt/images/cp1.qcow2 20Gqemu-img create -f qcow2 -b /var/lib/libvirt/images/ubuntu-24.04-cloud.img \ -F qcow2 /var/lib/libvirt/images/worker1.qcow2 20Gqemu-img create -f qcow2 -b /var/lib/libvirt/images/ubuntu-24.04-cloud.img \ -F qcow2 /var/lib/libvirt/images/worker2.qcow2 20GRocky Linux 9 est l'alternative compatible RHEL, gratuite et maintenue par la communauté. Elle s'impose si votre parc d'entreprise est déjà sous RHEL.
# Télécharger l'image cloud Rocky Linux (environ 1 Go)wget https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2 \ -O /var/lib/libvirt/images/rocky-9-cloud.qcow2
# Créer un snapshot pour chaque VMqemu-img create -f qcow2 -b /var/lib/libvirt/images/rocky-9-cloud.qcow2 \ -F qcow2 /var/lib/libvirt/images/cp1.qcow2 20Gqemu-img create -f qcow2 -b /var/lib/libvirt/images/rocky-9-cloud.qcow2 \ -F qcow2 /var/lib/libvirt/images/worker1.qcow2 20Gqemu-img create -f qcow2 -b /var/lib/libvirt/images/rocky-9-cloud.qcow2 \ -F qcow2 /var/lib/libvirt/images/worker2.qcow2 20GConfigurer cloud-init
Section intitulée « Configurer cloud-init »Cloud-init est l'outil standard d'initialisation des instances cloud. Il pose le nom d'hôte, crée les utilisateurs, injecte les clés SSH et exécute des commandes au premier amorçage. Écrivez un fichier par VM, en adaptant l'adresse IP et le nom d'hôte.
Le fichier ci-dessous configure le control plane (cp1). Les points importants :
- Utilisateur
kube: compte dédié avec sudo sans mot de passe pour simplifier les manipulations - Clé SSH : remplacez par votre clé publique pour vous connecter sans mot de passe
- IP statique : garantit que les nœuds gardent la même IP après reboot
- Swap désactivé : kubelet refuse de démarrer si le swap est actif
#cloud-confighostname: cp1fqdn: cp1.kube.localmanage_etc_hosts: true
users: - name: kube sudo: ALL=(ALL) NOPASSWD:ALL groups: sudo shell: /bin/bash ssh_authorized_keys: - ssh-ed25519 AAAA... votre-clé-publique
# Réseau statique - adaptez à votre réseau libvirtnetwork: version: 2 ethernets: enp1s0: addresses: - 192.168.122.10/24 gateway4: 192.168.122.1 nameservers: addresses: - 192.168.122.1
# Commandes exécutées au premier bootruncmd: - swapoff -a - sed -i '/swap/d' /etc/fstabCréez des fichiers similaires pour worker1 (IP .20) et worker2 (IP .21).
Créer les VMs avec virt-install
Section intitulée « Créer les VMs avec virt-install »Les images et la configuration prêtes, il reste à créer les machines virtuelles. La commande cloud-localds fabrique un disque ISO portant la configuration cloud-init, que la VM lit à son premier amorçage.
# Générer l'ISO cloud-init pour le control planecloud-localds /var/lib/libvirt/images/cp1-cidata.iso cloud-init-cp1.yaml
# Créer la VM control plane# --import : utilise un disque existant au lieu de lancer une installation# --noautoconsole : ne pas attacher de console (la VM démarre en arrière-plan)virt-install \ --name cp1 \ --ram 2048 \ --vcpus 2 \ --disk path=/var/lib/libvirt/images/cp1.qcow2,format=qcow2 \ --disk path=/var/lib/libvirt/images/cp1-cidata.iso,device=cdrom \ --os-variant ubuntu24.04 \ --network network=default \ --graphics none \ --console pty,target_type=serial \ --import \ --noautoconsoleRépétez l'opération pour worker1 et worker2 en adaptant les noms et les fichiers cloud-init.
Vérification : après une minute de boot, testez la connexion SSH. Si la connexion échoue, vérifiez que votre clé publique est correcte dans le fichier cloud-init.
ssh kube@192.168.122.10# Doit se connecter sans demander de mot de passeInstallation des prérequis sur tous les nœuds
Section intitulée « Installation des prérequis sur tous les nœuds »Cette section prépare le système pour exécuter Kubernetes. Chaque étape a une raison précise, et sauter une étape causera des problèmes difficiles à diagnostiquer. Exécutez ces commandes sur tous les nœuds (control plane et workers).
-
Configurer les modules kernel pour le réseau des conteneurs
Kubernetes relie les conteneurs par des ponts réseau virtuels. Le module
overlayautorise le stockage en couches des images, etbr_netfilterfait passer le trafic des ponts par iptables. Sans ce second module, les règles des Services ne s'appliquent pas.Fenêtre de terminal # Charger les modules au démarragecat <<EOF | sudo tee /etc/modules-load.d/k8s.confoverlaybr_netfilterEOF# Charger les modules immédiatement (sans reboot)sudo modprobe overlaysudo modprobe br_netfilterVérification : les modules doivent apparaître dans la liste des modules chargés.
Fenêtre de terminal lsmod | grep -E 'overlay|br_netfilter'# br_netfilter 32768 0# overlay 151552 0 -
Configurer sysctl pour le forwarding réseau
Ces paramètres noyau laissent le trafic traverser les interfaces virtuelles. Sans eux, les Pods ne communiquent ni entre eux ni avec l'extérieur. Le paramètre
ip_forwardactive le routage IP, indispensable puisque chaque nœud se comporte en routeur pour ses Pods.Fenêtre de terminal cat <<EOF | sudo tee /etc/sysctl.d/k8s.confnet.bridge.bridge-nf-call-iptables = 1net.bridge.bridge-nf-call-ip6tables = 1net.ipv4.ip_forward = 1EOF# Appliquer sans rebootsudo sysctl --systemVérification : les valeurs doivent être à 1.
Fenêtre de terminal sysctl net.ipv4.ip_forward# net.ipv4.ip_forward = 1 -
Désactiver le swap (obligatoire)
Le kubelet refuse de démarrer tant que le swap est actif, et la raison mérite d'être connue : le scheduler décide du placement d'après la mémoire réellement disponible. Un système qui swape rend ces calculs faux. Si cloud-init a déjà désactivé le swap, la commande est sans effet.
Fenêtre de terminal # Désactiver immédiatementsudo swapoff -a# Supprimer l'entrée swap du fstab pour que ça persiste au rebootsudo sed -i '/swap/d' /etc/fstabVérification : la commande
freene doit montrer aucun swap.Fenêtre de terminal free -h | grep Swap# Swap: 0B 0B 0B -
Installer containerd comme runtime de conteneurs
Kubernetes a besoin d'un runtime de conteneurs conforme à l'interface CRI (Container Runtime Interface). Depuis Kubernetes 1.24, le kubelet ne parle plus directement à Docker Engine : c'est dockershim qui a été retiré, Docker Engine restant utilisable via l'adaptateur cri-dockerd. containerd est devenu le standard de fait : léger, stable, et utilisé par tous les clouds publics. Nous l'installons depuis le dépôt Docker car il fournit des binaires à jour.
Fenêtre de terminal # Installer les dépendances pour ajouter des repos HTTPSsudo apt-get updatesudo apt-get install -y ca-certificates curl gnupg# Ajouter la clé GPG du repo Dockersudo install -m 0755 -d /etc/apt/keyringscurl -fsSL https://download.docker.com/linux/ubuntu/gpg | \sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg# Ajouter le repo Dockerecho "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \sudo tee /etc/apt/sources.list.d/docker.list# Installer containerdsudo apt-get updatesudo apt-get install -y containerd.ioFenêtre de terminal # Ajouter le repo Dockersudo dnf config-manager --add-repo \https://download.docker.com/linux/centos/docker-ce.repo# Installer containerdsudo dnf install -y containerd.io -
Configurer containerd avec le cgroup driver systemd
C'est l'étape la plus critique et la plus souvent oubliée. Kubernetes et containerd doivent utiliser le même cgroup driver. Sur les distributions modernes avec systemd, ce driver doit être
systemd(pascgroupfs). Si vous oubliez cette configuration, le kubelet crashera avec des erreurs cryptiques.Fenêtre de terminal # Générer la configuration par défautsudo mkdir -p /etc/containerdcontainerd config default | sudo tee /etc/containerd/config.toml# CRITIQUE : activer le cgroup driver systemdsudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml# Redémarrer pour appliquersudo systemctl restart containerdsudo systemctl enable containerdVérification : containerd doit être actif et la configuration correcte.
Fenêtre de terminal sudo systemctl status containerd# ● containerd.service - containerd container runtime# Active: active (running)grep SystemdCgroup /etc/containerd/config.toml# SystemdCgroup = true -
Installer kubeadm, kubelet et kubectl
Ces trois binaires forment le cœur de l'installation :
- kubeadm : outil de bootstrap qui initialise le cluster et génère les certificats
- kubelet : agent qui tourne sur chaque nœud et gère les containers
- kubectl : CLI pour interagir avec l'API Kubernetes
Fenêtre de terminal # Ajouter la clé GPG du repo Kubernetessudo mkdir -p /etc/apt/keyringscurl -fsSL https://pkgs.k8s.io/core:/stable:/v1.36/deb/Release.key | \sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg# Ajouter le repo Kubernetesecho 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] \https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /' | \sudo tee /etc/apt/sources.list.d/kubernetes.list# Installer les composantssudo apt-get updatesudo apt-get install -y kubelet kubeadm kubectl# Bloquer les mises à jour automatiques (important pour les upgrades contrôlés)sudo apt-mark hold kubelet kubeadm kubectlFenêtre de terminal # Ajouter le repo Kubernetescat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo[kubernetes]name=Kubernetesbaseurl=https://pkgs.k8s.io/core:/stable:/v1.36/rpm/enabled=1gpgcheck=1gpgkey=https://pkgs.k8s.io/core:/stable:/v1.36/rpm/repodata/repomd.xml.keyEOF# Installer les composantssudo dnf install -y kubelet kubeadm kubectl --disableexcludes=kubernetessudo systemctl enable kubeletVérification : les binaires doivent être installés à la bonne version.
Fenêtre de terminal kubeadm version# kubeadm version: &version.Info{Major:"1", Minor:"36", EmulationMajor:"",# EmulationMinor:"", MinCompatibilityMajor:"", MinCompatibilityMinor:"",# GitVersion:"v1.36.0", GitCommit:"ecf6decece6a6de25a57aad9ba90b6ce580f6f78",# GitTreeState:"clean", BuildDate:"2026-04-22T13:54:03Z", GoVersion:"go1.26.2",# Compiler:"gc", Platform:"linux/amd64"}kubectl version --client# Client Version: v1.36.0# Kustomize Version: v5.8.1Deux champs de cette sortie déroutent la première fois. Depuis la 1.36, la structure de version porte
EmulationMajor/EmulationMinoretMinCompatibilityMajor/MinCompatibilityMinor, liés à la compatibility version. Ils sont vides sur un binaire standard, et c'est normal : ils servent à un kube-apiserver qui doit émuler le comportement d'une version antérieure pendant une mise à jour progressive.
Initialisation du cluster
Section intitulée « Initialisation du cluster »L'initialisation du cluster est le moment où kubeadm génère tous les composants du control plane : certificats TLS, fichiers de configuration, et pods statiques. Cette étape ne s'exécute que sur le premier nœud control plane.
Comprendre les options de kubeadm init
Section intitulée « Comprendre les options de kubeadm init »Avant de lancer la commande, comprenez chaque option pour pouvoir adapter à votre environnement :
| Option | Signification | Pourquoi c'est important |
|---|---|---|
--pod-network-cidr | Plage d'adresses pour les pods | Le CNI (Flannel, Calico) utilisera ce CIDR. 10.244.0.0/16 est le défaut pour Flannel |
--apiserver-advertise-address | IP sur laquelle l'API server écoute | Les workers et kubectl utiliseront cette IP |
--control-plane-endpoint | Endpoint stable pour le control plane | Indispensable pour HA : permet d'ajouter d'autres control planes plus tard |
Méthode recommandée : fichier de configuration YAML
Section intitulée « Méthode recommandée : fichier de configuration YAML »Plutôt que des options CLI longues, utilisez un fichier de configuration kubeadm. C'est reproductible, versionnable et compatible avec IaC (Ansible, Terraform).
Créez un fichier kubeadm-config.yaml :
apiVersion: kubeadm.k8s.io/v1beta4kind: ClusterConfigurationkubernetesVersion: v1.36.0controlPlaneEndpoint: "192.168.122.10:6443"networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12---apiVersion: kubelet.config.k8s.io/v1beta1kind: KubeletConfigurationcgroupDriver: systemdPuis initialisez avec :
sudo kubeadm init --config kubeadm-config.yamlQuatre raisons rendent cette forme préférable à la ligne de commande. Le
fichier est versionnable dans Git, donc relisible et comparable d'une
version à l'autre. Il se génère depuis Ansible ou Terraform le jour où
l'installation s'industrialise. Il rassemble toutes les options au même
endroit, là où une commande longue devient illisible. Et il n'empêche rien :
le passage en haute disponibilité se fait en ajoutant --upload-certs à la
commande, pas au fichier.
Initialiser avec la ligne de commande (alternative)
Section intitulée « Initialiser avec la ligne de commande (alternative) »Si vous préférez ne pas créer de fichier YAML pour un lab rapide, vous pouvez utiliser les options CLI. Sur le nœud cp1 uniquement, lancez l'initialisation :
sudo kubeadm init \ --pod-network-cidr=10.244.0.0/16 \ --apiserver-advertise-address=192.168.122.10 \ --control-plane-endpoint=192.168.122.10:6443Un conseil qui ne coûte rien sur le moment et évite une reconstruction plus
tard : renseignez --control-plane-endpoint même si la haute
disponibilité n'est pas au programme. Ce champ fixe l'adresse que tous les
clients utiliseront, et c'est lui qui permet d'ajouter des control planes
sans recréer le cluster. À défaut de load balancer, mettez l'adresse du
premier control plane ; l'important est que le champ existe dès le départ.
Sortie attendue (les tokens seront différents) :
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
...
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.122.10:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:...Copiez et sauvegardez la commande kubeadm join affichée ! Vous en aurez besoin pour joindre les workers. Le token expire après 24 heures.
Configurer kubectl pour l'utilisateur courant
Section intitulée « Configurer kubectl pour l'utilisateur courant »kubectl a besoin d'un kubeconfig pour savoir où joindre l'API server et comment s'y authentifier. Le fichier admin.conf produit par kubeadm porte un certificat client administrateur. On le copie dans le répertoire personnel pour que kubectl le trouve sans option.
# Créer le répertoire de configuration kubectlmkdir -p $HOME/.kube
# Copier le fichier de configuration adminsudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# Donner les droits à l'utilisateur courantsudo chown $(id -u):$(id -g) $HOME/.kube/configVérification : kubectl doit maintenant pouvoir contacter l'API server.
kubectl get nodes# NAME STATUS ROLES AGE VERSION# cp1 NotReady control-plane 30s v1.36.0Le statut NotReady est normal à ce stade : le CNI (Container Network Interface) n'est pas encore installé. Sans CNI, les pods ne peuvent pas obtenir d'adresses IP et le nœud ne peut pas être considéré comme prêt.
Installer le plugin réseau CNI
Section intitulée « Installer le plugin réseau CNI »Le CNI (Container Network Interface) fournit le réseau aux pods. Sans lui, les pods resteront en Pending et le nœud en NotReady.
Choisissez votre CNI selon votre cas d'usage :
| CNI | Usage conseillé | NetworkPolicies | Complexité | Quand l'utiliser |
|---|---|---|---|---|
| Flannel | Lab, démo, apprentissage | ❌ Non | ⭐ Faible | Vous débutez ou n'avez pas besoin de NetworkPolicies |
| Calico | Production classique | ✅ Oui | ⭐⭐ Moyenne | Vous avez besoin d'isolation réseau entre namespaces |
| Cilium | Production avancée, observabilité | ✅ Oui + eBPF | ⭐⭐⭐ Plus élevée | Vous voulez de l'observabilité réseau poussée |
Flannel est le CNI le plus simple à poser, ce qui en fait le bon choix pour apprendre et pour la CKA. Il n'applique pas les NetworkPolicies, limite sans conséquence sur un lab mais rédhibitoire en production.
# Installer Flannelkubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.ymlCalico supporte les NetworkPolicies et offre plus de contrôle sur le réseau. Recommandé pour les clusters self-managed sérieux et la production. La séquence ci-dessous correspond à Calico v3.30.1 sur Kubernetes 1.36.
# Installer l'opérateur Tigera (CRDs Installation et APIServer)kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.30.1/manifests/tigera-operator.yaml
# Attendre que les CRDs soient enregistrés (sinon le kubectl apply suivant échoue)kubectl wait --for=condition=Established crd/installations.operator.tigera.io --timeout=60skubectl wait --for=condition=Established crd/apiservers.operator.tigera.io --timeout=60s
# Déployer Calico avec le CIDR cohérent avec --pod-network-cidr du kubeadm initcat <<EOF | kubectl apply -f -apiVersion: operator.tigera.io/v1kind: Installationmetadata: name: defaultspec: calicoNetwork: ipPools: - blockSize: 26 cidr: 10.244.0.0/16 encapsulation: VXLANCrossSubnet natOutgoing: Enabled nodeSelector: all()---apiVersion: operator.tigera.io/v1kind: APIServermetadata: name: defaultspec: {}EOFLes kubectl wait --for=condition=Established ci-dessus ne sont pas
décoratifs. Sans eux, le second kubectl apply échoue sur no matches for kind "Installation" in version "operator.tigera.io/v1" : les CRD viennent
d'être créées et le cache de découverte de kubectl ne les connaît pas
encore. L'erreur est déroutante parce qu'elle désigne un type qui existe bel
et bien, une seconde plus tard.
Cette commande crée un namespace dédié, un DaemonSet, des ConfigMaps et les RBAC nécessaires. Attendez environ 30 secondes que les pods CNI démarrent.
Vérification : le nœud doit passer en Ready et Flannel doit tourner.
# Le nœud doit maintenant être Readykubectl get nodes# NAME STATUS ROLES AGE VERSION# cp1 Ready control-plane 2m v1.36.0
# Le pod Flannel doit être Runningkubectl get pods -n kube-flannel# NAME READY STATUS RESTARTS AGE# kube-flannel-ds-xxxxx 1/1 Running 0 30s
# Vérifier aussi les pods systèmekubectl get pods -n kube-system# Tous les pods doivent être Running ou CompletedJoindre les workers au cluster
Section intitulée « Joindre les workers au cluster »Chaque worker doit s'enregistrer auprès du control plane avant de recevoir des Pods. La commande kubeadm join s'authentifie avec un token et une empreinte de certificat, les deux étant obligatoires.
Sur chaque worker (worker1 et worker2), exécutez la commande copiée lors de l'initialisation :
sudo kubeadm join 192.168.122.10:6443 \ --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:...Le token est valide 24 heures. Si vous l'avez perdu ou s'il a expiré, générez-en un nouveau sur le control plane :
# Sur le control plane : regénérer la commande join complètekubeadm token create --print-join-commandVérification finale depuis le control plane : tous les nœuds doivent être Ready.
kubectl get nodes -o wide# NAME STATUS ROLES AGE VERSION INTERNAL-IP OS-IMAGE# cp1 Ready control-plane 5m v1.36.0 192.168.122.10 Ubuntu 24.04# worker1 Ready <none> 2m v1.36.0 192.168.122.20 Ubuntu 24.04# worker2 Ready <none> 1m v1.36.0 192.168.122.21 Ubuntu 24.04Félicitations ! Vous avez un cluster Kubernetes fonctionnel. Les sections suivantes couvrent la haute disponibilité, les mises à jour et le dépannage.
Configuration haute disponibilité
Section intitulée « Configuration haute disponibilité »En production, un control plane unique est un point de défaillance unique. S'il tombe, l'API server devient injoignable et le cluster n'est plus pilotable. Les workers continuent de faire tourner les Pods existants, mais plus aucun déploiement, mise à l'échelle ou modification n'aboutit.
La haute disponibilité répond à ce risque avec trois control planes et un répartiteur de charge devant eux. La perte d'un nœud laisse les deux autres servir.
Choisir votre topologie etcd
Section intitulée « Choisir votre topologie etcd »Kubernetes HA supporte deux architectures etcd. Comprenez les différences avant de choisir :
| Architecture | Description | Avantages | Inconvénients | Quand l'utiliser |
|---|---|---|---|---|
| Stacked etcd | etcd sur les mêmes nœuds que le control plane | Moins de VMs, plus simple | Couplage control plane/etcd, risque de contention ressources | Lab, CKA, clusters < 50 nœuds |
| External etcd | Cluster etcd dédié (3 VMs séparées) | Isolation ressources, scaling indépendant | Plus de VMs, complexité certificats | Production critique, > 50 nœuds |
Ce guide utilise stacked etcd (la topologie par défaut de kubeadm).
Attention au load balancer comme SPOF
Section intitulée « Attention au load balancer comme SPOF »Le load balancer (HAProxy) lui-même peut devenir un point de défaillance unique. En production stricte :
- Utilisez 2 instances HAProxy avec Keepalived pour une VIP flottante
- Ou un load balancer cloud (AWS ELB, GCP LB) qui est nativement HA
Architecture HA
Section intitulée « Architecture HA »Le schéma ci-dessous montre une architecture HA courante. HAProxy répartit le trafic entre les API servers, chaque control plane héberge son propre etcd, ce qu'on appelle la topologie stacked, et les workers ne connaissent que le répartiteur.
Installer HAProxy sur une VM dédiée
Section intitulée « Installer HAProxy sur une VM dédiée »HAProxy répartit en TCP le port 6443 de l'API server. Dédiez-lui une VM, ou réutilisez un répartiteur existant. Le contrôle de santé TCP retire automatiquement du service un control plane qui ne répond plus.
sudo apt-get install -y haproxyConfigurez HAProxy pour répartir entre les trois control planes. Le mode tcp est obligatoire : l'API server parle TLS, et le répartiteur ne doit surtout pas terminer la connexion chiffrée.
global daemon maxconn 256
defaults mode tcp timeout connect 5000ms timeout client 50000ms timeout server 50000ms
frontend kubernetes-frontend bind *:6443 default_backend kubernetes-backend
backend kubernetes-backend balance roundrobin option tcp-check server cp1 192.168.122.10:6443 check server cp2 192.168.122.11:6443 check server cp3 192.168.122.12:6443 checkRedémarrez HAProxy et vérifiez qu'il écoute sur le port 6443 :
sudo systemctl restart haproxysudo systemctl enable haproxy
# Vérifier que HAProxy écoutess -tlnp | grep 6443# LISTEN 0 128 *:6443 *:* users:(("haproxy",...))Initialiser le premier control plane HA
Section intitulée « Initialiser le premier control plane HA »L'initialisation en HA se distingue par l'option --upload-certs, qui chiffre les certificats du cluster et les dépose dans un Secret. Les control planes suivants les récupèrent à la jointure, sans copie manuelle.
sudo kubeadm init \ --pod-network-cidr=10.244.0.0/16 \ --control-plane-endpoint="192.168.122.5:6443" \ --upload-certsPoints importants :
--control-plane-endpointpointe vers HAProxy (pas vers cp1)--upload-certsgénère une clé de déchiffrement valide 2 heures
La sortie affiche deux commandes kubeadm join :
- Une pour les workers (sans
--control-plane) - Une pour les control planes (avec
--control-plane --certificate-key)
Joindre les autres control planes
Section intitulée « Joindre les autres control planes »Sur cp2 et cp3, exécutez la commande spéciale pour control planes :
sudo kubeadm join 192.168.122.5:6443 \ --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:... \ --control-plane \ --certificate-key ...Vérification : les 3 control planes doivent apparaître avec le rôle control-plane.
kubectl get nodes# NAME STATUS ROLES AGE VERSION# cp1 Ready control-plane 10m v1.36.0# cp2 Ready control-plane 5m v1.36.0# cp3 Ready control-plane 3m v1.36.0Mise à jour du cluster
Section intitulée « Mise à jour du cluster »La montée de version d'un cluster est une compétence attendue à la CKA. Kubernetes publie trois versions mineures par an, et l'exercice consiste à suivre ce rythme sans interruption de service.
Règles de version skew
Section intitulée « Règles de version skew »Kubernetes impose des règles strictes de compatibilité entre versions. Le version skew définit l'écart de version autorisé entre composants :
| Composant | Skew autorisé par rapport à kube-apiserver |
|---|---|
| kubelet | -2 versions mineures (ex: API 1.36 → kubelet 1.34 OK) |
| kubectl | ±1 version mineure |
| kube-controller-manager, kube-scheduler | Même version ou -1 |
Règle pratique : mettez à jour le control plane avant les workers, et ne sautez pas de version mineure.
Deux règles gouvernent l'ordre des opérations, et les enfreindre bloque la
mise à jour plutôt que de la casser, ce qui est déjà ça. La première interdit
de sauter une version mineure : de 1.34, on passe par 1.35 avant
d'atteindre 1.36. La seconde fixe l'ordre à l'intérieur d'une même étape :
kubeadm d'abord, puis kubeadm upgrade apply, et seulement ensuite
kubelet et kubectl.
Mettre à jour le control plane
Section intitulée « Mettre à jour le control plane »La mise à jour du control plane se fait en plusieurs étapes. Cette procédure minimise le temps d'indisponibilité de l'API server.
Quatre vérifications avant de lancer quoi que ce soit, dont aucune n'est
facultative. Sauvegardez etcd, c'est le seul retour en arrière possible si
l'opération tourne mal. Lisez les notes de version de la cible, à la
recherche des changements de comportement. Vérifiez le skew, aucun saut de
version mineure n'est permis. Et si vos nœuds sont derrière un miroir,
récupérez les images à l'avance avec kubeadm config images pull.
-
Vérifier les versions disponibles
Avant toute chose, regardez quelles versions le dépôt propose réellement. C'est ce qui permet de planifier la montée et de vérifier que la version cible existe.
Fenêtre de terminal # Lister les versions disponibles de kubeadmapt-cache madison kubeadm | head -5# kubeadm | 1.36.0-1.1 | https://pkgs.k8s.io/core:/stable:/v1.36/deb Packages# kubeadm | 1.35.4-1.1 | https://pkgs.k8s.io/core:/stable:/v1.35/deb Packages# kubeadm | 1.35.3-1.1 | https://pkgs.k8s.io/core:/stable:/v1.35/deb Packages# kubeadm | 1.35.2-1.1 | https://pkgs.k8s.io/core:/stable:/v1.35/deb Packages# kubeadm | 1.35.1-1.1 | https://pkgs.k8s.io/core:/stable:/v1.35/deb PackagesLe dépôt
pkgs.k8s.ioest versionné par version mineure, ce qui surprend au premier passage. Pour voir les paquets1.36.x, il faut d'abord déclarer le dépôtv1.36:/etc/apt/sources.list.d/kubernetes.listdoit pointer vershttps://pkgs.k8s.io/core:/stable:/v1.36/deb/. Sans cette étape,apt-cache madisonne listera que la mineure courante, et vous conclurez à tort que la version cible n'existe pas. -
Mettre à jour kubeadm en premier
kubeadm doit lui-même être à la version cible avant de pouvoir l'appliquer. On lève donc le blocage du paquet, on met à jour, puis on rebloque pour qu'une mise à jour système ne l'emporte pas.
Fenêtre de terminal # Débloquer kubeadmsudo apt-mark unhold kubeadm# Mettre à jour le cache et installer la nouvelle versionsudo apt-get updatesudo apt-get install -y kubeadm=1.36.0-1.1# Rebloquer pour éviter les mises à jour automatiquessudo apt-mark hold kubeadm -
Vérifier le plan de mise à jour
Cette commande affiche exactement ce qui sera mis à jour, vérifie les prérequis et signale les obstacles. Lisez sa sortie en entier avant d'aller plus loin.
Fenêtre de terminal sudo kubeadm upgrade plan# [preflight] Running pre-flight checks.# [upgrade/config] Reading configuration from the "kubeadm-config" ConfigMap...# [upgrade] Running cluster health checks# [upgrade] Fetching available versions to upgrade to# [upgrade/versions] Cluster version: 1.35.4# [upgrade/versions] kubeadm version: v1.36.0# [upgrade/versions] Target version: v1.36.0# [upgrade/versions] Latest version in the v1.35 series: v1.35.4## Components that must be upgraded manually after you have upgraded the control plane# with 'kubeadm upgrade apply':# COMPONENT NODE CURRENT TARGET# kubelet cp1 v1.35.4 v1.36.0# kubelet worker1 v1.35.4 v1.36.0# kubelet worker2 v1.35.4 v1.36.0## Upgrade to the latest stable version:## COMPONENT NODE CURRENT TARGET# kube-apiserver cp1 v1.35.4 v1.36.0# kube-controller-manager cp1 v1.35.4 v1.36.0# kube-scheduler cp1 v1.35.4 v1.36.0# kube-proxy 1.35.4 v1.36.0# CoreDNS v1.13.1 v1.14.2# etcd cp1 3.6.6-0 3.6.8-0## You can now apply the upgrade by executing the following command:## kubeadm upgrade apply v1.36.0Notez les sauts de version embarqués : CoreDNS v1.13.1 → v1.14.2, etcd 3.6.6-0 → 3.6.8-0. Pour la liste exhaustive des images packagées avec 1.36 :
Fenêtre de terminal sudo kubeadm config images list --kubernetes-version v1.36.0# registry.k8s.io/kube-apiserver:v1.36.0# registry.k8s.io/kube-controller-manager:v1.36.0# registry.k8s.io/kube-scheduler:v1.36.0# registry.k8s.io/kube-proxy:v1.36.0# registry.k8s.io/coredns/coredns:v1.14.2# registry.k8s.io/pause:3.10.2# registry.k8s.io/etcd:3.6.8-0Si vos nœuds n'atteignent pas
registry.k8s.iodirectement, ne découvrez pas le problème au milieu de la mise à jour : récupérez les images à l'avance sur chaque nœud aveckubeadm config images pull --kubernetes-version v1.36.0. Sur un cluster isolé derrière un miroir, cette étape fait la différence entre une fenêtre de quelques secondes et une indisponibilité qui s'étire. -
Appliquer la mise à jour
Cette commande met à jour les composants du control plane : elle télécharge les images, réécrit les manifestes des pods statiques et redémarre les composants. Le cluster reste accessible, avec au pire quelques secondes d'indisponibilité de l'API.
Fenêtre de terminal sudo kubeadm upgrade apply v1.36.0 --yes# [upgrade/staticpods] Backing up old manifest to /etc/kubernetes/tmp/...# [upgrade/staticpods] Waiting for the kubelet to restart the component# [apiclient] Found 1 Pods for label selector component=kube-apiserver# [upgrade/staticpods] Component "kube-apiserver" upgraded successfully!# ... (idem pour kube-controller-manager, kube-scheduler, etcd)# [upgrade/control-plane] The control plane instance for this node was successfully upgraded!# [kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system...# [upgrade/kubeconfig] The kubeconfig files for this node were successfully upgraded!# [upgrade/kubelet-config] The kubelet configuration for this node was successfully upgraded!# [addons] Applied essential addon: CoreDNS# [addons] Applied essential addon: kube-proxy## [upgrade] SUCCESS! A control plane node of your cluster was upgraded to "v1.36.0".Ce que fait
kubeadm upgrade applymérite d'être connu, parce que cela dit où chercher si l'opération tourne mal. Pour chaque pod statique du control plane,kube-apiserver,kube-controller-manager,kube-scheduleretetcd, kubeadm procède en trois temps : il sauvegarde l'ancien manifeste dans/etc/kubernetes/tmp/kubeadm-backup-manifests-<horodatage>/, écrit le nouveau dans/etc/kubernetes/manifests/, puis attend que le kubelet redémarre le pod. L'indisponibilité par composant se compte en secondes, et ce répertoire de sauvegarde est votre filet en cas de retour arrière. -
Mettre à jour kubelet et kubectl
kubelet et kubectl doivent être mis à jour séparément. Le kubelet gère les pods sur ce nœud, donc un redémarrage est nécessaire.
Fenêtre de terminal # Débloquer les paquetssudo apt-mark unhold kubelet kubectl# Installer les nouvelles versionssudo apt-get install -y kubelet=1.36.0-1.1 kubectl=1.36.0-1.1# Rebloquersudo apt-mark hold kubelet kubectl# Recharger la configuration systemd et redémarrer kubeletsudo systemctl daemon-reloadsudo systemctl restart kubeletVérification : le nœud control plane doit afficher la nouvelle version.
Fenêtre de terminal kubectl get nodes# NAME STATUS ROLES AGE VERSION# cp1 Ready control-plane 8m v1.36.0 # ← nouvelle version# worker1 Ready <none> 7m v1.35.4 # ← workers à upgrader# worker2 Ready <none> 7m v1.35.4 -
Vérifier les add-ons après upgrade
Après l'upgrade, vérifiez que les composants critiques fonctionnent toujours :
Fenêtre de terminal # Vérifier CoreDNSkubectl get pods -n kube-system -l k8s-app=kube-dns# Tous doivent être Running# Vérifier kube-proxykubectl get pods -n kube-system -l k8s-app=kube-proxy# DaemonSet, un pod par nœud# Vérifier le CNI (Flannel ou Calico)kubectl get pods -n kube-flannel # ou -n calico-system# Tous doivent être Running# Vérifier qu'il n'y a pas d'erreurs dans les eventskubectl get events -A --field-selector type=Warning --sort-by='.lastTimestamp' | head -10
Mettre à jour les workers
Section intitulée « Mettre à jour les workers »Les workers se mettent à jour un par un, pour que les applications restent servies. La séquence drain, upgrade, uncordon garantit que les Pods sont déplacés avant toute intervention sur le nœud.
-
Drainer le nœud pour évacuer les pods
Le drain déplace proprement les Pods vers les autres nœuds. Les DaemonSets restent, puisqu'ils doivent tourner partout. Les Pods portant un volume emptyDir perdent leurs données, ce que l'option
--delete-emptydir-datavous fait accepter explicitement.Fenêtre de terminal # Depuis le control planekubectl drain worker1 --ignore-daemonsets --delete-emptydir-data# node/worker1 cordoned# Warning: ignoring DaemonSet-managed Pods: calico-system/calico-node-xxxxx,# calico-system/csi-node-driver-xxxxx, kube-system/kube-proxy-xxxxx# evicting pod kube-system/coredns-589f44dc88-xxxxx# evicting pod calico-system/calico-typha-55d4f6d9c7-xxxxx# pod/coredns-589f44dc88-xxxxx evicted# pod/calico-typha-55d4f6d9c7-xxxxx evicted# node/worker1 drained# Vérifier que le nœud est cordoned (SchedulingDisabled)kubectl get nodes# NAME STATUS ROLES AGE VERSION# cp1 Ready control-plane 10m v1.36.0# worker1 Ready,SchedulingDisabled <none> 9m v1.35.4# worker2 Ready <none> 9m v1.35.4 -
Mettre à jour kubeadm et kubelet sur le worker
Ces commandes se lancent sur le worker, et non sur le control plane.
kubeadm upgrade nodemet à jour la configuration locale du kubelet, pas le plan de contrôle.Fenêtre de terminal # Sur le worker (SSH kube@192.168.122.20)# Ajouter le dépôt v1.36 (idem que sur le control plane)curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.36/deb/Release.key \| sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-1.36-keyring.gpgecho "deb [signed-by=/etc/apt/keyrings/kubernetes-1.36-keyring.gpg] \https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /" \| sudo tee /etc/apt/sources.list.d/kubernetes-1.36.listsudo apt-mark unhold kubeadm kubeletsudo apt-get updatesudo apt-get install -y kubeadm=1.36.0-1.1 kubelet=1.36.0-1.1sudo apt-mark hold kubeadm kubelet# Mettre à jour la configuration kubelet localesudo kubeadm upgrade node# [upgrade/preflight] Skipping prepull. Not a control plane node.# [upgrade/control-plane] Skipping phase. Not a control plane node.# [upgrade/kubeconfig] Skipping phase. Not a control plane node.# [upgrade] Backing up kubelet config file to /etc/kubernetes/tmp/kubeadm-kubelet-config-...# [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"# [upgrade/kubelet-config] The kubelet configuration for this node was successfully upgraded!# [upgrade/addon] Skipping the addon/coredns phase. Not a control plane node.# [upgrade/addon] Skipping the addon/kube-proxy phase. Not a control plane node.# Redémarrer kubeletsudo systemctl daemon-reloadsudo systemctl restart kubelet -
Remettre le nœud en service
Une fois la mise à jour terminée, autorisez à nouveau le scheduling sur ce nœud. Les pods en attente seront automatiquement schedulés dessus.
Fenêtre de terminal # Depuis le control planekubectl uncordon worker1# node/worker1 uncordoned# Vérifier que le nœud est Ready et à la nouvelle versionkubectl get nodes# NAME STATUS ROLES AGE VERSION# cp1 Ready control-plane 10m v1.36.0# worker1 Ready <none> 10m v1.36.0# worker2 Ready <none> 10m v1.35.4 # ← prochain à upgrader
Répétez cette procédure pour chaque worker. En production, attendez que les pods soient stables sur un nœud avant de passer au suivant.
Sauvegarde et restauration d'etcd
Section intitulée « Sauvegarde et restauration d'etcd »etcd est la base de données du cluster Kubernetes. Elle contient tout : Deployments, Services, Secrets, ConfigMaps, état des pods, etc. Si etcd est corrompu ou perdu sans sauvegarde, le cluster est irrécupérable. La sauvegarde régulière d'etcd est donc critique en production.
Comprendre où sont stockées les données etcd
Section intitulée « Comprendre où sont stockées les données etcd »etcd tourne comme un pod statique sur chaque control plane. Ses données vivent dans /var/lib/etcd/, ses certificats dans /etc/kubernetes/pki/etcd/. Toute interaction avec lui en exige trois :
| Certificat | Chemin | Rôle |
|---|---|---|
| CA | /etc/kubernetes/pki/etcd/ca.crt | Autorité de certification etcd |
| Certificat client | /etc/kubernetes/pki/etcd/server.crt | Authentification du client |
| Clé privée | /etc/kubernetes/pki/etcd/server.key | Signature des requêtes |
Sauvegarder etcd
Section intitulée « Sauvegarder etcd »La sauvegarde crée un snapshot de toutes les données etcd. Cette opération est non-bloquante et peut être exécutée sur un cluster en production.
Où trouver etcdctl, qui n'est pas sur le nœud
Section intitulée « Où trouver etcdctl, qui n'est pas sur le nœud »Première surprise : etcdctl n'est pas installé par kubeadm. Vérifié sur un
nœud de cette formation, command -v etcdctl ne rend rien. Deux voies existent,
et la seconde ne demande rien à installer.
Ou bien vous installez le paquet client d'etcd sur le nœud, ou bien vous appelez le binaire là où il vit déjà, dans le conteneur etcd lui-même :
kubectl -n kube-system exec etcd-<nom-du-noeud> -- etcdctl versionetcdctl version: 3.7.0API version: 3.7Appelez etcdctl directement, sans passer par sh -c : l'image d'etcd ne
contient aucun shell, et toute commande enveloppée échoue sur
"sh": executable file not found in $PATH.
# Créer un snapshot d'etcd, depuis le conteneur etcdkubectl -n kube-system exec etcd-<nom-du-noeud> -- etcdctl snapshot save /tmp/etcd-backup.db \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \ --key=/etc/kubernetes/pki/etcd/healthcheck-client.key{"level":"info",...,"msg":"fetched snapshot","size":"5.0 MB","took":"33.181333ms"}Snapshot saved at /tmp/etcd-backup.dbDeux précisions sur cette commande, toutes deux vérifiées. ETCDCTL_API=3
n'est plus nécessaire : la variable était obligatoire du temps d'etcd 3.3 et
3.4, et le client 3.7 l'ignore purement et simplement, y compris si vous lui
donnez la valeur 2. Et le certificat client employé ici est healthcheck-client, prévu
pour cet usage ; server.crt fonctionne aussi, mais c'est détourner un
certificat de serveur pour un rôle de client.
Vérification : contrôlez que le snapshot est valide et contient des données. En etcd 3.7, etcdctl snapshot n'offre plus que save ; la vérification appartient à etcdutl :
etcdutl snapshot status /tmp/etcd-backup.db --write-out=table┌──────────┬──────────┬────────────┬────────────┬─────────┐│ HASH │ REVISION │ TOTAL KEYS │ TOTAL SIZE │ VERSION │├──────────┼──────────┼────────────┼────────────┼─────────┤│ 642e758b │ 257204 │ 360 │ 40 MB │ 3.7.0 │└──────────┴──────────┴────────────┴────────────┴─────────┘Il n'existe pas d'alternative avec etcdctl, et c'est le piège. Appeler
etcdctl snapshot status n'échoue pas : la commande affiche l'aide de
snapshot et sort en 0. Un script de sauvegarde qui vérifie ainsi son
instantané signale un succès sans avoir ouvert le fichier.
Un snapshot laissé sur le nœud qu'il sauvegarde ne sert à rien le jour où ce nœud disparaît. Quatre règles séparent une sauvegarde d'une illusion de sauvegarde. Externalisez les snapshots vers S3, GCS, NFS ou tout stockage distant. Chiffrez-les : ils contiennent l'intégralité des Secrets du cluster en clair, ce qui en fait l'objet le plus sensible de votre infrastructure. Testez la restauration sur un cluster jetable, tous les mois, faute de quoi vous ne saurez pas si vos fichiers sont exploitables. Et gardez au moins sept jours d'historique, parce qu'une corruption ne se remarque pas toujours le jour même.
Restaurer etcd
Section intitulée « Restaurer etcd »La restauration d'etcd est une opération destructive : elle écrase toutes les données actuelles. Utilisez-la uniquement pour récupérer d'un désastre ou migrer vers un nouveau cluster.
-
Arrêter le control plane
Arrêtez kubelet pour que les pods statiques (API server, etc.) s'arrêtent. etcd doit être arrêté pour la restauration.
Fenêtre de terminal sudo systemctl stop kubelet -
Restaurer le snapshot dans un nouveau répertoire
La restauration crée un nouveau répertoire de données. Elle ne modifie pas
/var/lib/etcddirectement.Fenêtre de terminal etcdutl snapshot restore /tmp/etcd-backup.db \--data-dir=/var/lib/etcd-restoredetcdctl snapshot restorea été supprimé en 3.7 et répondError: unknown flag: --data-dir. Contrairement àstatus, l'échec est ici bruyant. -
Remplacer les données etcd
Sauvegardez l'ancien répertoire (au cas où) et mettez le nouveau en place.
Fenêtre de terminal sudo mv /var/lib/etcd /var/lib/etcd.oldsudo mv /var/lib/etcd-restored /var/lib/etcd -
Redémarrer le control plane
kubelet va redémarrer les pods statiques, y compris etcd avec les données restaurées.
Fenêtre de terminal sudo systemctl start kubelet -
Vérifier que le cluster fonctionne
Attendez quelques minutes que tous les composants redémarrent.
Fenêtre de terminal kubectl get nodeskubectl get pods -A
Renouvellement des certificats
Section intitulée « Renouvellement des certificats »Les certificats Kubernetes générés par kubeadm expirent après 1 an par défaut. Un certificat expiré bloque complètement l'accès au cluster : kubectl ne fonctionne plus, les nœuds perdent le contact avec l'API server.
Vérifier l'expiration des certificats
Section intitulée « Vérifier l'expiration des certificats »Cette commande affiche la date d'expiration de chaque certificat. Planifiez le renouvellement avant l'expiration.
sudo kubeadm certs check-expiration# CERTIFICATE EXPIRES RESIDUAL TIME EXTERNALLY MANAGED# admin.conf Mar 15, 2027 10:00 UTC 364d no# apiserver Mar 15, 2027 10:00 UTC 364d no# apiserver-etcd-client Mar 15, 2027 10:00 UTC 364d no# ...Surveillez la colonne RESIDUAL TIME. Renouvelez quand il reste moins de 30 jours.
Une distinction évite de surveiller ce qui n'en a pas besoin. Kubeadm
configure par défaut la rotation automatique des certificats client du
kubelet : ceux-là se renouvellent seuls avant expiration, vous n'avez rien à
faire. Ceux qui exigent une intervention manuelle sont ceux du control
plane : API server, etcd, controller-manager, scheduler, et les fichiers
kubeconfig qui vont avec. C'est exactement la liste que rend kubeadm certs check-expiration.
Renouveler tous les certificats
Section intitulée « Renouveler tous les certificats »Le renouvellement régénère tous les certificats avec une nouvelle validité d'un an. Les clients (kubectl, kubelet des workers) devront récupérer les nouveaux certificats.
# Renouveler tous les certificats du control planesudo kubeadm certs renew all
# Redémarrer les composants pour qu'ils utilisent les nouveaux certificatssudo systemctl restart kubeletAprès le renouvellement, mettez à jour le fichier kubeconfig de votre utilisateur :
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/configsudo chown $(id -u):$(id -g) $HOME/.kube/configAutomatisez l'alerte, gardez la main sur l'opération. Une tâche
hebdomadaire qui lance kubeadm certs check-expiration et prévient au-delà
d'un seuil coûte trois lignes et rend un vrai service. Déclencher le
renouvellement sans surveillance est une autre affaire : l'opération
redémarre les composants du control plane, et vous ne voulez pas qu'elle se
produise à trois heures du matin sans personne pour constater le résultat.
Dépannage du cluster
Section intitulée « Dépannage du cluster »Le dépannage représente 30% de l'examen CKA, c'est le domaine le plus lourd. Cette section vous donne une méthodologie structurée et les commandes essentielles pour diagnostiquer rapidement les problèmes.
Méthodologie de diagnostic
Section intitulée « Méthodologie de diagnostic »Face à un problème, suivez cette approche en couches :
- État du nœud :
kubectl get nodes, le nœud est-il Ready ? - Pods système :
kubectl get pods -n kube-system, les composants tournent-ils ? - kubelet :
journalctl -u kubelet, le kubelet démarre-t-il ? - Composants : logs des pods statiques avec
crictl - Réseau : connectivité entre pods, DNS, Services
Problèmes courants et solutions
Section intitulée « Problèmes courants et solutions »Ce tableau couvre les situations les plus fréquentes. Pour chaque symptôme, la cause la plus probable et la solution directe.
| Symptôme | Cause probable | Comment diagnostiquer | Solution |
|---|---|---|---|
Nœud NotReady après init | CNI non installé | kubectl describe node → "network plugin is not ready" | Installer Flannel ou Calico |
Nœud NotReady après reboot | kubelet ne démarre pas | journalctl -u kubelet -xe | Vérifier swap, cgroups, containerd |
connection refused :6443 | API server down | crictl ps -a | grep kube-api | Vérifier manifest /etc/kubernetes/manifests/kube-apiserver.yaml |
| Token expiré | Token > 24h | kubeadm token list | kubeadm token create --print-join-command |
| Certificat expiré | Certificats > 1 an | kubeadm certs check-expiration | kubeadm certs renew all |
Pods en Pending | Pas de nœud disponible ou ressources insuffisantes | kubectl describe pod <pod> → Events | Ajouter des workers ou libérer des ressources |
Pods en CrashLoopBackOff | Application qui crash | kubectl logs <pod> --previous | Corriger l'application |
CoreDNS en CrashLoopBackOff | Problème CNI ou loop DNS | kubectl logs -n kube-system coredns-xxx | Vérifier CNI, /etc/resolv.conf |
| Worker ne joint pas | Connectivité, token, ou cgroups | journalctl -u kubelet -xe sur le worker | Vérifier les 3 causes ci-dessus |
Diagnostic du kubelet
Section intitulée « Diagnostic du kubelet »Le kubelet est l'agent qui pilote les conteneurs sur chaque nœud. S'il ne tourne pas, rien ne tourne sur ce nœud. Les commandes ci-dessous sont les premiers réflexes de diagnostic.
# État du service kubeletsudo systemctl status kubelet# Si inactive ou failed, regarder pourquoi :
# Logs détaillés du kubelet (les 100 dernières lignes)sudo journalctl -u kubelet -n 100 --no-pager
# Logs en temps réel (pour voir ce qui se passe pendant un test)sudo journalctl -u kubelet -f
# Erreurs spécifiques (--since pour limiter)sudo journalctl -u kubelet --since "5 minutes ago" | grep -i errorErreurs fréquentes dans les logs kubelet :
| Message d'erreur | Cause | Solution |
|---|---|---|
failed to run Kubelet: running with swap on is not supported | Swap actif | swapoff -a && sed -i '/swap/d' /etc/fstab |
failed to get cgroup | Mauvais cgroup driver | Vérifier SystemdCgroup = true dans containerd |
Unable to connect to the server | API server injoignable | Vérifier réseau et certificats |
certificate has expired | Certificats expirés | kubeadm certs renew all |
Diagnostic des pods statiques du control plane
Section intitulée « Diagnostic des pods statiques du control plane »Les composants du control plane (kube-apiserver, etcd, kube-scheduler, kube-controller-manager) sont des pods statiques gérés directement par kubelet. Leurs manifests sont dans /etc/kubernetes/manifests/. Pour voir leurs logs, utilisez crictl (pas kubectl, qui nécessite un API server fonctionnel).
# Lister tous les conteneurs (y compris arrêtés)sudo crictl ps -a
# Logs de l'API serversudo crictl logs $(sudo crictl ps -q --name kube-apiserver)
# Logs d'etcdsudo crictl logs $(sudo crictl ps -q --name etcd)
# Logs du schedulersudo crictl logs $(sudo crictl ps -q --name kube-scheduler)
# Logs du controller-managersudo crictl logs $(sudo crictl ps -q --name kube-controller-manager)Vérifier l'état d'etcd
Section intitulée « Vérifier l'état d'etcd »etcd est la base de données du cluster. Si etcd ne fonctionne pas, l'API server ne peut pas stocker ni récupérer de données.
# Statut des endpoints etcd (santé du cluster etcd)sudo etcdctl endpoint health \ --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
# Sortie attendue :# https://127.0.0.1:2379 is healthy: successfully committed proposal: took = 2.5ms
# Liste des membres du cluster etcd (utile en HA)sudo etcdctl member list \ --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.keyDiagnostic réseau et DNS
Section intitulée « Diagnostic réseau et DNS »Les problèmes réseau sont fréquents. Ces commandes vérifient que les pods peuvent communiquer et que le DNS fonctionne.
# Vérifier que CoreDNS fonctionnekubectl get pods -n kube-system -l k8s-app=kube-dns# Les pods doivent être Running
# Tester la résolution DNS depuis un pod temporairekubectl run dnstest --image=busybox:1.28 --rm -it --restart=Never -- nslookup kubernetes# Doit résoudre vers l'IP du service kubernetes (10.96.0.1 par défaut)
# Si DNS échoue, vérifier le service CoreDNSkubectl get svc -n kube-system kube-dnskubectl get endpointslice -n kube-system -l kubernetes.io/service-name=kube-dns
# Vérifier les logs CoreDNSkubectl logs -n kube-system -l k8s-app=kube-dnsDiagnostic des Services et endpoints
Section intitulée « Diagnostic des Services et endpoints »Quand un Service ne répond pas, vérifiez la chaîne complète : Service → Endpoints → Pods.
# Lister les Services avec leurs ClusterIPkubectl get svc -A
# Vérifier qu'un Service a des endpoints (pods cibles)kubectl get endpointslice -l kubernetes.io/service-name=<service-name># Si ENDPOINTS est vide, le selector ne matche aucun pod
# Vérifier les EndpointSlices (nouveau format)kubectl get endpointslices -l kubernetes.io/service-name=<service-name>
# Tester la connectivité vers un Service depuis un podkubectl run curltest --image=curlimages/curl:8.21.0 --rm -it --restart=Never -- \ curl -v http://<service-name>.<namespace>.svc.cluster.localVoir les événements récents
Section intitulée « Voir les événements récents »Les événements Kubernetes sont une mine d'or pour le dépannage. Ils montrent ce qui s'est passé récemment.
# Tous les événements du cluster, triés par datekubectl get events -A --sort-by='.lastTimestamp'
# Événements d'un namespace spécifiquekubectl get events -n <namespace>
# Événements liés à un objet spécifiquekubectl describe pod <pod-name> # Section Events en bas
# Filtrer les événements de type Warningkubectl get events -A --field-selector type=WarningReset complet d'un nœud
Section intitulée « Reset complet d'un nœud »Si un nœud est trop corrompu pour être réparé, réinitialisez-le complètement. Cette procédure efface toute la configuration Kubernetes du nœud.
# Réinitialiser kubeadm (supprime certificats et configuration)sudo kubeadm reset -f
# Supprimer la configuration CNIsudo rm -rf /etc/cni/net.d
# Supprimer le kubeconfig utilisateursudo rm -rf $HOME/.kube
# Nettoyer les règles iptables créées par kube-proxysudo iptables -Fsudo iptables -t nat -Fsudo iptables -t mangle -Fsudo iptables -X
# Optionnel : nettoyer les images containerdsudo crictl rmi --allAprès le reset, vous pouvez rejoindre le cluster avec kubeadm join.
Compétences CKA couvertes par ce guide
Section intitulée « Compétences CKA couvertes par ce guide »Ce guide couvre principalement le domaine Cluster Architecture, Installation & Configuration (25%) de la CKA. Le tableau ci-dessous résume ce que vous avez appris et ce qui reste à maîtriser dans d'autres guides.
Ce que ce guide couvre (25% de l'examen)
Section intitulée « Ce que ce guide couvre (25% de l'examen) »Ce guide est aligné sur le domaine Cluster Architecture, Installation & Configuration, qui pèse 25 % de l'épreuve. Le tableau met en regard chaque objectif du programme et la section qui le traite, ce qui permet de repérer ce qu'il reste à revoir plutôt que de relire la page entière. Trois points reviennent le plus souvent à l'examen : le nombre impair de control planes, imposé par le quorum d'etcd, la différence entre etcd empilé et etcd externe, et la sauvegarde puis restauration d'etcd, qui est un classique.
| Objectif CKA | Section du guide | Compétence acquise |
|---|---|---|
| Préparer l'infrastructure pour installer un cluster | Création des VMs, prérequis | Configuration kernel, containerd, swap |
| Créer et gérer des clusters avec kubeadm | Initialisation, join workers | kubeadm init, kubeadm join, CNI |
| Gérer le cycle de vie d'un cluster | Mise à jour | kubeadm upgrade, drain/uncordon |
| Implémenter un control plane HA | Configuration HA | HAProxy, stacked etcd, join control planes |
| Comprendre les interfaces d'extension (CNI, CSI, CRI) | Installation containerd, CNI | CRI avec containerd, CNI avec Flannel |
| Sauvegarder et restaurer etcd | Sauvegarde/restauration | etcdctl snapshot save/restore |
Ce que ce guide ne couvre pas (à étudier ailleurs)
Section intitulée « Ce que ce guide ne couvre pas (à étudier ailleurs) »La CKA évalue aussi des compétences non couvertes ici. Consultez les guides dédiés :
| Domaine CKA | Poids | Ce qu'il faut savoir | Guide recommandé |
|---|---|---|---|
| Troubleshooting | 30% | Logs, events, debug réseau, kubelet | Ce guide + pratique intensive |
| Services & Networking | 20% | Services, Ingress, NetworkPolicies, Gateway API, CoreDNS | Guide Réseau Kubernetes |
| Workloads & Scheduling | 15% | Deployments, rollouts, ConfigMaps, Secrets, scheduling | Guide Workloads Kubernetes |
| Storage | 10% | PV, PVC, StorageClass, access modes | Guide Storage Kubernetes |
Outils à maîtriser pour la CKA
Section intitulée « Outils à maîtriser pour la CKA »La CKA attend que vous maîtrisiez certains outils de packaging et configuration :
| Outil | Ce qu'il faut savoir | Couvert ici ? |
|---|---|---|
| kubectl | Toutes les commandes, output JSON/YAML, --dry-run | Partiellement |
| kubeadm | init, join, upgrade, certs, reset | ✅ Oui |
| etcdctl | snapshot save/restore, endpoint health | ✅ Oui |
| Helm | install, upgrade, rollback, values | ❌ Guide dédié |
| Kustomize | bases, overlays, patches | ❌ Guide dédié |
| crictl | ps, logs, images | ✅ Oui |
Tester vos connaissances
Section intitulée « Tester vos connaissances »Dix questions sur ce qui coûte le plus cher en pratique comme à l'examen :
l'ordre des opérations d'une mise à jour, l'emplacement des fichiers que
kubeadm produit, et la façon d'atteindre etcdctl sur un nœud qui ne le
fournit pas.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
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
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »Ce guide vous a appris à installer et maintenir un cluster Kubernetes avec kubeadm. Voici les points essentiels à retenir :
-
kubeadm est l'outil officiel de bootstrap, il génère certificats, manifests et configure le cluster selon les standards upstream
-
containerd avec
SystemdCgroup = trueest obligatoire, c'est l'erreur n°1 des débutants, vérifiez toujours ce paramètre -
Les modules kernel
overlayetbr_netfiltersont indispensables pour le réseau des conteneurs -
Le swap doit être désactivé, kubelet refuse de démarrer si le swap est actif
-
Le CNI (Flannel, Calico) s'installe après
kubeadm init, sans lui, les nœuds restent en NotReady -
Spécifiez
--control-plane-endpointmême pour un cluster single-node, cela permet de passer en HA plus tard -
Mettez à jour control plane avant workers, respectez le version skew (1 version mineure max)
-
Sauvegardez etcd régulièrement, c'est la seule source de vérité du cluster, sans backup = perte totale
-
Renouvelez les certificats avant expiration, ils expirent après 1 an, planifiez le renouvellement
-
Pour dépanner : kubelet logs → crictl logs → events → describe, suivez cette progression systématiquement
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Installer avec Talos Linux : L'alternative immuable à kubeadm, sans accès shell aux nœuds.
- Backup et Restore : La sauvegarde d'etcd à mettre en place dès la fin de l'installation.
- Mettre à jour un cluster : La procédure
kubeadm upgrade, à connaître avant la première montée de version.
Ressources
Section intitulée « Ressources »Pour aller plus loin, consultez ces ressources officielles :
- Documentation kubeadm, référence officielle pour toutes les options et procédures
- CKA Certification, page officielle avec le curriculum et les objectifs de l'examen
- Kubernetes the Hard Way, installation manuelle pour comprendre chaque composant en profondeur
- GitHub kubeadm, issues et discussions sur kubeadm
- Best practices clusters de production, recommandations officielles pour la production