Déboguer un Pod en échec : describe, logs, exec et port-forward
Une checklist reproductible pour comprendre pourquoi un Pod est Pending, plante ou ne répond pas.
Tôt ou tard, un Pod ne démarre pas, redémarre sans cesse, ou tourne sans répondre. La solution est presque toujours visible à l’aide de quelques commandes kubectl, utilisées dans le bon ordre. Ce guide vous donne cet ordre : lire le statut, demander les événements, lire les logs, entrer dans le conteneur, puis suivre le chemin réseau.
Lire d’abord le statut
Commencez par la colonne de statut :
kubectl get pods -o wide
Les états les plus courants, et où regarder en premier :
- Pending. Le Pod n’est pas assigné à un nœud. En général, il manque de CPU ou de mémoire, un quota est épuisé, ou un volume ne peut pas être lié.
describevous dira lequel. - ContainerCreating. Le nœud prépare le conteneur. Si cet état persiste, cherchez un volume manquant ou un téléchargement d’image lent.
- ErrImagePull / ImagePullBackOff. L’image ne peut pas être téléchargée, le plus souvent à cause d’une faute de frappe dans le nom ou le tag, ou d’identifiants manquants pour un registre privé.
- CrashLoopBackOff. Le conteneur démarre, se termine, puis est redémarré en boucle avec des délais croissants. L’application échoue : lisez ses logs.
- CreateContainerConfigError. Le Pod référence un ConfigMap, un Secret ou une clé qui n’existe pas.
- Running mais
READY 0/1. Le conteneur est lancé mais échoue à sa readiness probe. - OOMKilled (visible dans
describe). Le conteneur a dépassé sa limite de mémoire.
Demander à Kubernetes pourquoi : describe et les événements
kubectl describe pod POD_NAME
Descendez jusqu’à la section Events en bas. Elle se lit comme une chronologie : Scheduled, Pulling, Failed, BackOff. Des messages comme 0/3 nodes are available: insufficient cpu ou Failed to pull image "ngnix:1.25" nomment généralement le problème sans détour. Plus haut, regardez le State et le Last State de chaque conteneur pour les codes de sortie et les raisons. Pour une vue d’ensemble de ce qui s’est passé dans le namespace :
kubectl get events --sort-by=.metadata.creationTimestamp
Lire la sortie du conteneur
kubectl logs POD_NAME
kubectl logs POD_NAME -c CONTAINER_NAME
kubectl logs POD_NAME --all-containers
kubectl logs POD_NAME --previous
kubectl logs POD_NAME -f --since=10m --tail=100
Utilisez -c quand un Pod a plusieurs conteneurs, -f pour suivre en continu, --since et --tail pour limiter la sortie, et --previous pour lire les logs de la dernière instance plantée, ce dont vous avez besoin pour une boucle de plantage. Pour essayer, créez un Deployment dont le conteneur échoue volontairement :
kubectl create deployment crashy --image=busybox:1.36 -- \
sh -c 'echo starting; echo "fatal: DB_URL is not set" >&2; exit 1'
kubectl get pods -l app=crashy
kubectl logs deployment/crashy --previous
Le statut devient CrashLoopBackOff, et le log explique pourquoi. Nettoyez avec kubectl delete deployment crashy.
Gardez en tête que les logs appartiennent au Pod. Quand il est supprimé ou remplacé, ses logs disparaissent avec lui : pour conserver un historique, il faut un collecteur de logs comme Fluentd ou Fluent Bit qui les envoie vers un stockage durable.
Entrer dedans : exec, port-forward et cp
kubectl exec -it POD_NAME -- sh
kubectl exec POD_NAME -- env
kubectl port-forward pod/POD_NAME 8080:80
curl http://localhost:8080
kubectl cp POD_NAME:/path/to/file ./file
exec exécute une commande dans le conteneur, port-forward relie un port local à un port du Pod (cela fonctionne aussi avec svc/NAME), et cp copie des fichiers vers ou depuis le conteneur. Beaucoup d’images de production sont minimales et n’ont ni shell ni curl. Dans ce cas, kubectl debug -it POD_NAME --image=busybox:1.36 --target=CONTAINER_NAME attache un conteneur de débogage temporaire qui partage les namespaces du Pod.
Tout ce que vous modifiez dans un conteneur en cours d’exécution, comme l’édition d’un fichier de configuration, est perdu dès que le Pod est remplacé. Utilisez exec pour investiguer, mais appliquez la correction dans l’image, le manifeste ou un ConfigMap.
Remonter le chemin de la requête
Si le Pod semble sain mais que l’application est injoignable, suivez le chemin de l’intérieur vers l’extérieur :
- Le Pod est-il en cours d’exécution et
READY? Réparez d’abord le Pod. - Le sélecteur du Service correspond-il aux labels du Pod ?
kubectl get pods --show-labelsetkubectl describe service NAMEdoivent concorder. - Le Service a-t-il des endpoints ?
kubectl get endpointslices -l kubernetes.io/service-name=NAMEdoit lister des IP de Pods. Une liste vide indique un sélecteur qui ne correspond pas ou l’absence de Pods prêts. - Les ports correspondent-ils ? Le
targetPortdu Service doit être le port sur lequel le conteneur écoute réellement. - Est-ce que cela fonctionne depuis un autre Pod ?
kubectl run tmp --rm -it --image=busybox:1.36 --restart=Never -- wget -qO- http://NAME. Cela teste le DNS et le Service, et écarte tout ce qui est extérieur au cluster. - Une NetworkPolicy pourrait-elle bloquer le trafic ? Listez-les avec
kubectl get networkpolicy. - Enfin, vérifiez l’Ingress ou le load balancer externe placé devant.
Chaque étape circonscrit le problème à une seule couche, ce qui est plus rapide que de deviner.
Guides populaires
-
Ce qu'est Kubernetes et les problèmes qu'il résout Pourquoi les conteneurs seuls ne passent plus à l'échelle, et comment Kubernetes transforme un groupe de machines en une seule plateforme. -
Comment fonctionne un cluster Kubernetes : plan de contrôle et nœuds Les composants qui font tourner un cluster, et ce qui se passe entre kubectl apply et un conteneur en cours d'exécution. -
Deployments : mise à l'échelle, auto-réparation et mises à jour progressives Exécutez des réplicas d'un Pod, mettez-les à jour sans interruption et revenez en arrière quand une version tourne mal. -
Services : un réseau stable pour des Pods éphémères Donnez une adresse stable à vos Pods, exposez-les à l'intérieur et à l'extérieur du cluster, et restreignez qui peut parler à qui.