Problème
Un conteneur est lancé, la commande rend la main sans erreur visible, puis le conteneur n'apparaît plus dans docker ps : il s'est arrêté en quelques secondes. Variante plus trompeuse : il apparaît bien, mais avec une durée de vie qui repart à zéro à chaque vérification, et le service n'est jamais joignable. Dans les deux cas rien ne semble expliquer la panne, parce que le message d'erreur est resté dans les journaux du conteneur mort.
Solution recommandée
Lire les journaux du conteneur avant toute tentative de relance. Relancer est le réflexe naturel et il ne produit que la même panne, en effaçant au passage le contexte de la tentative précédente. Les journaux, plus le code de sortie, désignent presque toujours l'une de trois causes : le programme principal se termine normalement au lieu de rester au premier plan, un réglage obligatoire manque et l'application refuse de démarrer, ou le port demandé est déjà occupé sur la machine hôte.
Matériel & outils
Un terminal sur la machine qui héberge les conteneurs, les commandes docker ps, docker logs, docker inspect, docker run et docker stop, docker compose si les conteneurs sont décrits dans un fichier compose, la commande ss sous Linux ou netstat sous Windows pour identifier le programme qui occupe un port
Étapes
1. Ne relancez pas. Une relance à l'identique refera exactement la même panne et vous fera perdre les traces de la précédente : le diagnostic commence par la lecture, pas par une deuxième tentative 2. Listez aussi ce qui est arrêté avec docker ps -a, car docker ps seul ne montre que ce qui tourne. La colonne STATUS sépare les deux situations : Exited suivi d'un nombre signifie que le conteneur s'est arrêté une fois et le reste, tandis que Restarting, ou un Up de quelques secondes qui repart à zéro chaque fois que vous relancez la commande, signale une boucle de redémarrage 3. Lisez les journaux du conteneur mort avec docker logs le-nom, ou docker logs --tail 50 le-nom pour n'avoir que la fin. Les journaux restent lisibles après l'arrêt tant que le conteneur n'a pas été supprimé, et la cause tient presque toujours dans les dernières lignes 4. Lisez le code de sortie avec docker inspect --format '{{.State.ExitCode}}' le-nom. La valeur 0 signifie que le programme s'est terminé normalement, ce qui oriente vers la première cause. Toute autre valeur signifie un refus ou un arrêt brutal, et la valeur 137 correspond au conteneur tué par la machine hôte, le plus souvent faute de mémoire disponible 5. Première cause, le programme principal ne reste pas au premier plan. Le signe : des journaux vides ou réduits à une bannière de démarrage, et un code de sortie à 0. Un conteneur vit exactement aussi longtemps que le programme lancé au démarrage ; si ce programme se met en arrière-plan ou se termine, le conteneur se termine avec lui, en succès. Corrigez la commande de démarrage pour qu'elle reste au premier plan, ou utilisez la commande par défaut de l'image officielle plutôt que de la remplacer 6. Deuxième cause, un réglage obligatoire manque. Le signe : une ligne explicite dans les journaux nommant une variable d'environnement, un fichier de configuration ou un dossier attendu. Une base de données qui refuse de s'initialiser sans mot de passe administrateur en est l'exemple le plus courant. Recréez le conteneur en fournissant ce qui manque, par une variable passée avec -e NOM=valeur ou par un dossier monté avec -v 7. Troisième cause, le port est déjà pris. Le signe est différent des deux autres : il n'y a pas de journaux du tout, parce que le conteneur n'a jamais démarré, et le message apparaît directement en réponse à docker run, sous la forme port is already allocated. Trouvez le programme qui occupe le port avec ss -ltnp sous Linux ou netstat -ano sous Windows, puis arrêtez-le, ou publiez un autre port côté hôte en remplaçant par exemple -p 8080:80 par -p 8081:80. Seul le nombre de gauche change : celui de droite est imposé par l'image 8. Si le conteneur est en boucle de redémarrage, arrêtez d'abord la boucle avec docker stop le-nom. Sans cela les journaux de chaque tentative se mélangent et deviennent illisibles. docker inspect --format '{{.RestartCount}}' le-nom donne le nombre de tentatives déjà faites. Retenez qu'une politique de redémarrage automatique, déclarée par --restart always ou --restart unless-stopped, ne répare rien : elle relance un conteneur qui échoue et transforme une panne visible en panne silencieuse 9. Si les journaux ne suffisent pas, gardez le conteneur en vie assez longtemps pour aller regarder dedans, en remplaçant son programme de démarrage par un interpréteur de commandes : docker run -it --rm --entrypoint sh nom-de-l-image. Vous obtenez une invite à l'intérieur de l'image, où vous pouvez vérifier la présence des fichiers, les droits sur les dossiers et les variables disponibles avec env. Le conteneur ne meurt plus, parce que cet interpréteur reste au premier plan 10. Si les conteneurs sont décrits dans un fichier compose, lisez les journaux du service fautif avec docker compose logs nom-du-service, ou relancez la pile en avant-plan avec docker compose up sans l'option -d : la sortie du programme s'affiche alors directement dans le terminal 11. Corrigez la cause identifiée, supprimez le conteneur fautif avec docker rm, recréez-le, puis vérifiez deux fois : docker ps quelques minutes plus tard doit montrer une durée de vie qui augmente, et docker logs ne doit plus contenir le message d'origine
Coût estimé
0 €, hors temps passé : tout le diagnostic utilise des commandes livrées avec Docker
Limites
Ne couvre pas le cas où l'image ne se télécharge pas, qui échoue avant même la création du conteneur et se reconnaît à un message d'authentification ou de version introuvable. Ne couvre pas un conteneur qui tourne mais répond mal, ni les problèmes de communication entre plusieurs conteneurs. Ne couvre pas la panne du moteur Docker lui-même sur la machine hôte. Sur un orchestrateur comme Kubernetes, le raisonnement reste le même mais les commandes et les noms d'état diffèrent.
Erreurs fréquentes
Relancer trois fois de suite avant d'avoir lu une seule ligne de journal. Lancer avec l'option --rm pendant un diagnostic : le conteneur est supprimé dès qu'il s'arrête et ses journaux disparaissent avec lui, ce qui est exactement l'inverse de ce qu'on cherche. Ajouter une politique de redémarrage automatique pour faire taire le symptôme, ce qui donne un conteneur qui semble exister sans jamais rendre service. Conclure que rien ne s'est passé devant des journaux vides, alors qu'un code de sortie à 0 dit précisément le contraire : le programme a fini son travail et s'est arrêté.
Alternatives
Pendant un diagnostic, lancer le conteneur en avant-plan avec docker run sans l'option -d : la sortie du programme s'affiche en direct et rien n'est à aller chercher après coup. Sur un hôte où les journaux sont centralisés vers un collecteur, lire ce collecteur plutôt que docker logs, qui peut y être vidé. Quand l'image vient d'une source inconnue et que ses journaux n'expliquent rien, repartir de l'image officielle du même logiciel et de sa documentation, souvent plus rentable que de deviner ce que contient la première.
Besoin d'un accompagnement personnalisé ?
Cours 1:1, conseil de solution, ou simplement une question précise - contacte-moi directement.