Introduction
L'initialisation d'un plan de contrôle Kubernetes avec kubeadm init devrait être prévisible, mais les clusters réels échouent pour des raisons concrètes : exigences du runtime de conteneurs non satisfaites, mauvaise configuration du plugin réseau, problèmes de certificats ou contraintes de ressources. Ce guide transforme ces échecs en un flux de travail de dépannage reproductible.
Il est destiné aux développeurs, consultants DevOps et équipes techniques de startups qui gèrent eux-mêmes Kubernetes. Chaque solution inclut la commande exacte, le résultat attendu, une étape de vérification et une procédure de retour en arrière lorsqu'elle existe. Les exemples utilisent des variables comme 10.0.0.10 ou k8s-master-1 ; ne copiez jamais d'adresses IP privées, de jetons ou de certificats dans un runbook ou un article.
Parcourez les sections dans l'ordre. Commencez par des observations en lecture seule, confirmez la version et l'environnement, puis appliquez un changement ciblé à la fois. Cela limite la zone d'impact et facilite le diagnostic de l'échec suivant.
Inventaire des versions et de l'environnement
Avant de dépanner toute erreur de kubeadm init, enregistrez les versions exactes et la topologie. Les différentes versions de Kubernetes modifient le comportement par défaut, donc une commande qui fonctionne sur la version 1.26 peut ne pas fonctionner sur la version 1.30.
1. Vérifiez les versions installées
Exécutez sur le nœud qui deviendra le plan de contrôle :
kubeadm version -o short
kubelet --version
kubectl version --client --short
Résultat attendu (illustratif pour Kubernetes v1.30.0) :
v1.30.0
Kubernetes v1.30.0
Client Version: v1.30.0
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Si kubeadm est manquant ou obsolète, installez-le depuis le dépôt officiel de Kubernetes. Sur Debian/Ubuntu :
sudo apt-get update
sudo apt-get install -y kubelet=1.30.0-1.1 kubeadm=1.30.0-1.1 kubectl=1.30.0-1.1
sudo apt-mark hold kubelet kubeadm kubectl
2. Confirmez le runtime de conteneurs
kubeadm prend en charge containerd, CRI-O et Docker Engine (via cri-dockerd). Vérifiez quel runtime est actif :
sudo crictl version
sudo crictl info | grep -A 5 "config"
Si crictl n'est pas installé, utilisez la propre CLI du runtime :
sudo containerd --version
sudo crio --version
sudo dockerd --version
Vérifiez que le socket du runtime correspond à celui attendu par kubeadm. Pour containerd, le chemin par défaut est /run/containerd/containerd.sock. Pour CRI-O, /var/run/crio/crio.sock. Pour Docker avec cri-dockerd, /var/run/cri-dockerd.sock. Si vous voyez une erreur CRI v1 runtime API is not implemented lors de l'init, le chemin du socket est généralement incorrect.
3. Documentez le réseau et la topologie
Capturez le nom d'hôte, les adresses IP et l'interface réseau :
hostname
ip -4 addr show | grep inet
cat /etc/hosts
Décidez s'il s'agit d'un cluster à nœud unique ou d'une configuration multi-nœuds. Enregistrez l'adresse d'annonce du serveur API que vous comptez utiliser. Exemple d'une init réussie :
apiServer:
advertiseAddress: 192.168.1.100
bindPort: 6443
Si vous ajoutez plus tard des nœuds workers, ils doivent pouvoir atteindre cette adresse. Une inadéquation entre l'adresse d'annonce et l'interface réseau réelle est une cause courante d'init bloquée ou échouée.
Vérification : Avant d'exécuter kubeadm init, assurez-vous que l'heure système est synchronisée :
sudo timedatectl status | grep synchronized
Résultat attendu : System clock synchronized: yes. Sinon, configurez NTP (chrony ou systemd-timesyncd).
Zone d'impact : Les changements de version et de runtime affectent tous les conteneurs du nœud. Ne mettez pas à niveau ou ne rétrogradez pas un runtime sur un nœud exécutant des charges de production sans l'avoir préalablement drainé. Pour une nouvelle initialisation, le risque est faible, mais notez toujours les versions précédentes pour permettre un retour en arrière.
Chemin de configuration sûr
La plupart des erreurs de kubeadm init proviennent de mauvaises correspondances de configuration, pas de Kubernetes lui-même. Utilisez un fichier de configuration pour la reproductibilité et pour éviter les fautes de frappe dans les indicateurs CLI.
1. Générez une configuration par défaut
kubeadm config print init-defaults > kubeadm-init.yaml
Ce fichier contient des valeurs d'exemple. Modifiez uniquement les champs dont vous avez besoin. Exemple de modification minimale :
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
nodeRegistration:
criSocket: unix:///var/run/containerd/containerd.sock
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.30.0
networking:
podSubnet: "10.244.0.0/16" # Doit correspondre aux attentes de votre plugin CNI
serviceSubnet: "10.96.0.0/12"
apiserver:
advertiseAddress: 192.168.1.100
Enregistrez ce fichier avec un nom clair, par exemple kubeadm-init-cluster1.yaml, et conservez-le dans un contrôle de version. Ne commitez jamais de secrets ; le fichier lui-même ne contient aucun secret si vous n'ajoutez pas les champs token ou certificate-authority-data.
2. Exécutez l'init avec la configuration
sudo kubeadm init --config kubeadm-init-cluster1.yaml --upload-certs --v=5
L'indicateur --v=5 augmente la verbosité des journaux, ce qui est utile lorsqu'une erreur se produit. L'indicateur --upload-certs n'est nécessaire que pour les configurations multi-maîtres ; omettez-le pour un plan de contrôle unique afin de réduire la surface d'attaque.
Si la commande échoue, la sortie montrera quelle vérification préalable ou quelle phase a échoué. Ne vous précipitez pas pour ajouter --ignore-preflight-errors=all. Lisez plutôt l'erreur spécifique et traitez sa cause fondamentale. Ignorer les erreurs de vérification préalable peut laisser le cluster dans un état incohérent plus difficile à récupérer.
3. Erreurs courantes liées à la configuration et solutions
Erreur : [ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables does not exist
Cela indique que le module du noyau br_netfilter n'est pas chargé. Solution :
sudo modprobe br_netfilter
sudo sh -c 'echo "br_netfilter" > /etc/modules-load.d/br_netfilter.conf'
sudo sysctl -w net.bridge.bridge-nf-call-iptables=1
sudo sh -c 'echo "net.bridge.bridge-nf-call-iptables = 1" > /etc/sysctl.d/99-kubernetes.conf'
Vérifiez :
sysctl net.bridge.bridge-nf-call-iptables
Attendu : net.bridge.bridge-nf-call-iptables = 1.
Erreur : [ERROR Swap]: running with swap on is not supported
Kubernetes nécessite la désactivation du swap. Solution :
sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
Vérifiez qu'aucune entrée de swap n'est active :
free -h
La ligne Swap doit afficher 0B au total.
Erreur : [ERROR FileContent--etc-containerd-config.toml]: /etc/containerd/config.toml does not contain a valid config
Les anciennes configurations de containerd peuvent manquer des paramètres du plugin CRI. Régénérez la configuration par défaut et redémarrez :
sudo sh -c 'containerd config default > /etc/containerd/config.toml'
sudo systemctl restart containerd
Vérification : Après tout changement de configuration, exécutez les vérifications préalables seules :
sudo kubeadm init phase preflight --config kubeadm-init-cluster1.yaml
Toutes les vérifications doivent réussir avant de procéder à l'init complète.
Zone d'impact : Les changements de configuration n'affectent que le nœud où ils sont appliqués. Cependant, modifier les paramètres sysctl ou de pare-feu peut affecter d'autres services sur le même hôte. Documentez chaque changement et testez à nouveau l'init complète immédiatement.
Vérification et diagnostics
Une fois que kubeadm init se termine avec succès, vous devez encore vérifier que le cluster est fonctionnel et diagnostiquer pourquoi il pourrait ne pas l'être. Un message d'init vert ne signifie pas que le serveur API est sain.
1. Configurez kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Testez la connectivité :
kubectl get nodes
Résultat attendu (initialement) :
NAME STATUS ROLES AGE VERSION
k8s-master-1 NotReady control-plane 1m v1.30.0
Le nœud restera NotReady jusqu'à l'installation d'un réseau de pods.
2. Inspectez la santé des composants principaux
kubectl get pods -n kube-system
Tous les pods kube-apiserver, kube-controller-manager, kube-scheduler, etcd et kube-proxy doivent être en Running ou Completed pour les pods statiques. Si certains sont en CrashLoopBackOff, consultez les journaux :
kubectl logs -n kube-system kube-apiserver-k8s-master-1 --tail=50
Modèles de diagnostic courants :
etcdincapable de démarrer : souvent un disque défaillant ou des permissions incorrectes surdata-dir. Vérifiezsudo journalctl -u kubelet -f.kube-apiserverne répond pas : vérifiez les erreurs de certificat dans les journaux. Si vous voyezx509: certificate has expired or is not yet valid, l'horloge système est probablement incorrecte. Exécutezsudo timedatectlet corrigez NTP.kube-proxyen échec : peut être dû à un plugin réseau non installé. Installez d'abord un CNI.
3. Installez un réseau de pods (CNI)
Ce guide utilise Calico comme exemple, mais le choix dépend de votre environnement. Pour un cluster à nœud unique, Flannel est plus simple. Pour la production, Calico ou Cilium offrent un support des politiques réseau.
Installez Flannel (rapide à mettre en place) :
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
Installez Calico (plus riche en fonctionnalités) :
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/custom-resources.yaml
Après l'application, attendez que les pods CNI soient prêts :
kubectl get pods -n kube-system -w
Vérifiez ensuite l'état du nœud :
kubectl get nodes
Attendu : k8s-master-1 Ready control-plane 5m v1.30.0.
4. Testez un déploiement de charge de travail
Déployez un simple pod nginx et un service :
kubectl create deployment nginx --image=nginx:1.25
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get svc nginx
Notez le NodePort (par exemple, 30080). Accédez-y via curl http://<node-ip>:30080. Si cela reste bloqué, vérifiez l'état du pod :
kubectl get pods -l app=nginx
Si le pod est en Pending, exécutez kubectl describe pod <pod-name> pour voir les événements. Un problème courant est une insuffisance de CPU/mémoire ou un CNI manquant.
Vérification : kubeadm init stocke sa sortie, y compris la commande de jointure et la clé de certificat, dans /var/log/kubeadm-init.log. Inspectez-le pour tout avertissement :
sudo cat /var/log/kubeadm-init.log | grep -i warning
Zone d'impact : L'ajout d'un plugin CNI n'affecte que le réseau des pods. Supprimer ou changer un CNI sur un cluster en cours d'exécution est perturbateur ; choisissez soigneusement avant l'installation.
Modes de défaillance et récupération
Même avec une préparation minutieuse, l'init peut échouer à différentes étapes. Cette section répertorie les modes de défaillance courants, leurs symptômes et les étapes de récupération.
Défaillance : kubeadm init expire pendant waiting for the kubelet to boot up the control plane
Symptômes : L'init reste bloquée pendant plusieurs minutes et finit par échouer. journalctl -u kubelet montre des erreurs répétées.
Causes possibles et solutions :
- Runtime de conteneurs non prêt : Vérifiez
sudo systemctl status containerd(ou CRI-O/Docker). S'il ne fonctionne pas, démarrez-le et réessayez l'init. - Plugin réseau déjà appliqué avant l'init : Supprimez tous les fichiers
/etc/cni/net.d/*.confet redémarrez kubelet. - Ressources insuffisantes : Vérifiez
free -hetdf -h. Assurez-vous que le système de fichiers racine a au moins 10 Go libres et que la mémoire est d'au moins 2 Go. - Problèmes de certificats : Si vous réessayez l'init après une tentative précédente, exécutez d'abord
sudo kubeadm reset -fpour nettoyer l'état résiduel.
Récupération : Exécutez toujours sudo kubeadm reset -f après un échec d'init avec des erreurs d'état persistantes. Corrigez ensuite le problème sous-jacent et relancez l'init.
Défaillance : Problèmes de certificat du serveur API
Symptômes : kubectl get nodes renvoie Unable to connect to the server: x509: certificate signed by unknown authority ou curl https://<master-ip>:6443/version échoue avec une erreur TLS.
Causes :
- Dérive de l'horloge système.
- Mélange d'anciens certificats d'un cluster précédent.
- Utilisation d'une autorité de certification personnalisée sans confiance appropriée.
Solution :
- Assurez la synchronisation de l'heure :
sudo timedatectl set-ntp true. - Réinitialisez entièrement le cluster :
sudo kubeadm reset -fetsudo rm -rf /etc/kubernetes /var/lib/etcd /var/lib/kubelet. - Relancez l'init. Ne tentez pas de remplacer manuellement les certificats à moins d'être expérimenté avec l'ICG (Infrastructure à Clés Gérées).
Défaillance : Le nœud reste NotReady après l'installation du CNI
Symptômes : kubectl get nodes montre NotReady indéfiniment. kubectl describe node <name> montre que le plugin réseau n'est pas prêt.
Causes :
- Les pods CNI plantent (
kubectl get pods -n kube-systemmontreCrashLoopBackOff). - La configuration CNI ne correspond pas au CIDR des pods.
- Le nœud a plusieurs adresses IP internes et le CNI choisit la mauvaise.
Solution :
- Vérifiez les journaux des pods CNI :
kubectl logs -n kube-system <cni-pod> --tail=50. - Vérifiez que le CIDR des pods dans le manifeste CNI correspond à votre option
--pod-network-cidr. Pour Calico, modifiez la variable d'environnementCALICO_IPV4POOL_CIDR. - Si plusieurs interfaces, définissez
nodeAddressAutodetectionV4dans le manifeste CNI sur l'interface ou la plage IP correcte.
Récupération : Réappliquez le manifeste CNI après correction. Si cela échoue, supprimez toutes les ressources CNI (kubectl delete -f <manifest>) et réinstallez après avoir corrigé la configuration.
Défaillance : La commande de jointure expire ou le jeton est introuvable
Symptômes : Les nœuds workers ne peuvent pas se joindre car le jeton est invalide. kubeadm token list ne montre aucun jeton.
Solution : Générez un nouveau jeton et imprimez la commande de jointure :
sudo kubeadm token create --print-join-command
Utilisez la sortie sur le nœud worker. Les jetons expirent après 24 heures par défaut. Pour des jetons à longue durée, utilisez --ttl=0 (non recommandé en production).
Vérification : Après toute récupération, exécutez kubectl get nodes et assurez-vous que le nœud récupéré affiche Ready. Ensuite, exécutez un pod simple pour confirmer l'ordonnancement et le réseau :
kubectl run test-pod --image=busybox --restart=Never --command -- sleep 3600
kubectl get pod test-pod
Supprimez le pod de test lorsque vous avez terminé.
Pièges courants et comment les éviter
Même les opérateurs expérimentés tombent dans ces pièges. Les connaître à l'avance vous fait gagner des heures.
Piège 1 : Ignorer les erreurs de vérification préalable avec --ignore-preflight-errors=all
Bien que cela puisse faire démarrer un cluster rapidement, les vérifications ignorées causent souvent des défaillances subtiles plus tard. Par exemple, ignorer la vérification numcpu sur une VM à faibles ressources conduit à des timeouts du serveur API sous charge. Au lieu de cela, corrigez la condition sous-jacente ou utilisez une ignorance étroitement ciblée avec un nom de vérification spécifique, comme --ignore-preflight-errors=NumCPU uniquement si vous comprenez le risque.
Piège 2 : Utiliser un runtime de conteneurs non pris en charge ou une version non compatible
Kubernetes a déprécié le support Docker dans la version 1.20 ; il nécessite cri-dockerd. De nombreux utilisateurs essaient encore --container-runtime=docker dans la version 1.30 et obtiennent des erreurs. Tenez-vous-en à containerd ou CRI-O, qui sont les runtimes principalement pris en charge.
Piège 3 : Ne pas définir un CIDR de réseau de pods pendant l'init
Si vous omettez --pod-network-cidr, le plugin CNI peut choisir par défaut un CIDR qui entre en conflit avec votre réseau ou échoue silencieusement. Spécifiez toujours un CIDR qui correspond aux valeurs par défaut du CNI. Pour Flannel, utilisez 10.244.0.0/16 ; pour Calico, utilisez 192.168.0.0/16 sauf personnalisation.
Piège 4 : Exécuter kubeadm init en tant qu'utilisateur non root sans sudo
kubeadm nécessite les privilèges root car il écrit des fichiers système et configure systemd. L'exécuter sans sudo donne une erreur de permission déroutante. Utilisez toujours sudo et assurez-vous que votre utilisateur est dans le groupe sudo.
Piège 5 : Réutiliser un ancien fichier de configuration kubeadm après une mise à niveau de version
Les versions de l'API de configuration changent (par exemple, v1beta2 à v1beta3). L'utilisation d'un ancien fichier provoque une erreur no kind "InitConfiguration" is registered for version "kubeadm.k8s.io/v1beta2". Régénérez les valeurs par défaut avec kubeadm config print init-defaults pour votre version actuelle et migrez vos valeurs personnalisées.
Piège 6 : Ne pas vérifier les règles de pare-feu pour le port 6443
Les workers et kubectl ont besoin d'accéder au port du serveur API. Sur certaines VM cloud, un pare-feu hôte bloque le port 6443 même si les groupes de sécurité l'autorisent. Vérifiez avec sudo ufw status ou sudo firewall-cmd --list-all. S'il est bloqué, autorisez-le :
sudo ufw allow 6443/tcp
Ou pour firewalld :
sudo firewall-cmd --permanent --add-port=6443/tcp
sudo firewall-cmd --reload
Liste de contrôle des opérations
Utilisez cette liste de contrôle avant et après chaque tentative de kubeadm init. Chaque élément comprend un responsable (une seule personne) et une fréquence de révision.
Liste de contrôle pré-init
| # | Tâche | Commande / Vérification | Résultat attendu | Responsable | Révision |
|---|---|---|---|---|---|
| 1 | Enregistrer les versions de Kubernetes et du runtime | kubeadm version && crictl version | Versions dans la plage prise en charge | Ingénieur DevOps, Priya Shah | Avant chaque init |
| 2 | Désactiver le swap | sudo swapoff -a; free -h | La ligne Swap affiche 0B | Administrateur de cluster, Marcus Lee | Avant chaque init |
| 3 | Charger les modules du noyau et définir sysctl | sudo modprobe br_netfilter; sysctl net.bridge.bridge-nf-call-iptables | Sortie 1 pour chaque | Ingénieur DevOps, Priya Shah | Avant chaque init |
| 4 | Confirmer le socket du runtime de conteneurs | sudo crictl info | grep -A2 "endpoint" | Le chemin du socket correspond à votre runtime | Administrateur de cluster, Marcus Lee | Avant chaque init |
| 5 | Générer un fichier de configuration kubeadm frais | kubeadm config print init-defaults > kubeadm-init-$(hostname).yaml | Fichier créé et modifiable | Ingénieur DevOps, Priya Shah | Avant chaque init |
| 6 | Exécuter les vérifications préalables seules | sudo kubeadm init phase preflight --config | Toutes les vérifications passent | Administrateur de cluster, Marcus Lee | Avant chaque init |
Liste de contrôle post-init
| # | Tâche | Commande / Vérification | Résultat attendu | Responsable | Révision |
|---|---|---|---|---|---|
| 1 | Copier la kubeconfig et tester l'accès | kubectl get nodes | Liste le nœud du plan de contrôle | Ingénieur DevOps, Priya Shah | Immédiatement après l'init |
| 2 | Vérifier que tous les pods système s'exécutent | kubectl get pods -n kube-system | Aucun CrashLoopBackOff ou Pending | Administrateur de cluster, Marcus Lee | Immédiatement après l'init puis hebdomadaire |
| 3 | Installer le CNI et confirmer que le nœud est Ready | kubectl apply -f <cni-manifest>; kubectl get nodes | L'état du nœud est Ready | Ingénieur DevOps, Priya Shah | Immédiatement après l'init |
| 4 | Tester le déploiement d'une charge de travail | kubectl run test-pod ... | Le pod est en Running et accessible | Administrateur de cluster, Marcus Lee | Immédiatement après l'init |
| 5 | Enregistrer le journal d'init et la configuration | Copier /var/log/kubeadm-init.log et le fichier de configuration vers une sauvegarde sécurisée | Les fichiers existent et sont récupérables | Ingénieur DevOps, Priya Shah | Après une init réussie, puis audit trimestriel |
Notes sur les responsables : Choisissez une seule personne, pas une équipe, pour éviter la dilution des responsabilités. Le responsable met à jour la liste de contrôle et dirige la révision à la fréquence indiquée. Si une vérification échoue, le responsable enregistre le mode de défaillance et l'action corrective dans le runbook.
Conclusion
Les erreurs de kubeadm init sont rarement mystérieuses ; elles proviennent de prérequis ignorés, de configurations inadéquates ou d'une préparation incomplète de l'environnement. Le flux de travail de ce guide - observer d'abord, changer une chose à la fois, vérifier et documenter - réduit les temps d'arrêt et renforce la confiance opérationnelle.
Commencez par l'inventaire des versions et de l'environnement, puis utilisez un fichier de configuration pour rendre l'init reproductible. Lorsqu'une erreur se produit, lisez le message spécifique, corrigez la cause fondamentale et vérifiez avec le contrôle approprié. Les pièges courants comme ignorer les erreurs de vérification préalable ou utiliser un runtime non pris en charge sont évitables avec la bonne liste de contrôle et l'attribution d'un responsable.
Après une init réussie, installez un CNI, testez une charge de travail et sécurisez vos fichiers de configuration. Enfin, planifiez une révision mensuelle de la santé du cluster et revenez à ce guide chaque fois qu'une nouvelle défaillance apparaît. Kubernetes est une cible mouvante, mais un processus de dépannage discipliné vous garde en contrôle.