19 - Debugger ses conteneurs
Ce que tu vas apprendre
- Utiliser docker logs avec ses options utiles (follow, tail, since)
- Entrer dans un conteneur avec docker exec
- Comprendre pourquoi un conteneur quitte immédiatement (PID 1)
- Inspecter un conteneur avec docker inspect
- Récupérer des fichiers d'un conteneur plante
- Les erreurs courantes et leurs solutions
Prerequisites
Avoir suivi l'article sur les entrypoints. Avoir Docker installe et quelques conteneurs qui tournent (ou qui plantent, c'est le sujet).
Mon premier reflexe quand un conteneur ne marche pas, c'est de taper docker logs et de prier pour que le message d'erreur soit lisible. Spoiler : c'est rarement le cas. Alors voici toutes les techniques que j'utilise au quotidien.
docker logs : la base
bash# Les logs complets
docker logs mon-conteneur
# Suivre les logs en temps reel (comme tail -f)
docker logs -f mon-conteneur
# Les 50 dernieres lignes
docker logs --tail 50 mon-conteneur
# Les logs depuis les 5 dernieres minutes
docker logs --since 5m mon-conteneur
# Combiner : les 20 dernieres lignes + suivre
docker logs --tail 20 -f mon-conteneur
# Avec les timestamps
docker logs -t mon-conteneur
Le --since accepte des durees (5m, 1h, 30s) ou des dates (2026-03-29T10:00:00). Je l'utilise tout le temps pour filtrer le bruit quand un conteneur tourne depuis des jours.
Un détail qui m'a fait perdre du temps : par défaut, Docker melange stdout et stderr. Si tu veux les séparer :
bash# stderr uniquement
docker logs mon-conteneur 2>&1 1>/dev/null
# stdout uniquement
docker logs mon-conteneur 2>/dev/null
docker exec : entrer dans le conteneur
Quand les logs ne suffisent pas, tu veux entrer dedans et regarder :
bash# Shell interactif
docker exec -it mon-conteneur sh
# Ou bash si l'image l'a
docker exec -it mon-conteneur bash
# Lancer une commande directe
docker exec mon-conteneur cat /app/config.json
# Avec un utilisateur specifique
docker exec -u root mon-conteneur ls /root
Le -it c'est pour interactif + pseudo-TTY. Sans ca, tu n'as pas de prompt et les commandes interactives ne marchent pas.
Attention : sur les images Alpine ou distroless, bash n'est pas installe. Utilise sh. Sur les images distroless, il n'y a meme pas de shell. La, c'est une autre histoire (on en parle dans l'article sur la sécurité).
Pourquoi le conteneur quitte immédiatement
C'est la question que tout le monde se pose au début. Tu fais docker run, le conteneur démarré et s'arrêté aussitot. Le status dit Exited (0) ou Exited (1).
La raison : Docker garde un conteneur vivant tant que le processus PID 1 tourne. Des que ce processus se termine, le conteneur s'arrêté. Point.
Les causes habituelles :
bash# Cause 1 : la commande se termine immediatement
docker run ubuntu echo "hello"
# -> affiche hello, puis le conteneur s'arrete
# Cause 2 : le processus se met en background
# Dans ton Dockerfile
CMD ["nginx"]
# nginx se daemonize par defaut -> PID 1 termine -> conteneur mort
# Fix : nginx -g "daemon off;"
# Cause 3 : erreur au demarrage
docker logs mon-conteneur
# -> regarde le message d'erreur
Pour vérifier le code de sortie :
bashdocker ps -a --filter "name=mon-conteneur"
# CONTAINER ID IMAGE STATUS
# abc123 myapp Exited (137) 2 minutes ago
Les codes utiles : 0 = sortie normale, 1 = erreur applicative, 137 = tue par SIGKILL (souvent OOM), 139 = segfault, 143 = SIGTERM (arrêt propre demande par Docker).
docker inspect : tout savoir
docker inspect te donne un JSON énorme avec tout l'état du conteneur. C'est trop verbeux pour le lire en entier, alors utilise les filtres Go :
bash# L'adresse IP du conteneur
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mon-conteneur
# Les variables d'environnement
docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' mon-conteneur
# Les montages de volumes
docker inspect -f '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{println ""}}{{end}}' mon-conteneur
# Le code de sortie
docker inspect -f '{{.State.ExitCode}}' mon-conteneur
# L'etat complet
docker inspect -f '{{json .State}}' mon-conteneur | python -m json.tool
Sur paltemps.fr, quand j'ai un problème de connexion entre conteneurs, ma première commande c'est docker inspect pour vérifier que les conteneurs sont bien sur le meme réseau.
docker events : le flux en temps réel
bash# Tous les evenements Docker
docker events
# Filtrer par conteneur
docker events --filter container=mon-conteneur
# Filtrer par type d'evenement
docker events --filter event=die
docker events --filter event=oom
Tu lances ca dans un terminal, tu reproduis le bug dans un autre, et tu vois exactement ce qui se passe. L'événement oom est precieux : il te dit que le conteneur a ete tue par manque de mémoire.
Debugger un conteneur plante
Le conteneur a plante, tu ne peux plus faire exec dedans. Pas de panique :
bash# Copier un fichier depuis un conteneur arrete
docker cp mon-conteneur:/app/logs/error.log ./error.log
# Creer une image a partir du conteneur plante
docker commit mon-conteneur debug-image
# Puis lancer cette image avec un shell
docker run -it debug-image sh
Le docker commit créé un snapshot du filesystem du conteneur. C'est un truc de debug, pas de production. Mais ca sauve la mise quand tu veux inspecter l'état des fichiers au moment du crash.
Les erreurs courantes et leurs fixes
"bind: address already in use" : un autre process utilise deja le port.
bash# Trouver qui utilise le port 3000
lsof -i :3000
# Ou changer le mapping
docker run -p 3001:3000 mon-image
"no space left on device" : Docker a rempli le disque avec des images et des volumes.
bash# Voir l'espace utilise
docker system df
# Nettoyer tout ce qui n'est pas utilise
docker system prune -a --volumes
"exec format error" : tu essaies de lancer une image ARM sur x86 ou inversement. On verra ca dans l'article sur le multi-platform.
"OCI runtime error" : souvent un problème de permissions ou un binaire manquant dans l'image.
bash# Verifier que le binaire existe
docker run --entrypoint ls mon-image /app/
Conteneur qui redemarre en boucle : regarde les logs entre deux redemarrages.
bashdocker logs --tail 50 mon-conteneur
# Ou desactiver le restart pour voir l'erreur
docker update --restart=no mon-conteneur
Résumé
docker logs -f --tail 50est ta commande de base pour le debug.docker exec -itte donne un shell dans un conteneur qui tourne.- Un conteneur quitte des que le PID 1 se termine : garde ton process au foreground.
docker inspectavec les templates Go extrait les infos precises.docker commit+docker cppermettent d'inspecter un conteneur plante.- Le code de sortie (
137= OOM,143= SIGTERM) oriente le diagnostic.
Article précédent : Docker 18 - ENTRYPOINT et scripts d'init Article suivant : Docker 20 - Bases de donnees