Introduction
Dépanner un cluster Kubernetes initialisé avec kubeadm signifie passer d'un symptôme observé à une correction vérifiée sans aggraver la situation. Le chemin le plus rapide n'est presque jamais un kubeadm reset aveugle. C'est une séquence de vérifications en lecture seule qui confirment la version exacte, la topologie et l'état des composants avant de modifier le moindre fichier.
Cet article s'adresse aux développeurs, consultants DevOps et petites équipes plateforme qui exploitent des clusters kubeadm autogérés. Il relie les modes de défaillance courants de kubeadm à des commandes concrètes, des sorties attendues, l'interprétation des journaux et des étapes de récupération sûres. Chaque exemple utilise des variables pour les noms d'hôte, les chemins et les versions afin que vous puissiez l'adapter à votre environnement sans exposer de secrets de production.
Les règles directrices sont : observer avant de modifier, limiter le rayon d'impact, vérifier après chaque modification et documenter le plan de récupération avant d'en avoir besoin.
Inventaire des versions et de l'environnement
Avant de toucher à quoi que ce soit, capturez l'état actuel. Vous devez savoir exactement quelle version de Kubernetes, quelle version de kubeadm, quel runtime de conteneurs et quel système d'exploitation vous utilisez. Enregistrez ensuite la topologie des nœuds et la configuration kubeadm actuelle.
Commencez par des commandes en lecture seule :
# Versions client et serveur Kubernetes
kubectl version --client --output=yaml
# Versions kubeadm et kubelet
kubeadm version -o json
kubelet --version
# Système d'exploitation et noyau
cat /etc/os-release
uname -r
# Runtime de conteneurs (exemple : containerd)
ctr version
La sortie attendue pour kubeadm version -o json sur un nœud sain ressemble à ceci :
{
"clientVersion": {
"major": "1",
"minor": "30",
"gitVersion": "v1.30.1",
"gitCommit": "ac3b1c5e035d74a5c1e6f7d4d1abf0e2a8f5e7b1",
"gitTreeState": "clean",
"buildDate": "2024-05-15T12:00:00Z",
"goVersion": "go1.22.2",
"compiler": "gc",
"platform": "linux/amd64"
}
}
Si kubeadm version échoue avec command not found, alors kubeadm n'est pas installé sur ce nœud. C'est un problème différent d'un décalage de version. Installez le paquet approprié pour votre système d'exploitation, mais seulement après avoir documenté que ce nœud ne fait pas encore partie du plan de contrôle.
Vérifiez maintenant la topologie du cluster et l'état des nœuds :
# Depuis un nœud du plan de contrôle fonctionnel
kubectl get nodes -o wide
# Informations détaillées sur un nœud
kubectl describe node control-plane-1
Recherchez les conditions NotReady des nœuds. kubectl describe node affiche la raison sous Conditions. Les raisons courantes sont KubeletNotReady, ContainerRuntimeUnhealthy ou NetworkUnavailable.
Ensuite, enregistrez la configuration kubeadm active. La configuration du cluster générée pendant kubeadm init est stockée dans la ConfigMap kube-system/kubeadm-config. Obtenez-la en lecture seule :
kubectl -n kube-system get configmap kubeadm-config -o yaml
Faites attention à ClusterConfiguration.kubernetesVersion, ClusterConfiguration.controlPlaneEndpoint et ClusterConfiguration.networking.podSubnet. Par exemple :
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.30.1
controlPlaneEndpoint: "kube-apiserver.example.com:6443"
networking:
podSubnet: "10.244.0.0/16"
serviceSubnet: "10.96.0.0/12"
Ne modifiez pas cette ConfigMap directement. Copiez-la dans un fichier local pour référence uniquement.
Enfin, enregistrez les horodatages pour une corrélation ultérieure. date -u affiche l'heure UTC actuelle. Ajoutez toutes ces informations à vos notes d'incident.
Chemin de configuration sûr
Kubeadm stocke la configuration du cluster à trois endroits que vous pourriez avoir besoin de modifier : le fichier de configuration kubeadm sur le disque, la ConfigMap kubeadm-config et la configuration du kubelet. Ne modifiez qu'un seul de ces éléments à la fois et gardez toujours une sauvegarde.
Sauvegarder avant de modifier
Pour les fichiers sur le disque, utilisez cp -a pour préserver les permissions et la propriété :
sudo cp -a /etc/kubernetes/kubelet.conf /etc/kubernetes/kubelet.conf.bak-$(date +%Y%m%d)
sudo cp -a /var/lib/kubelet/config.yaml /var/lib/kubelet/config.yaml.bak-$(date +%Y%m%d)
Pour la ConfigMap kubeadm-config, exportez une copie propre :
kubectl -n kube-system get configmap kubeadm-config -o yaml > kubeadm-config-backup.yaml
Stockez les sauvegardes en dehors de /etc/kubernetes afin qu'un reset raté ne les supprime pas.
Modifier la configuration du kubelet en toute sécurité
Le fichier de configuration du kubelet /var/lib/kubelet/config.yaml contrôle le comportement d'exécution tel que maxPods, systemReserved et evictionHard. Par exemple, pour augmenter le nombre maximal de pods par nœud de la valeur par défaut 110 à 150 :
Extrait du fichier original :
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
maxPods: 110
Modifiez uniquement le champ maxPods à 150. Redémarrez ensuite kubelet :
sudo systemctl restart kubelet
sudo systemctl status kubelet --no-pager
Vérifiez que la configuration active a pris effet en examinant les drapeaux du processus kubelet :
ps -ef | grep kubelet | grep -o 'config.yaml'
# Sortie attendue contient : --config=/var/lib/kubelet/config.yaml
Confirmez également que le nœud rapporte toujours Ready :
kubectl get node worker-1
# Attendu : NAME STATUS ROLES AGE VERSION
# worker-1 Ready <none> 12d v1.30.1
Si le nœud devient NotReady ou si kubelet ne démarre pas, annulez la modification en restaurant la sauvegarde et en redémarrant kubelet à nouveau.
Mettre à jour la configuration du cluster kubeadm
Les mises à niveau à l'échelle du cluster ou les changements de feature gates se font avec kubeadm upgrade apply ou kubeadm upgrade node. Ne modifiez pas la ConfigMap kubeadm-config à la main sauf en cas d'urgence, et même alors documentez pendant l'opération.
Pour prévisualiser une mise à niveau sans rien changer :
sudo kubeadm upgrade plan
La sortie attendue montre à la fois la version actuelle et la version cible de Kubernetes, par exemple :
COMPONENT CURRENT TARGET
kubelet v1.29.2 v1.30.1
kubeadm v1.29.2 v1.30.1
kubectl v1.29.2 v1.30.1
N'appliquez jamais une mise à niveau sans lire les notes de version pour les changements cassants spécifiques à votre environnement.
Vérification et diagnostic
Une fois que vous comprenez l'état actuel, utilisez des diagnostics ciblés pour identifier le composant défaillant. Les sources les plus courantes de problèmes kubeadm sont le kubelet qui ne démarre pas, les pods statiques du plan de contrôle qui ne deviennent pas prêts et les problèmes de plugin réseau.
Vérifier l'état et les journaux du kubelet
Le kubelet est la première chose à échouer lorsque les certificats expirent, que le runtime de conteneurs est indisponible ou que la configuration du kubelet est invalide.
sudo systemctl status kubelet --no-pager -l
Un kubelet sain affiche active (running). S'il est dans l'état failed, consultez les journaux :
sudo journalctl -u kubelet -n 50 --no-pager -l
Messages d'erreur courants et leurs causes probables :
failed to run Kubelet: misconfiguration: kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs"-- incompatibilité de pilote cgroup. Corrigez en définissantcgroupDriver: systemddans la configuration du kubelet ou du runtime de conteneurs.error: failed to start container "kubelet": Error response from daemon: ...-- le runtime de conteneurs ne fonctionne pas ou est mal configuré. Vérifiezsudo systemctl status containerdousudo systemctl status docker.x509: certificate signed by unknown authority-- signifie souvent que le CA du cluster a changé ou quekubelet.confest corrompu. Régénérez aveckubeadm init phase kubeconfig kubeletou copiez depuis un autre nœud, mais soyez extrêmement prudent avec les secrets.
Inspecter les pods statiques du plan de contrôle
Les composants du plan de contrôle s'exécutent comme pods statiques dans /etc/kubernetes/manifests. S'ils plantent, le cluster perd l'accès à l'API.
Listez les pods statiques :
ls -la /etc/kubernetes/manifests/
Fichiers attendus : etcd.yaml, kube-apiserver.yaml, kube-controller-manager.yaml, kube-scheduler.yaml.
Consultez les journaux du pod de l'API server même si kubectl ne répond pas :
# Utilisation de crictl car kubelet gère les pods statiques via CRI
sudo crictl ps -a | grep kube-apiserver
Obtenez l'ID du conteneur puis :
sudo crictl logs <container-id> --tail=100
Surveillez les erreurs comme etcdserver: request timed out (etcd en panne), connection refused (réseau) ou failed to create listener: failed to listen on 0.0.0.0:6443 (port déjà utilisé).
Vérifier le point de terminaison de l'API server
Depuis un nœud du plan de contrôle, testez l'API server local :
curl -k https://127.0.0.1:6443/healthz?verbose
La sortie attendue inclut [+]ping ok et [+]log ok. Si vous obtenez connection refused, l'API server ne fonctionne pas. Si vous obtenez une erreur de certificat, cela peut être un décalage d'heure ou de CA.
Vérifier le réseau du cluster
Une défaillance du réseau des pods se manifeste par CNI plugin not initialized dans les journaux du kubelet ou des nœuds bloqués NotReady après la jointure. Confirmez que les pods de votre plugin CNI fonctionnent :
kubectl get pods -n kube-system | grep -E 'calico|flannel|weave|cilium'
Pour Flannel, les pods attendus sont kube-flannel-ds-xxxxx avec 1/1 Running. S'ils sont en CrashLoopBackOff, consultez leurs journaux :
kubectl -n kube-system logs ds/kube-flannel-ds --tail=50
Erreur Flannel courante : failed to find any valid interface to use lorsque plusieurs interfaces existent. Corrigez en ajoutant --iface=eth1 au daemonset flannel ou en définissant --iface-regex.
Modes de défaillance et récupération
Lorsque quelque chose est déjà cassé, suivez un chemin de récupération structuré. L'ordre compte : rétablissez d'abord le service, puis enquêtez sur la cause profonde, puis appliquez la prévention.
Mode de défaillance 1 : échec de la rotation des certificats du kubelet
Symptôme : Les nœuds deviennent NotReady, kubectl get nodes affiche SchedulingDisabled ou NotReady pour tous les workers, les journaux du kubelet montrent certificate has expired or is not yet valid.
Cause : Les certificats client du kubelet sont valables 1 an par défaut et peuvent échouer à tourner si l'approbation de la demande de signature de certificat (CSR) n'est pas automatique.
Récupération :
- Vérifiez les CSR en attente :
kubectl get csr
La sortie attendue montre des CSR en attente avec le statut Pending pour chaque nœud.
- Approuvez tous les CSR en attente :
kubectl get csr --no-headers | awk '{print $1}' | xargs -I {} kubectl certificate approve {}
- Vérifiez que les nœuds reviennent à Ready :
kubectl get nodes
Si l'approbation automatique des CSR est absente, implémentez un contrôleur comme kubelet-csr-approver ou ajustez les drapeaux de votre kube-controller-manager.
Mode de défaillance 2 : répertoire de données etcd corrompu
Symptôme : kubectl get nodes renvoie The connection to the server 192.168.1.10:6443 was refused - did you specify the right host or port? et les journaux du pod API server montrent etcdmain: cannot access data directory.
Cause : Disque plein sur le répertoire de données etcd ou suppression accidentelle de /var/lib/etcd.
Récupération :
- Confirmez que le pod etcd est en boucle de crash :
sudo crictl ps -a | grep etcd
- Vérifiez l'espace disque :
df -h /var/lib/etcd
- Si le disque est plein, arrêtez le pod etcd en déplaçant temporairement le manifeste :
sudo mv /etc/kubernetes/manifests/etcd.yaml /tmp/etcd.yaml.bak
- Libérez de l'espace ou restaurez à partir d'une sauvegarde etcd. Si aucune sauvegarde, vous devez reconstruire le cluster. C'est pourquoi les sauvegardes etcd sont non négociables.
- Restaurez etcd à partir d'un instantané (seulement si vous en avez un) :
sudo ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db --data-dir /var/lib/etcd-restore
sudo mv /var/lib/etcd-restore /var/lib/etcd
sudo mv /tmp/etcd.yaml.bak /etc/kubernetes/manifests/etcd.yaml
- Attendez que l'API server revienne, puis vérifiez avec
kubectl get nodes.
Mode de défaillance 3 : échec de la jointure d'un nœud worker avec erreur de jeton
Symptôme : Sur un nouveau worker, kubeadm join se termine par error execution phase preflight: couldn't validate the identity of the API Server: expected a 32byte but got 0 ou token not found.
Cause : Le jeton de jointure a expiré (24 heures par défaut) ou le hachage CA ne correspond pas.
Récupération :
- Sur le plan de contrôle, créez un nouveau jeton :
sudo kubeadm token create --print-join-command
Sortie attendue :
kubeadm join 10.0.0.10:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:1a2b3c...
- Exécutez cette commande exacte sur le nouveau worker avec sudo.
- Vérifiez que le nœud se joint :
kubectl get nodes
Si le hachage CA ne correspond toujours pas, vous pouvez avoir plusieurs clusters ou un ca.crt obsolète. Inspectez manuellement le hachage du certificat :
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
Comparez avec le hachage dans la commande de jointure.
Liste de contrôle opérationnelle
Utilisez cette liste de contrôle lors de toute session de dépannage kubeadm. Elle est ordonnée du moins invasif au plus invasif.
| Étape | Action | Commande | Résultat attendu | Récupération en cas d'échec |
|---|---|---|---|---|
| 1 | Vérifier les versions | kubeadm version -o json | Sortie JSON de version | Installer ou mettre à niveau kubeadm |
| 2 | Vérifier l'état des nœuds | kubectl get nodes | Tous les nœuds Ready | Diagnostiquer kubelet, runtime ou réseau |
| 3 | Vérifier l'état du kubelet | sudo systemctl status kubelet | active (running) | Redémarrer kubelet, inspecter les journaux |
| 4 | Vérifier la santé de l'API | curl -k https://127.0.0.1:6443/healthz?verbose | ok pour tous les contrôles | Inspecter les journaux du pod API server |
| 5 | Vérifier les pods statiques | sudo crictl ps -a | grep -E 'etcd|kube-api|kube-controller|kube-scheduler' | Tous en cours d'exécution | Redémarrer kubelet pour re-tirer les manifestes |
| 6 | Vérifier les CSR en attente | kubectl get csr | Aucun CSR en attente | Approuver les CSR ou installer un approbateur |
| 7 | Vérifier l'espace disque | df -h /var/lib/etcd /var/lib/kubelet | > 20% libre | Nettoyer ou étendre le disque |
| 8 | Vérifier les journaux des pods | kubectl -n kube-system logs <pod-name> --tail=50 | Aucune erreur répétée | Corriger le problème sous-jacent, puis redémarrer le pod |
Parcourez la liste de contrôle de haut en bas. Ne sautez pas à l'étape 8 sans faire les étapes 1 à 7 d'abord. La liste de contrôle est également utile comme document de revue post-incident.
Conclusion
Le dépannage kubeadm n'est pratique que lorsque chaque étape est versionnée, observable et réversible là où la technologie le permet. Copier une commande d'un forum sans comprendre la sortie attendue et le chemin de récupération n'est pas une procédure opérationnelle ; c'est un pari.
Comme prochaine étape, choisissez un diagnostic à faible risque de cet article, comme vérifier kubeadm version -o json ou kubectl get csr. Enregistrez l'état actuel, exécutez la commande, comparez le résultat avec le signal attendu et notez ce que vous feriez en cas d'échec.
Un flux de travail fiable rend la défaillance visible, protège les valeurs sensibles, limite les changements à la ressource prévue et définit la vérification de récupération avant qu'un incident ne force la décision. Gardez ces habitudes en place, et vos clusters kubeadm passeront beaucoup moins de temps dans des états de défaillance mystérieux.