
Le troubleshooting représente 30% de l’examen CKA. Ce guide présente une méthodologie systématique pour diagnostiquer et résoudre les problèmes les plus courants : Pods en échec, problèmes de scheduling, erreurs réseau, et défaillances de cluster.
Méthodologie générale
Section intitulée « Méthodologie générale »Appliquez cette approche systématique pour tout problème Kubernetes :
- Observer — Quel est l’état actuel ? (
kubectl get,kubectl describe) - Logs — Que disent les logs ? (
kubectl logs, journald) - Events — Quels événements récents ? (
kubectl get events) - Comparer — L’état actuel correspond-il à l’état désiré ?
- Isoler — Quel composant est en cause ?
- Corriger — Appliquer le fix et valider
Commandes essentielles
Section intitulée « Commandes essentielles »# Alias recommandésalias k=kubectlalias kd='kubectl describe'alias kl='kubectl logs'alias kg='kubectl get'
# Vue d'ensemble rapidekubectl get all -Akubectl get events -A --sort-by='.lastTimestamp' | tail -20
# État des nœudskubectl get nodes -o widekubectl top nodes
# État des Podskubectl get pods -A -o wide | grep -v RunningSection 1 — Troubleshooting Pods
Section intitulée « Section 1 — Troubleshooting Pods »États des Pods et leur signification
Section intitulée « États des Pods et leur signification »| État | Signification | Action |
|---|---|---|
Pending | En attente de scheduling | Vérifier ressources, affinités, taints |
ContainerCreating | Image en cours de pull ou volumes montés | Vérifier events, image, PVC |
Running | Conteneur actif | Vérifier readiness, logs si problème |
CrashLoopBackOff | Redémarre en boucle | Vérifier logs, commande, ressources |
Error | Conteneur terminé avec erreur | Vérifier logs du conteneur |
ImagePullBackOff | Échec de téléchargement image | Vérifier nom image, credentials |
ErrImagePull | Erreur initiale de pull | Vérifier registry, réseau |
Terminating | En cours de suppression | Vérifier finalizers, preStop hooks |
Pod Pending
Section intitulée « Pod Pending »Un Pod reste Pending quand le scheduler ne trouve pas de nœud approprié.
# Diagnostickubectl describe pod <pod-name> | grep -A10 Events
# Messages courants et solutions# "Insufficient cpu" → Augmenter ressources cluster ou réduire requests# "Insufficient memory" → Idem# "node(s) had untolerated taint" → Ajouter toleration ou retirer taint# "node(s) didn't match Pod's node affinity" → Vérifier labels des nœuds# "persistentvolumeclaim not found" → Créer le PVC manquantChecklist Pending :
# Ressources disponibles sur les nœudskubectl describe nodes | grep -A5 "Allocated resources"
# Taints des nœudskubectl get nodes -o custom-columns='NAME:.metadata.name,TAINTS:.spec.taints[*].key'
# PVC en attentekubectl get pvc -A | grep -v BoundPod CrashLoopBackOff
Section intitulée « Pod CrashLoopBackOff »Le conteneur démarre mais crash immédiatement, Kubernetes le redémarre en boucle.
# Logs du crash actuelkubectl logs <pod-name>
# Logs du crash précédentkubectl logs <pod-name> --previous
# Si multi-containerkubectl logs <pod-name> -c <container-name> --previousCauses fréquentes :
| Cause | Diagnostic | Solution |
|---|---|---|
| Command/Args invalides | Logs montrent erreur de syntaxe | Corriger command/args |
| Config manquante | ”file not found”, “env not set” | Vérifier ConfigMaps/Secrets |
| Dépendance indisponible | ”connection refused” | Vérifier Services dépendants |
| OOMKilled | kubectl describe pod → OOMKilled | Augmenter memory limit |
| Permissions | ”permission denied” | Vérifier securityContext, volumes |
# Vérifier si OOMKilledkubectl get pod <pod> -o jsonpath='{.status.containerStatuses[0].lastState.terminated.reason}'
# Détail du restartkubectl describe pod <pod> | grep -A5 "Last State"Pod ImagePullBackOff
Section intitulée « Pod ImagePullBackOff »Kubernetes ne parvient pas à télécharger l’image.
# Diagnostickubectl describe pod <pod> | grep -A5 "Events"
# Causes fréquentes :# - Image inexistante : vérifier le nom exact# - Registry privé : vérifier imagePullSecrets# - Réseau : vérifier l'accès au registry depuis les nœudsVérifier les credentials :
# Lister les secrets de type docker-registrykubectl get secrets -A -o json | jq -r '.items[] | select(.type=="kubernetes.io/dockerconfigjson") | "\(.metadata.namespace)/\(.metadata.name)"'
# Vérifier qu'un Pod utilise le bon secretkubectl get pod <pod> -o jsonpath='{.spec.imagePullSecrets}'Debug avec ephemeral containers
Section intitulée « Debug avec ephemeral containers »Depuis Kubernetes 1.25+, vous pouvez injecter un conteneur de debug dans un Pod running :
# Ajouter un conteneur de debugkubectl debug -it <pod-name> --image=busybox:1.36 --target=<container-name>
# Debug avec une copie du Podkubectl debug <pod-name> -it --copy-to=debug-pod --container=debug --image=busybox:1.36Section 2 — Troubleshooting Nodes
Section intitulée « Section 2 — Troubleshooting Nodes »États des nœuds
Section intitulée « États des nœuds »# Vue d'ensemblekubectl get nodes -o wide
# Détail d'un nœudkubectl describe node <node-name>
# Conditions importanteskubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{range .status.conditions[*]}{.type}={.status}{" "}{end}{"\n"}{end}'Conditions des nœuds
Section intitulée « Conditions des nœuds »| Condition | True = problème | Diagnostic |
|---|---|---|
MemoryPressure | ⚠️ | Mémoire insuffisante |
DiskPressure | ⚠️ | Disque plein |
PIDPressure | ⚠️ | Trop de processus |
NetworkUnavailable | ⚠️ | CNI non configuré |
Ready | ✅ Normal | Nœud opérationnel |
Node NotReady
Section intitulée « Node NotReady »# Diagnostic rapidekubectl describe node <node> | grep -A5 Conditions
# Vérifier kubelet sur le nœudssh <node> "systemctl status kubelet"ssh <node> "journalctl -u kubelet --since '10 minutes ago' | tail -50"
# Vérifier les certificatsssh <node> "openssl x509 -in /var/lib/kubelet/pki/kubelet.crt -noout -dates"Causes fréquentes :
| Symptôme | Cause probable | Solution |
|---|---|---|
| kubelet stopped | Service crashé | systemctl restart kubelet |
| certificate expired | Certificats expirés | Renouveler avec kubeadm |
| connection refused | API server inaccessible | Vérifier réseau, firewall |
| disk full | /var/lib/kubelet plein | Nettoyer images/logs |
Ressources insuffisantes
Section intitulée « Ressources insuffisantes »# Voir l'utilisation CPU/mémoirekubectl top nodes
# Détail par nœudkubectl describe node <node> | grep -A10 "Allocated resources"
# Pods sur un nœud spécifiquekubectl get pods -A --field-selector spec.nodeName=<node> -o wideSection 3 — Troubleshooting Services et Networking
Section intitulée « Section 3 — Troubleshooting Services et Networking »Service ne route pas vers les Pods
Section intitulée « Service ne route pas vers les Pods »-
Vérifier que le Service existe et a des endpoints
Fenêtre de terminal kubectl get svc <service>kubectl get endpoints <service> -
Vérifier que les labels correspondent
Fenêtre de terminal # Labels du selector du Servicekubectl get svc <service> -o jsonpath='{.spec.selector}'# Labels des Podskubectl get pods -l <label-selector> --show-labels -
Vérifier que les Pods sont Ready
Fenêtre de terminal kubectl get pods -l <label-selector># Un Pod non-Ready n'apparaît pas dans les endpoints -
Tester la connectivité depuis un Pod
Fenêtre de terminal kubectl run debug --rm -it --image=busybox:1.36 -- wget -qO- --timeout=2 <service>:<port>
Endpoints vides
Section intitulée « Endpoints vides »# Diagnostickubectl get endpoints <service># Si ENDPOINTS est <none> :
# 1. Vérifier le selector du Servicekubectl get svc <service> -o yaml | grep -A5 selector
# 2. Vérifier que des Pods matchent ce selectorkubectl get pods -l <key>=<value>
# 3. Vérifier que ces Pods sont Readykubectl get pods -l <key>=<value> -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}'DNS ne résout pas
Section intitulée « DNS ne résout pas »# Tester la résolution DNS depuis un Podkubectl run dnstest --rm -it --image=busybox:1.36 -- nslookup kubernetes.default
# Vérifier que CoreDNS fonctionnekubectl get pods -n kube-system -l k8s-app=kube-dnskubectl logs -n kube-system -l k8s-app=kube-dns
# Vérifier la configuration DNS d'un Podkubectl exec <pod> -- cat /etc/resolv.confNetworkPolicy bloque le trafic
Section intitulée « NetworkPolicy bloque le trafic »# Lister les NetworkPolicieskubectl get netpol -A
# Détail d'une policykubectl describe netpol <name>
# Test de connectivitékubectl run tester --rm -it --image=nicolaka/netshoot -- curl -v <target>:<port>Section 4 — Troubleshooting Control Plane
Section intitulée « Section 4 — Troubleshooting Control Plane »API Server non accessible
Section intitulée « API Server non accessible »# Depuis un nœud control planekubectl cluster-info
# Vérifier les composantskubectl get componentstatuses # Déprécié mais encore utilekubectl get pods -n kube-system | grep -E 'api|controller|scheduler|etcd'
# Logs API serverkubectl logs -n kube-system kube-apiserver-<node># Ou sur le nœud :journalctl -u kubelet | grep apiserveretcd en échec
Section intitulée « etcd en échec »# État des Pods etcdkubectl get pods -n kube-system -l component=etcd
# Logs etcdkubectl logs -n kube-system etcd-<node>
# Santé du cluster etcd (depuis un control plane)ETCDCTL_API=3 etcdctl --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 \ endpoint healthScheduler ou Controller Manager
Section intitulée « Scheduler ou Controller Manager »# Pods kube-systemkubectl get pods -n kube-system | grep -E 'scheduler|controller'
# Logskubectl logs -n kube-system kube-scheduler-<node>kubectl logs -n kube-system kube-controller-manager-<node>
# Vérifier les manifests statiquesls -la /etc/kubernetes/manifests/Section 5 — Troubleshooting Applications
Section intitulée « Section 5 — Troubleshooting Applications »Liveness/Readiness probe failures
Section intitulée « Liveness/Readiness probe failures »# Voir les eventskubectl describe pod <pod> | grep -A10 Events
# Messages courants :# "Liveness probe failed" → L'app ne répond pas, Pod sera redémarré# "Readiness probe failed" → L'app n'est pas prête, retirée des endpointsChecklist probes :
# Tester manuellement l'endpoint de probekubectl exec <pod> -- wget -qO- http://localhost:<port>/<path>kubectl exec <pod> -- curl -s http://localhost:<port>/<path>
# Vérifier la configuration des probeskubectl get pod <pod> -o jsonpath='{.spec.containers[0].livenessProbe}'kubectl get pod <pod> -o jsonpath='{.spec.containers[0].readinessProbe}'Application lente ou timeout
Section intitulée « Application lente ou timeout »# Ressources utilisées vs limiteskubectl top pod <pod>kubectl get pod <pod> -o jsonpath='{.spec.containers[0].resources}'
# Throttling CPU (si limite trop basse)kubectl exec <pod> -- cat /sys/fs/cgroup/cpu/cpu.cfs_throttled_periods
# Logs applicatifskubectl logs <pod> --tail=100 -fSection 6 — Exercices CKA Troubleshooting
Section intitulée « Section 6 — Exercices CKA Troubleshooting »Exercice 1 : Pod bloqué Pending (3 min)
Section intitulée « Exercice 1 : Pod bloqué Pending (3 min) »Un Pod stuck-pod est Pending depuis 5 minutes. Identifiez la cause et corrigez.
kubectl apply -f - <<'EOF'apiVersion: v1kind: Podmetadata: name: stuck-podspec: nodeSelector: disktype: nvme containers: - name: nginx image: nginx:1.25EOFSolution
# Diagnostickubectl describe pod stuck-pod | grep -A10 Events# "0/X nodes are available: X node(s) didn't match Pod's node affinity"
# Vérifier les labels des nœudskubectl get nodes --show-labels | grep disktype# Aucun nœud n'a le label disktype=nvme
# Solution A : Labelliser un nœudkubectl label node <node-name> disktype=nvme
# Solution B : Retirer le nodeSelectorkubectl patch pod stuck-pod --type='json' -p='[{"op": "remove", "path": "/spec/nodeSelector"}]'# Note : Patch de nodeSelector sur un Pod existant ne fonctionne pas, il faut recréer
# Solution pratique : Supprimer et recréer sans nodeSelectorkubectl delete pod stuck-podkubectl run stuck-pod --image=nginx:1.25Exercice 2 : CrashLoopBackOff (4 min)
Section intitulée « Exercice 2 : CrashLoopBackOff (4 min) »Diagnostiquez pourquoi ce Pod crash en boucle :
kubectl apply -f - <<'EOF'apiVersion: v1kind: Podmetadata: name: crash-podspec: containers: - name: app image: busybox:1.36 command: ['sh', '-c', 'cat /config/app.conf && sleep 3600']EOFSolution
# Diagnostickubectl describe pod crash-podkubectl logs crash-pod --previous# "cat: can't open '/config/app.conf': No such file or directory"
# Le fichier /config/app.conf n'existe pas
# Solution : Créer un ConfigMap et le monterkubectl create configmap app-config --from-literal=app.conf="key=value"
kubectl apply -f - <<'EOF'apiVersion: v1kind: Podmetadata: name: crash-pod-fixedspec: containers: - name: app image: busybox:1.36 command: ['sh', '-c', 'cat /config/app.conf && sleep 3600'] volumeMounts: - name: config mountPath: /config volumes: - name: config configMap: name: app-configEOF
kubectl delete pod crash-podExercice 3 : Service sans endpoints (4 min)
Section intitulée « Exercice 3 : Service sans endpoints (4 min) »Le Service web-svc ne route pas vers les Pods. Trouvez pourquoi.
kubectl apply -f - <<'EOF'apiVersion: apps/v1kind: Deploymentmetadata: name: webspec: replicas: 2 selector: matchLabels: app: web template: metadata: labels: app: webapp # Attention ici spec: containers: - name: nginx image: nginx:1.25---apiVersion: v1kind: Servicemetadata: name: web-svcspec: selector: app: web ports: - port: 80EOFSolution
# Diagnostickubectl get endpoints web-svc# ENDPOINTS: <none>
kubectl get svc web-svc -o jsonpath='{.spec.selector}'# {"app":"web"}
kubectl get pods --show-labels# app=webapp (pas app=web)
# Le selector du Service (app=web) ne matche pas les labels des Pods (app=webapp)
# Solution : Corriger les labels du Deploymentkubectl patch deployment web -p '{"spec":{"template":{"metadata":{"labels":{"app":"web"}}}}}'
# Vérifierkubectl get endpoints web-svc# Maintenant les endpoints apparaissentExercice 4 : Node NotReady (5 min)
Section intitulée « Exercice 4 : Node NotReady (5 min) »Simulez et diagnostiquez un nœud NotReady.
Solution (concept)
# Sur le nœud worker (SSH)sudo systemctl stop kubelet
# Sur le control plane, observerkubectl get nodes# Le nœud passe NotReady après ~40 secondes (node-monitor-grace-period)
kubectl describe node <worker> | grep -A5 Conditions# Ready: False - Kubelet stopped posting node status
# Diagnosticssh <worker> "systemctl status kubelet"# inactive (dead)
# Solutionssh <worker> "sudo systemctl start kubelet"
kubectl get nodes# ReadyChecklist récapitulative
Section intitulée « Checklist récapitulative »Pod qui ne démarre pas
Section intitulée « Pod qui ne démarre pas »kubectl get pod <name> # État actuelkubectl describe pod <name> | tail -30 # Eventskubectl logs <name> --previous # Logs du crash précédentkubectl get events --field-selector involvedObject.name=<name>Service non fonctionnel
Section intitulée « Service non fonctionnel »kubectl get svc <name> # Ports, ClusterIPkubectl get endpoints <name> # Pods backendkubectl get pods -l <selector> -o wide # État des Podskubectl run test --rm -it --image=busybox -- wget -qO- <svc>:<port>Nœud en échec
Section intitulée « Nœud en échec »kubectl describe node <name> | grep -A10 Conditionsssh <node> "systemctl status kubelet"ssh <node> "journalctl -u kubelet --since '10 min ago'"ssh <node> "df -h; free -m" # Ressources systèmeÀ retenir
Section intitulée « À retenir »- Toujours commencer par
kubectl describeetkubectl get events - Pod Pending = problème de scheduling (ressources, taints, affinités)
- CrashLoopBackOff = regarder
kubectl logs --previous - Service sans endpoints = vérifier que selector matche les labels des Pods Ready
- Node NotReady = vérifier kubelet et ses logs
- DNS = tester depuis un Pod avec nslookup/dig
- NetworkPolicy = peut bloquer silencieusement le trafic