Introduction
Déboguer des conteneurs Docker en production présente des défis uniques : les conteneurs sont éphémères, souvent immuables, et étroitement intégrés aux couches d'orchestration et de réseau. Une approche méthodique permet d'éviter des interruptions coûteuses et d'accélérer l'analyse des causes profondes. Cet article fournit une liste de contrôle pratique pour le débogage des conteneurs Docker en production, couvrant l'inventaire de l'environnement, la configuration sûre, les diagnostics, la récupération après échec et une liste de contrôle opérationnelle reproductible. En suivant ces étapes, les développeurs et les équipes DevOps peuvent réduire le temps moyen de récupération (MTTR) et maintenir la stabilité du système. Une liste de contrôle opérationnelle claire sépare l'investigation des suppositions, réduisant le retravail et garantissant des résultats de débogage cohérents. Commencez par un problème pilote étroit et mesurable, facile à inspecter localement avant d'étendre vos efforts de débogage.
Inventaire des versions et de l'environnement
Avant de plonger dans le débogage, établissez un instantané précis de l'environnement. Cet inventaire aide à reproduire les problèmes et fournit une base de référence pour les changements.
Version de Docker et système d'exploitation hôte
Exécutez docker version et docker info sur l'hôte concerné. Notez les versions du client et du serveur, le pilote de stockage et la version du noyau. Par exemple :
$ docker version --format '{{.Server.Version}}'
20.10.12
Sortie attendue : la version du moteur Docker. Si la version est obsolète, une mise à niveau peut résoudre des bogues connus. Enregistrez le système d'exploitation hôte avec cat /etc/os-release ou uname -a.
Topologie des conteneurs et orchestration
Identifiez si les conteneurs sont gérés par Docker Compose, Swarm ou Kubernetes. Pour les conteneurs autonomes, utilisez docker ps -a pour lister tous les conteneurs et leur statut. Pour les environnements orchestrés, récupérez l'état du cluster avec les outils appropriés (par exemple, kubectl get pods pour Kubernetes). Capturez l'ID de l'image et les étiquettes du conteneur :
$ docker inspect -f '{{.Config.Image}} {{.Image}}' <container_id>
nginx:1.21 sha256:2bcabc23b45489fb0885d69a06ba1d648aeda973fae7bb981bafbb884165e514
Cela montre le nom de l'image et son empreinte, ce qui est crucial pour revenir à une image connue et stable.
Prérequis réseau et ressources
Documentez les modes réseau, les mappages de ports et les limites de ressources. Utilisez docker inspect pour extraire la configuration détaillée :
$ docker inspect -f '{{json .NetworkSettings.Networks}}' <container_id> | python -m json.tool
Vérifiez les limites de CPU et de mémoire avec docker stats --no-stream <container_id> pour voir si le conteneur atteint sa limite. Vérifiez également que les journaux sont capturés par le pilote de journalisation (par exemple, json-file, journald).
Chemin de configuration sûr
Le débogage nécessite souvent des modifications de configuration. Pour éviter de causer d'autres problèmes, implémentez les changements de manière limitée et réversible.
Utiliser des surcharges spécifiques à l'environnement
Ne modifiez jamais directement la configuration d'un conteneur en cours d'exécution. Utilisez plutôt des variables d'environnement ou des fichiers de configuration qui peuvent être versionnés et restaurés. Par exemple, pour changer le niveau de journalisation d'un conteneur, redémarrez-le avec une variable d'environnement mise à jour :
$ docker run -d --name myapp -e LOG_LEVEL=debug myapp:latest
Cette commande démarre un nouveau conteneur avec le niveau de journalisation debug. L'ancien conteneur peut être arrêté et conservé pour comparaison.
Activer la journalisation de débogage en toute sécurité
Si l'application prend en charge la journalisation de débogage, activez-la temporairement via une variable d'environnement ou un fichier de configuration. Pour le démon Docker lui-même, activez le mode débogage en éditant /etc/docker/daemon.json et en redémarrant le démon :
{
"debug": true
}
Après le redémarrage, vérifiez que les journaux de débogage apparaissent dans le journal du démon (par exemple, journalctl -u docker.service -f). Sachez que la journalisation de débogage augmente la verbosité et peut affecter les performances ; désactivez-la après le dépannage.
Éviter le mode privilégié et les modifications de l'hôte
Lorsque vous devez inspecter le trafic réseau ou les appels système, utilisez des outils spécialisés qui ne nécessitent pas d'exécuter le conteneur avec --privileged. Par exemple, nsenter permet d'exécuter des commandes dans les espaces de noms du conteneur sans modifier ses privilèges. Pour obtenir un shell dans un conteneur à des fins de débogage, préférez docker exec à docker attach pour éviter d'interférer avec le processus principal du conteneur.
Vérification et diagnostics
Cette section fournit des vérifications concrètes et des résultats attendus pour faciliter le débogage.
Vérifier la santé du conteneur
Si un conteneur a une vérification de santé définie, interrogez son état :
$ docker inspect --format='{{.State.Health.Status}}' <container_id>
healthy
Sortie attendue : healthy ou unhealthy. Si le conteneur est malsain, inspectez le journal de vérification de santé :
$ docker inspect --format='{{json .State.Health}}' <container_id> | python -m json.tool
Cela montre la dernière sortie de la vérification de santé et le code de sortie.
Examiner les journaux
Utilisez docker logs pour voir la sortie du conteneur. Pour un conteneur avec beaucoup de journaux, utilisez --since et --until pour filtrer par heure, et --tail pour limiter les lignes. Exemple :
$ docker logs --since=2023-10-01T10:00:00 --until=2023-10-01T11:00:00 --tail=100 <container_id>
Sortie attendue : lignes de journal récentes. Recherchez les traces de pile d'erreurs, les délais d'attente ou les échecs de connexion.
Diagnostiquer la connectivité réseau
Si le conteneur ne peut pas atteindre les services externes, testez la connectivité depuis l'intérieur du conteneur :
$ docker exec -it <container_id> bash
root@container:/# curl -v https://example.com
Sortie attendue : en-têtes de réponse HTTP. Si curl échoue, vérifiez la résolution DNS (nslookup example.com) et le routage (ip route). Inspectez également les règles iptables sur l'hôte (nécessite root sur l'hôte).
Inspecter les processus et l'utilisation des ressources
Utilisez docker top <container_id> pour voir les processus en cours d'exécution dans le conteneur. Comparez avec les processus hôtes en utilisant ps aux | grep <process>. Pour vérifier les fuites de mémoire, surveillez la RSS au fil du temps avec docker stats. Une utilisation de mémoire en constante augmentation peut indiquer une fuite.
Analyser les changements du système de fichiers
Pour voir quels fichiers ont changé depuis le démarrage du conteneur, comparez le système de fichiers du conteneur avec l'image en utilisant docker diff <container_id>. Cela montre les fichiers ajoutés (A), modifiés (C) ou supprimés (D). Exemple :
$ docker diff <container_id>
C /var/log/app.log
A /tmp/newfile.txt
D /etc/oldconfig.conf
Cela est utile pour identifier les modifications non intentionnelles ou confirmer que les changements de configuration ont été appliqués.
Modes de défaillance et récupération
Même avec un débogage minutieux, des défaillances peuvent survenir. Préparez-vous aux modes de défaillance courants et sachez comment récupérer.
Boucle de redémarrage du conteneur
Si un conteneur démarre et se termine à plusieurs reprises, inspectez son code de sortie et ses journaux :
$ docker inspect -f '{{.State.ExitCode}} {{.State.Error}}' <container_id>
Codes de sortie courants : 1 (erreur d'application), 137 (SIGKILL, souvent OOM), 143 (SIGTERM, terminaison gracieuse). Pour empêcher temporairement le redémarrage, arrêtez le conteneur : docker stop <container_id>. Ensuite, exécutez le conteneur au premier plan avec --rm pour voir la sortie directement :
$ docker run --rm -it --name debug <image> bash
Cela donne un shell interactif pour tester le démarrage manuellement.
Mémoire insuffisante (OOM)
Si l'hôte manque de mémoire, le noyau peut tuer un processus de conteneur. Vérifiez dmesg | grep -i oom sur l'hôte. Pour prévenir l'OOM, augmentez la limite de mémoire du conteneur : docker update --memory 512m <container_id>. Analysez également les modèles d'utilisation de la mémoire de l'application.
Échec de communication réseau
Si le conteneur ne peut pas se connecter à d'autres conteneurs ou services externes, vérifiez la configuration réseau. Pour les réseaux ponts définis par l'utilisateur, assurez-vous que les conteneurs sont attachés au bon réseau : docker network inspect <network_name>. Vérifiez les règles de pare-feu : iptables -L -n -v | grep DOCKER. Revenez en arrière en annulant les modifications réseau récentes ou en redémarrant le démon Docker : systemctl restart docker.
Retour en arrière de la configuration
Gardez toujours les configurations précédentes dans le contrôle de version. Si un changement de configuration cause des problèmes, revenez à la dernière version connue et stable et redémarrez le conteneur. Pour les problèmes liés à l'image, revenez à une étiquette d'image précédente :
$ docker run -d --name myapp_rollback myapp:1.0.2
Ensuite, mettez à jour le service ou l'équilibreur de charge pour pointer vers le nouveau conteneur.
Perte ou corruption de données
Si un volume est corrompu, restaurez à partir des sauvegardes. Vérifiez régulièrement l'intégrité des sauvegardes. Pour les données critiques, utilisez une procédure de migration ou de restauration de base de données. Testez les exercices de récupération dans un environnement de préproduction.
Pièges courants et comment les éviter
Même les équipes expérimentées font des erreurs lors du débogage de conteneurs en production. Voici les pièges les plus courants, pourquoi ils surviennent et comment les éviter ou s'en remettre.
Piège 1 : Modifier directement un conteneur en cours d'exécution
Pourquoi cela arrive : Il semble rapide d'utiliser docker exec dans un conteneur et de modifier un fichier de configuration ou d'installer un paquet pour tester un correctif. Risque : Les modifications sont perdues lorsque le conteneur redémarre, et vous avez maintenant une configuration non reproductible. Comment éviter : Effectuez toujours les modifications via une reconstruction d'image, des variables d'environnement ou des fichiers de configuration montés. Si vous devez faire un changement d'urgence, documentez-le et créez immédiatement un correctif approprié dans votre pipeline de construction.
Piège 2 : Ignorer les limites de ressources
Pourquoi cela arrive : Les développeurs se concentrent souvent sur les erreurs d'application et négligent les limites de ressources des conteneurs. Risque : Un conteneur atteignant sa limite de mémoire peut être tué par le tueur OOM, provoquant des redémarrages inexpliqués. La limitation du CPU peut faire paraître l'application bloquée. Comment éviter : Définissez des limites de ressources appropriées dans votre manifeste de déploiement. Surveillez régulièrement docker stats. Lors du débogage, vérifiez toujours si le conteneur est proche de sa limite.
Piège 3 : Se fier à l'étiquette latest
Pourquoi cela arrive : Utiliser latest est pratique pendant le développement. Risque : En production, latest peut pointer vers une image différente de celle testée, entraînant un comportement inattendu et rendant les retours en arrière difficiles. Comment éviter : Utilisez toujours des étiquettes de version explicites ou des empreintes d'image en production. Par exemple, utilisez myapp:1.2.3 ou myapp@sha256:....
Piège 4 : Négliger la configuration de la journalisation
Pourquoi cela arrive : Les équipes supposent que les journaux sont capturés correctement. Risque : Si le pilote de journalisation est mal configuré ou si l'espace disque est épuisé, vous perdez la visibilité au moment où vous en avez le plus besoin. Comment éviter : Vérifiez le pilote de journalisation avec docker info. Configurez la rotation des journaux pour éviter l'épuisement du disque. Utilisez un système d'agrégation de journaux centralisé.
Piège 5 : Exécuter des conteneurs en tant que root
Pourquoi cela arrive : De nombreuses images de base utilisent root par défaut pour simplifier. Risque : Un conteneur compromis donne à un attaquant un accès root à l'hôte. Comment éviter : Spécifiez un utilisateur non root dans votre Dockerfile (directive USER) et assurez-vous que votre application n'a pas besoin de root. Utilisez le drapeau --user de Docker si nécessaire.
Liste de contrôle des opérations
Utilisez la liste de contrôle suivante pour un débogage systématique et des opérations continues. Cette liste aide les équipes à transformer les défis de débogage en tâches reproductibles et mesurables. Attribuez un seul responsable pour chaque étape et définissez une cadence de revue (par exemple, hebdomadaire pour la surveillance, mensuelle pour la revue de la liste).
| Étape | Action | Responsable (exemple) | Vérification | Fréquence |
|---|---|---|---|---|
| 1 | Enregistrer les détails de l'environnement (version Docker, OS hôte, orchestration) | Priya Shah, ingénieure DevOps | Sortie de docker version et docker info capturée | À chaque incident |
| 2 | Identifier le conteneur défaillant et son objectif | Ingénieur d'astreinte | docker ps -a montre le statut | À chaque incident |
| 3 | Examiner les journaux du conteneur pour détecter les erreurs | Ingénieur d'astreinte | docker logs --tail=100 ne montre aucune erreur inattendue | À chaque incident |
| 4 | Vérifier l'état de santé du conteneur | Ingénieur d'astreinte | docker inspect --format='{{.State.Health.Status}}' renvoie healthy | À chaque incident |
| 5 | Tester la connectivité réseau depuis l'intérieur du conteneur | Spécialiste réseau (si nécessaire) | docker exec <container_id> curl -v <url> réussit | Lorsque des problèmes réseau sont suspectés |
| 6 | Inspecter l'utilisation des ressources (CPU, mémoire, E/S disque) | Priya Shah, ingénieure DevOps | docker stats --no-stream montre une utilisation inférieure à 80 % | Hebdomadaire |
| 7 | Comparer le système de fichiers du conteneur à l'image | Ingénieur d'astreinte | docker diff ne montre que les changements attendus | Lorsque des changements sont suspectés |
| 8 | Reproduire le problème avec une configuration minimale | Responsable développement (ex. Alex Chen) | Le conteneur s'exécute avec --rm et un environnement minimal sans erreur | Pendant l'analyse des causes profondes |
| 9 | Appliquer le correctif de manière limitée (nouveau conteneur, surcharge d'environnement) | Responsable développement | docker run avec une configuration mise à jour réussit | Pendant le correctif |
| 10 | Surveiller après le correctif et documenter la cause profonde | Ingénieur d'astreinte | docker stats et les journaux ne montrent aucune erreur pendant 24 heures | Post-correctif et revue |
Revue régulière des opérations
Effectuez des revues régulières de la santé des conteneurs, de la rotation des journaux et des alertes de ressources. Configurez une surveillance avec Prometheus et Grafana, ou utilisez la commande intégrée docker stats avec un script de collecte. Définissez des seuils d'alerte pour le CPU, la mémoire et les redémarrages. La liste de contrôle des opérations elle-même doit être examinée mensuellement par le responsable de l'équipe DevOps pour intégrer les nouveaux apprentissages.
Conclusion
Le débogage de conteneurs Docker en production exige une approche systématique. Cette liste de contrôle fournit un cadre pratique : commencez par un inventaire de l'environnement, apportez des modifications de configuration limitées, utilisez des commandes de diagnostic concrètes, anticipez les modes de défaillance, suivez une liste de contrôle opérationnelle reproductible et évitez les pièges courants. En adoptant ces pratiques, les équipes peuvent réduire les temps d'arrêt et améliorer la fiabilité. N'oubliez pas de garder une focalisation étroite et mesurable pour chaque session de débogage, de toujours vérifier les correctifs avec des contrôles observables et d'attribuer une responsabilité claire pour chaque étape. Révisez et mettez à jour régulièrement vos procédures de débogage pour couvrir de nouveaux scénarios et technologies de conteneurs.
---
Remarque : Toutes les commandes et sorties sont illustratives. Adaptez-les à votre environnement spécifique et à votre moteur de conteneurs.