kubeadm est l’outil officiel pour créer un cluster Kubernetes conforme aux bonnes pratiques, sans la couche d’abstraction des services managés. C’est la méthode utilisée pour la certification CKA et la meilleure façon de comprendre ce qui compose réellement un cluster. Ce guide installe Kubernetes 1.33 sur Ubuntu 24.04 avec containerd et le réseau Calico, sur un nœud de contrôle et deux nœuds de travail. Les anciens tutoriels utilisant apt-key, le dépôt apt.kubernetes.io ou Docker comme moteur ne fonctionnent plus ; tout ce qui suit correspond à l’outillage 2026.
Prérequis : trois machines Ubuntu 24.04 (VM locales, VPS ou instances cloud) avec au moins 2 vCPU et 2 Go de RAM (4 Go conseillés pour le nœud de contrôle), des noms d’hôte uniques, des adresses IP fixes sur le même réseau et un accès sudo. Ports à ouvrir : 6443, 2379-2380, 10250, 10257, 10259 sur le nœud de contrôle ; 10250 et 30000-32767 sur les workers ; TCP 179 et UDP 4789 partout pour Calico.
| Rôle | Nom d’hôte | IP (exemple) |
|---|---|---|
| Nœud de contrôle | cp1 | 192.168.56.10 |
| Worker | w1 | 192.168.56.11 |
| Worker | w2 | 192.168.56.12 |
Étape 1 – Préparer les trois nœuds
À exécuter sur chaque machine. Kubernetes exige que le swap soit désactivé et que le noyau route le trafic IPv4 et expose le trafic ponté à iptables.
# Nom d'hôte (adapter sur chaque nœud) et résolution locale
sudo hostnamectl set-hostname cp1
echo "192.168.56.10 cp1
192.168.56.11 w1
192.168.56.12 w2" | sudo tee -a /etc/hosts
# Désactiver le swap maintenant et au démarrage
sudo swapoff -a
sudo sed -i '/sswaps/s/^/#/' /etc/fstab
# Modules noyau et paramètres réseau
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay && sudo modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --systemÉtape 2 – Installer containerd
Le point qui piège tout le monde : kubelet utilise le pilote de cgroups systemd, containerd doit donc faire de même, sinon les pods restent bloqués en ContainerCreating.
sudo apt-get update
sudo apt-get install -y containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml > /dev/null
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo sed -i 's#sandbox_image = .*#sandbox_image = "registry.k8s.io/pause:3.10"#' /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerdÉtape 3 – Installer kubeadm, kubelet et kubectl
Les paquets proviennent des dépôts communautaires pkgs.k8s.io, un dépôt par version mineure. La clé de signature est déclarée avec signed-by.
K8S_MINOR=v1.33
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL "https://pkgs.k8s.io/core:/stable:/${K8S_MINOR}/deb/Release.key"
| sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${K8S_MINOR}/deb/ /"
| sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl # les mises à jour se font volontairement avec kubeadm
sudo systemctl enable --now kubelet
kubeadm version -o shortKubelet redémarre en boucle tant que kubeadm init ou join ne lui a pas fourni de configuration : c’est normal. Pour installer une version précise : apt-cache madison kubeadm puis apt-get install kubelet=1.33.4-1.1 kubeadm=1.33.4-1.1 kubectl=1.33.4-1.1.
Étape 4 – Initialiser le nœud de contrôle (cp1 uniquement)
sudo kubeadm init
--pod-network-cidr=192.168.0.0/16
--apiserver-advertise-address=192.168.56.10
--control-plane-endpoint=cp1
--kubernetes-version=stable-1.33
# Configurer kubectl pour votre utilisateur
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# cp1 NotReady control-plane 45s v1.33.4Conservez la commande kubeadm join … affichée à la fin. Le nœud est NotReady et CoreDNS reste Pending tant qu’aucun plugin réseau n’est installé : c’est attendu. Si votre réseau local utilise déjà 192.168.x.x, choisissez --pod-network-cidr=10.244.0.0/16 et adaptez la configuration Calico à l’étape suivante.
Étape 5 – Installer le réseau Calico
CALICO_VERSION=v3.30.2 # vérifier la dernière version sur docs.tigera.io
kubectl create -f "https://raw.githubusercontent.com/projectcalico/calico/${CALICO_VERSION}/manifests/tigera-operator.yaml"
curl -fsSLO "https://raw.githubusercontent.com/projectcalico/calico/${CALICO_VERSION}/manifests/custom-resources.yaml"
grep cidr custom-resources.yaml # doit correspondre au --pod-network-cidr
kubectl create -f custom-resources.yaml
watch kubectl get tigerastatus # attendre AVAILABLE=True partout, puis Ctrl-C
kubectl get nodes # cp1 passe à ReadyÉtape 6 – Joindre les workers (w1 et w2)
# Coller la commande affichée par kubeadm init, par exemple :
sudo kubeadm join cp1:6443 --token abcdef.0123456789abcdef
--discovery-token-ca-cert-hash sha256:<EMPREINTE_AFFICHEE_PAR_INIT>
# Commande perdue ? En générer une nouvelle sur cp1 (les jetons expirent après 24 h)
kubeadm token create --print-join-commandÉtape 7 – Vérifier le cluster
kubectl get nodes -o wide
# cp1 Ready control-plane 15m v1.33.4 192.168.56.10 Ubuntu 24.04.2 LTS containerd://1.7.27
# w1 Ready <none> 4m v1.33.4 192.168.56.11 ...
# w2 Ready <none> 3m v1.33.4 192.168.56.12 ...
kubectl get pods -A # tout doit être Running
kubectl label node w1 w2 node-role.kubernetes.io/worker=
# Test de bout en bout : déploiement, service NodePort, DNS
kubectl create deployment web --image=nginx:1.27 --replicas=2
kubectl expose deployment web --port=80 --type=NodePort
kubectl get svc web # relever le port 3xxxx
curl -s http://192.168.56.11:<NODEPORT> | grep -o '<title>.*</title>'
kubectl run -it --rm test-dns --image=busybox:1.36 --restart=Never -- nslookup web.default.svc.cluster.localPour un laboratoire à un seul nœud, autorisez les pods applicatifs sur le nœud de contrôle : kubectl taint nodes --all node-role.kubernetes.io/control-plane-.
Dépannage
- Échec du contrôle préliminaire « swap is enabled » – relancez
swapoff -a; sur certaines images cloud, masquez aussi l’unitéswap.img.swap. - Pods bloqués en ContainerCreating – pilote de cgroups incohérent ; vérifiez
SystemdCgroup = true, redémarrez containerd, puiskubeadm reset -fet recommencez. - Nœud NotReady durablement – Calico ne démarre pas :
kubectl get pods -n calico-system,kubectl describe tigerastatus calico; cause habituelle : pare-feu bloquant BGP (179) ou VXLAN (UDP 4789). - Join refusé (empreinte du certificat) – jeton expiré ou mal copié ; régénérez la commande.
- Tout recommencer sur un nœud –
sudo kubeadm reset -f && sudo rm -rf /etc/cni/net.d $HOME/.kube.
Mettre à jour plus tard
Les paquets étant gelés (apt-mark hold), une mise à jour est une décision explicite : changez K8S_MINOR dans le fichier de dépôt, mettez à jour kubeadm, exécutez kubeadm upgrade plan puis kubeadm upgrade apply v1.34.x sur cp1, et enfin mettez à jour kubelet et kubectl nœud par nœud après un kubectl drain. Kubernetes publie trois versions par an ; ne sautez jamais une version mineure.
À retenir
- Pile 2026 : Ubuntu 24.04, containerd avec cgroups systemd, dépôts
pkgs.k8s.io, Kubernetes 1.33, Calico via l’opérateur. kubeadm initsur le nœud de contrôle,kubeadm joinsur les workers ; paquets gelés, mises à jour maîtrisées.- Un nœud reste NotReady tant qu’aucun CNI n’est installé : c’est voulu.
- Validez toujours avec un déploiement réel, un NodePort et une résolution DNS entre nœuds.
La suite de la série Kubernetes (en anglais) : parcours d’apprentissage Kubernetes, etcd, plugins CNI. Documentation officielle : Creating a cluster with kubeadm.


