infra / docker
Logs et debugging (exec, logs, inspect)
Explication
Ce que vous allez apprendre
- Consulter les logs d'un conteneur avec les bons filtres (
--tail,--since,-f) - Exécuter une commande ou ouvrir un shell dans un conteneur déjà en cours d'exécution avec
docker exec - Déboguer un conteneur qui crashe immédiatement au démarrage en court-circuitant son entrypoint
- Déboguer le réseau d'une image minimale (alpine, distroless) dépourvue d'outils avec
netshoot - Limiter la taille des logs pour éviter de saturer le disque de la machine hôte
Dans quel contexte ?
Un conteneur en production redémarre en boucle toutes les quelques secondes. docker exec échoue car le conteneur n'est jamais "running" assez longtemps pour qu'une commande s'y exécute. En relançant l'image avec docker run -it --entrypoint bash mon-api:1.0, un développeur peut explorer l'environnement intérieur, vérifier les fichiers de configuration et comprendre — souvent en quelques minutes — que la commande de démarrage pointait vers un fichier qui n'existait plus après un refactoring récent.
Quand tout ne se passe pas comme prévu
Après avoir appris à construire, lancer et surveiller des conteneurs, il reste la compétence la plus utilisée au quotidien : comprendre pourquoi quelque chose ne fonctionne pas comme attendu. Un conteneur qui refuse de démarrer, une application qui plante silencieusement, une erreur mystérieuse : dans tous ces cas, deux outils couvrent l'essentiel des besoins.
| Situation | Outil |
|---|---|
| Comprendre un comportement inattendu | docker logs -f --since |
| Explorer un conteneur qui tourne | docker exec -it ... bash |
| Conteneur qui crashe au démarrage | docker run -it --entrypoint bash |
| Image minimale sans outils réseau | docker run --network container:X nicolaka/netshoot |
Piège fréquent
Sans limite configurée, les logs JSON par défaut de Docker peuvent, avec le temps, saturer complètement le disque de la machine hôte. Configure toujours --log-opt max-size et max-file (ou l'équivalent dans daemon.json) avant la mise en production.
Les logs : la première chose à consulter
Tout ce qu'une application écrit sur sa sortie standard (stdout) ou d'erreur (stderr) est automatiquement capturé par Docker et consultable avec docker logs, sans configuration particulière. C'est presque toujours le premier réflexe face à un problème — bien avant d'ouvrir un shell dans le conteneur.
exec : entrer dans un conteneur vivant
docker exec permet d'exécuter une commande, y compris un shell interactif complet, à l'intérieur d'un conteneur déjà en cours d'exécution — un peu comme se connecter à distance à une machine déjà allumée. C'est très différent de docker run, qui crée un TOUT NOUVEAU conteneur : exec agit sur un conteneur existant.
Le piège du conteneur qui crashe immédiatement
Quand un conteneur s'arrête dès son démarrage (crash au lancement), docker exec ne fonctionne plus, car il n'existe alors plus de processus vivant dans lequel entrer. La solution consiste à relancer un nouveau conteneur en remplaçant temporairement sa commande de démarrage par un simple shell (--entrypoint bash), pour explorer l'environnement et comprendre ce qui a fait échouer le vrai démarrage.
Un conteneur minimaliste n'a parfois aucun outil réseau
Les images de production légères (alpine, distroless) n'embarquent souvent ni curl, ni ping, ni les autres outils habituels de diagnostic. Pour déboguer le réseau d'un tel conteneur, on utilise plutôt une image dédiée au debug (comme netshoot), qui partage temporairement l'espace réseau du conteneur à examiner.
Ne pas laisser les logs grandir indéfiniment
Sans limite configurée, les logs JSON par défaut de Docker peuvent, avec le temps, saturer complètement le disque de la machine hôte — un piège classique en production qu'on évite avec max-size/max-file.
Commandes & code
Logs et debugging
# --- Logs ---
docker logs mon-api # tous les logs stdout/stderr du conteneur
docker logs -f mon-api # suit en temps réel (comme tail -f)
docker logs --tail 100 mon-api # 100 dernières lignes uniquement
docker logs --since 10m mon-api # logs des 10 dernières minutes
docker logs -t mon-api # ajoute un timestamp à chaque ligne
docker logs mon-api 2>&1 | grep -i error # filtre les erreurs
# --- Exécuter une commande dans un conteneur déjà lancé ---
docker exec -it mon-api bash # ouvre un shell interactif
docker exec mon-api ps aux # liste les process internes sans ouvrir de shell
docker exec mon-api env # variables d'environnement effectives
docker exec -u root mon-api bash # entre en tant que root même si le conteneur tourne en non-root
docker exec -w /app mon-api ls -la # exécute dans un répertoire précis
# --- Debug d'un conteneur qui crash au démarrage (exec impossible car il n'est plus "running") ---
docker run -it --entrypoint bash mon-api:1.0 # court-circuite le CMD/ENTRYPOINT pour investiguer
docker logs mon-api # voir pourquoi il s'est arrêté
docker inspect --format '{{.State.ExitCode}}' mon-api # code de sortie du process principal
docker inspect --format '{{.State.OOMKilled}}' mon-api # true = tué par manque de mémoire (voir cgroups)
# --- Copier des fichiers entre l'hôte et un conteneur (debug ponctuel) ---
docker cp mon-api:/app/app.log ./app.log
docker cp ./fix.py mon-api:/app/fix.py
# --- Debug réseau depuis l'intérieur d'un conteneur minimal (souvent sans outils réseau) ---
docker run -it --network container:mon-api nicolaka/netshoot
# netshoot embarque curl, dig, tcpdump, nmap... utile quand l'image de prod est distroless/alpine
# --- Attacher son terminal au process principal (rare, à utiliser avec prudence) ---
docker attach mon-api # Ctrl+P puis Ctrl+Q pour se détacher SANS arrêter le conteneur
# --- Limiter le volume des logs pour éviter de saturer le disque hôte ---
docker run -d --log-driver json-file --log-opt max-size=10m --log-opt max-file=3 mon-api:1.0
# Config globale équivalente dans /etc/docker/daemon.json :
# { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }Résumé
docker logs -f --sincecouvre l'essentiel du debug quotidien ;docker execpermet d'investiguer à chaud.- Pour un conteneur qui crash immédiatement, relancer avec
--entrypoint bashcourt-circuite le process fautif. - Sans limite (
max-size/max-file), les logs JSON par défaut peuvent saturer le disque de l'hôte au fil du temps.
Exercices pratiques
Mission : élucider un conteneur qui redémarre en boucle en production
Objectif : Contourner l'impossibilité d'utiliser exec sur un conteneur qui crashe, et déboguer le réseau d'une image sans outils.
Contexte
Un conteneur mon-api redémarre en boucle toutes les quelques secondes. docker exec -it mon-api bash échoue systématiquement. L'image de production est basée sur distroless, donc sans outils réseau non plus.