Docker pour les devs - 19 - Debugger ses conteneurs

docker logs, docker exec, docker inspect et toutes les techniques pour comprendre pourquoi un conteneur plante.

  1. 01 Docker pour les devs - 00 - Pourquoi Docker change tout
  2. 02 Docker pour les devs - 01 - Containers vs VMs
  3. 03 Docker pour les devs - 02 - L'architecture de Docker
  4. 04 Docker pour les devs - 03 - Docker Desktop, Engine et alternatives
  5. 05 Docker pour les devs - 04 - Écrire un Dockerfile
  6. 06 Docker pour les devs - 05 - Layers et cache
  7. 07 Docker pour les devs - 06 - Le .dockerignore
  8. 08 Docker pour les devs - 07 - Multi-stage builds
  9. 09 Docker pour les devs - 08 - Choisir son image de base
  10. 10 Docker pour les devs - 09 - Docker Compose, les bases
  11. 11 Docker pour les devs - 10 - Docker Compose avance
  12. 12 Docker pour les devs - 11 - Networking Docker, les bases
  13. 13 Docker pour les devs - 12 - Networking Docker avance
  14. 14 Docker pour les devs - 13 - Volumes et persistance
  15. 15 Docker pour les devs - 14 - Variables d'environnement et secrets
  16. 16 Docker pour les devs - 15 - Permissions et utilisateurs
  17. 17 Docker pour les devs - 16 - Docker et monorepo
  18. 18 Docker pour les devs - 17 - Dev vs Prod
  19. 19 Docker pour les devs - 18 - ENTRYPOINT, CMD et scripts d'initialisation
  20. 20 Docker pour les devs - 19 - Debugger ses conteneurs
  21. 21 Docker pour les devs - 20 - Bases de donnees dans Docker
  22. 22 Docker pour les devs - 21 - Sauvegardes et restauration
  23. 23 Docker pour les devs - 22 - Conteneuriser un frontend
  24. 24 Docker pour les devs - 23 - Sécurité des conteneurs
  25. 25 Docker pour les devs - 24 - Optimisation des images
  26. 26 Docker pour les devs - 25 - Builds multi-platform
  27. 27 Docker pour les devs - 26 - Limiter les ressources de tes conteneurs
  28. 28 Docker pour les devs - 27 - Gerer les logs comme un adulte
  29. 29 Docker pour les devs - 28 - Healthchecks et restart policies
  30. 30 Docker pour les devs - 29 - Nettoyer Docker avant qu'il mange ton disque
  31. 31 Docker pour les devs - 30 - Registries et stratégie de tags
  32. 32 Docker pour les devs - 31 - Docker en CI/CD
  33. 33 Docker pour les devs - 32 - Au-dela de Compose
  34. 34 Docker pour les devs - 33 - Glossaire Docker de A a Z

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 50 est ta commande de base pour le debug.
  • docker exec -it te donne un shell dans un conteneur qui tourne.
  • Un conteneur quitte des que le PID 1 se termine : garde ton process au foreground.
  • docker inspect avec les templates Go extrait les infos precises.
  • docker commit + docker cp permettent 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

Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.