Introduction
Quand une application conteneurisée se comporte mal, le premier réflexe de la plupart des opérateurs est de consulter les journaux. Cependant, le comportement de journalisation par défaut de Docker est souvent insuffisant pour les systèmes de production : les journaux peuvent croître sans limite, manquer de structure ou disparaître lorsqu'un conteneur est remplacé. Les drivers de journalisation Docker résolvent ces problèmes en vous donnant le contrôle sur la façon dont les journaux des conteneurs sont capturés, formatés et expédiés vers des systèmes externes.
Cet article explore en profondeur les drivers de journalisation Docker, de l'architecture sous-jacente à la configuration pratique et au dépannage. Il s'adresse aux développeurs, ingénieurs DevOps et responsables techniques qui savent déjà exécuter des conteneurs mais doivent construire une stratégie de journalisation robuste. Vous apprendrez comment les drivers de journalisation fonctionnent sous le capot, comment choisir le bon driver pour votre environnement, comment configurer les drivers en toute sécurité, comment vérifier que la journalisation fonctionne comme prévu et comment récupérer en cas de problème. Chaque recommandation inclut des commandes concrètes et des sorties attendues pour que vous puissiez suivre sur votre propre infrastructure.
L'objectif est la clarté opérationnelle : observez avant de modifier, limitez le rayon d'impact de chaque changement, protégez les données sensibles, vérifiez les résultats et ayez toujours un plan de retour en arrière.
Comment fonctionnent les drivers de journalisation Docker : fonctionnement interne et architecture
Les drivers de journalisation Docker sont des composants enfichables qui déterminent où les flux stdout et stderr des conteneurs sont envoyés. Par défaut, Docker utilise le driver json-file, qui écrit les journaux sous forme d'objets JSON dans des fichiers sur l'hôte sous /var/lib/docker/containers/<container-id>/<container-id>-json.log. Chaque entrée de journal inclut le nom du flux, l'horodatage et le message de journal.
L'architecture du driver de journalisation est simple. Lorsqu'un conteneur démarre, le démon Docker initialise le driver de journalisation configuré pour ce conteneur. La sortie standard et la sortie d'erreur du conteneur sont alors multiplexées et passées à travers le driver. Selon le driver, les journaux peuvent être écrits dans un fichier local, transmis sur le réseau à un service distant ou entièrement supprimés. Cette conception maintient la journalisation découplée de l'application : l'application écrit sur les flux standard, et la plateforme gère le reste.
Docker prend en charge de nombreux drivers de journalisation prêts à l'emploi, notamment :
json-file: le pilote par défaut, écrit les journaux dans des fichiers locaux.journald: envoie les journaux au journal systemd.syslog: transmet les journaux à un serveur syslog.fluentd: envoie les journaux à un collecteur Fluentd.gelf: envoie les journaux au format GELF (Graylog Extended Log Format) à un serveur Graylog ou compatible.awslogs: envoie les journaux à Amazon CloudWatch Logs.splunk: envoie les journaux à Splunk.none: supprime toute sortie de journal.
Vous pouvez définir le driver de journalisation par défaut pour le démon Docker dans /etc/docker/daemon.json, ou vous pouvez le remplacer par conteneur à l'aide de l'option --log-driver. Cette dernière est souvent préférable en développement, tandis que les déploiements en production définissent généralement une valeur par défaut à l'échelle du démon et autorisent des exceptions si nécessaire.
Étiquettes de journal et métadonnées
De nombreux drivers de journalisation prennent en charge l'option --log-opt tag, qui vous permet d'ajouter un contexte supplémentaire à chaque entrée de journal. Par exemple, avec le driver json-file, vous pouvez ajouter une étiquette personnalisée à la ligne de journal. Avec les drivers réseau comme fluentd ou gelf, l'étiquette devient souvent une clé de routage ou un champ que les processeurs en aval peuvent utiliser pour filtrer ou agréger les journaux.
Un modèle courant consiste à inclure le nom du conteneur et la version de l'image dans l'étiquette :
docker run --log-driver=fluentd \
--log-opt fluentd-address=localhost:24224 \
--log-opt tag="{{.Name}}/{{.ImageName}}" \
nginx
Cette étiquette se développe en quelque chose comme sharp_curie/nginx:latest, vous donnant un contexte immédiat dans votre système d'agrégation de journaux.
Variables d'environnement et données sensibles
Un piège critique avec les drivers de journalisation est la fuite accidentelle de secrets. De nombreux drivers prennent en charge les options env ou env-regex, qui incluent les variables d'environnement dans chaque entrée de journal. Cela peut être utile pour le débogage, mais peut également exposer des mots de passe, des clés API ou des jetons. Par exemple :
docker run --log-driver=gelf \
--log-opt gelf-address=udp://localhost:12201 \
--log-opt env=MY_SECRET \
app
Si MY_SECRET contient des données sensibles, chaque ligne de journal les inclura. Examinez toujours quelles variables d'environnement sont journalisées et utilisez des listes d'autorisation plutôt que des modèles autorisant tout.
Choisir le bon driver de journalisation
Le choix d'un driver de journalisation dépend de votre contexte opérationnel. Voici une matrice de décision pour vous aider à évaluer les options en fonction des exigences courantes :
| Exigence | Driver recommandé | Notes |
|---|---|---|
| Débogage local, hôte unique | json-file | Simple, par défaut, mais nécessite une rotation des journaux pour éviter l'épuisement du disque. |
| Journalisation centralisée avec systemd | journald | Intégration native avec systemd, mais l'interrogation peut être plus lente que des outils dédiés. |
| Journalisation structurée vers Elasticsearch/Logstash | fluentd | Flexible, prend en charge la mise en mémoire tampon et les nouvelles tentatives. |
| Systèmes Graylog ou compatibles GELF | gelf | Léger, UDP ou TCP, prend en charge la compression. |
| Charges de travail natives AWS | awslogs | Intégration directe avec CloudWatch, nécessite des autorisations IAM. |
| Écosystème Splunk | splunk | Fonctionnalités riches, mais peut être complexe à configurer. |
| Aucun journal nécessaire (par exemple, travaux par lots éphémères) | none | Supprime les journaux, mais à utiliser avec prudence. |
Lorsque plusieurs drivers pourraient fonctionner, tenez compte des facteurs opérationnels tels que la fiabilité du réseau, le volume de journaux, les exigences de rétention et la courbe d'apprentissage pour votre équipe. Considérez également si vous devez caviarder ou transformer les journaux avant de les expédier ; certains drivers prennent en charge un traitement limité, mais un sidecar ou un processeur de journaux dédié peut être nécessaire pour les cas d'utilisation avancés.
Configuration sûre et bonnes pratiques
Les modifications de configuration doivent être apportées progressivement et en pleine conscience du rayon d'impact. Voici un flux de travail de configuration sûr :
- Enregistrez l'état actuel. Avant de changer quoi que ce soit, notez le driver de journalisation actuel et les options pour chaque conteneur ou service.
- Effectuez une modification limitée. Ne modifiez pas la journalisation de tous les conteneurs à la fois ; commencez par un seul conteneur ou service.
- Vérifiez le résultat. Vérifiez les journaux dans le système cible, confirmez que le format de journal est correct et assurez-vous qu'aucune erreur n'est signalée.
- Revenez en arrière si nécessaire. Si la modification ne fonctionne pas, revenez au driver et aux options précédents.
Parcourons un exemple concret : passer un conteneur du driver par défaut json-file à fluentd.
Tout d'abord, confirmez qu'une instance Fluentd est accessible. Dans cet exemple, Fluentd s'exécute sur l'hôte au port 24224. Vérifiez avec :
nc -zv localhost 24224
Sortie attendue :
Connection to localhost 24224 port [tcp/*] succeeded!
Si la connexion échoue, démarrez Fluentd ou vérifiez sa configuration avant de continuer.
Ensuite, exécutez un conteneur de test avec le driver fluentd, en attribuant une étiquette personnalisée :
docker run --rm --log-driver=fluentd \
--log-opt fluentd-address=localhost:24224 \
--log-opt tag="docker.test" \
alpine echo "Hello from Fluentd"
Le conteneur imprime le message sur la sortie standard et se termine. Comme le driver envoie le journal à Fluentd, vous devriez voir l'entrée dans la sortie Fluentd. Si Fluentd est configuré pour écrire sur la sortie standard, sa console affichera un enregistrement comme :
2025-03-10 12:00:00 +0000 docker.test: {"container_id": "...", "container_name": "...", "source": "stdout", "log": "Hello from Fluentd"}
Si vous voyez l'entrée, le driver fonctionne. Sinon, vérifiez les journaux Fluentd pour les erreurs de connexion et confirmez le format de l'adresse et de l'étiquette.
Rotation des journaux pour le driver json-file
Par défaut, le driver json-file ne fait pas tourner les journaux, ce qui peut remplir le disque de l'hôte. Pour éviter cela, définissez les options de rotation globalement dans daemon.json ou par conteneur. Voici un exemple pour daemon.json :
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Pour un seul conteneur :
docker run --log-driver=json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
nginx
Avec ces paramètres, Docker fait tourner le fichier journal lorsqu'il atteint 10 Mo et conserve au maximum trois fichiers tournés. Cela représente un total de 40 Mo par conteneur, ce qui est souvent suffisant pour le dépannage tout en empêchant une utilisation incontrôlée du disque. Ajustez les tailles en fonction de votre volume de journaux et de vos exigences de rétention.
Expédition des journaux vers AWS CloudWatch
Si vous exécutez des conteneurs sur AWS, le driver awslogs s'intègre directement à CloudWatch Logs. Créez d'abord un groupe de journaux s'il n'existe pas :
aws logs create-log-group --log-group-name my-app-logs
Exécutez ensuite un conteneur avec le driver awslogs, en spécifiant la région, le groupe de journaux et le nom du flux :
docker run --log-driver=awslogs \
--log-opt awslogs-region=us-east-1 \
--log-opt awslogs-group=my-app-logs \
--log-opt awslogs-stream=container-1 \
nginx
Assurez-vous que l'instance EC2 ou la tâche ECS dispose d'un rôle IAM avec les autorisations d'écrire dans CloudWatch Logs. Sinon, le conteneur ne démarrera pas avec une erreur similaire à :
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
En réalité, l'erreur sera plus spécifique, telle que AccessDeniedException, dans les journaux du démon Docker ou les métadonnées du conteneur. Vérifiez toujours docker logs <container> ou les journaux du démon lorsqu'un conteneur ne démarre pas avec un nouveau driver de journalisation.
Vérification et diagnostics
Vérifier que la journalisation fonctionne correctement ne consiste pas seulement à voir des journaux quelque part ; vous devez confirmer que le contenu, le format et les métadonnées du journal sont corrects. Voici des commandes pratiques pour chaque driver.
Vérification des journaux json-file
Pour inspecter les journaux d'un conteneur utilisant le driver json-file, utilisez docker logs :
docker logs <container-name> --tail 20
Cela affiche les 20 dernières lignes. Si vous souhaitez voir le fichier JSON brut, trouvez l'ID du conteneur et affichez directement le fichier journal :
docker inspect --format='{{.Id}}' <container-name>
ls -l /var/lib/docker/containers/<container-id>/<container-id>-json.log
cat /var/lib/docker/containers/<container-id>/<container-id>-json.log | tail -1
La dernière commande affiche l'entrée de journal la plus récente au format JSON, qui inclut des champs comme log, stream et time. Si les journaux n'apparaissent pas, vérifiez que le conteneur écrit sur stdout ou stderr. Les applications qui écrivent directement dans des fichiers à l'intérieur du conteneur ne seront pas capturées par la journalisation Docker.
Vérification des drivers distants
Pour les drivers réseau, utilisez le service récepteur pour vérifier les journaux. Par exemple, avec Fluentd, vous pouvez consulter ses propres journaux ou interroger le point de terminaison. Avec awslogs, utilisez :
aws logs tail my-app-logs --follow
Cela diffuse les journaux depuis CloudWatch en temps réel. Si vous voyez la sortie de votre conteneur, le driver fonctionne. Sinon, vérifiez les autorisations IAM, la connectivité réseau et les journaux du démon Docker pour les erreurs.
Contrôles de santé et journalisation
Un modèle de diagnostic courant consiste à combiner les contrôles de santé Docker avec la journalisation. Par exemple :
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost/ || exit 1
Si le contrôle de santé échoue, Docker marque le conteneur comme malsain, et vous pouvez utiliser docker inspect pour voir l'état de santé. Les journaux liés aux contrôles de santé ne sont pas automatiquement capturés par les drivers de journalisation, mais vous pouvez faire en sorte que la commande de contrôle de santé écrive sur stdout pour inclure sa sortie dans les journaux si nécessaire.
Pièges courants et comment les éviter
Les drivers de journalisation peuvent introduire des problèmes subtils qui n'apparaissent que dans des conditions spécifiques. Voici les pièges les plus courants et comment les gérer.
Piège 1 : Oublier la rotation des journaux
Sans rotation, le driver json-file peut consommer tout l'espace disque disponible sur l'hôte. Cela peut faire tomber non seulement le conteneur mais l'hôte entier, affectant tous les services.
Comment éviter : Définissez toujours les options max-size et max-file, globalement ou par conteneur. Surveillez l'utilisation du disque sur les hôtes exécutant de nombreux conteneurs.
Récupération : Si le disque est plein, arrêtez le conteneur affecté, supprimez ou compressez les anciens fichiers journaux, et redémarrez le conteneur avec les options de rotation. Ensuite, examinez et appliquez la rotation globalement.
Piège 2 : Journaliser des données sensibles
Utiliser les options env ou env-regex sans précaution peut divulguer des secrets dans les fichiers journaux ou les systèmes externes.
Comment éviter : Ne journalisez jamais les variables d'environnement à moins d'être certain qu'elles sont sûres. Utilisez des listes d'autorisation de noms de variables spécifiques et évitez les modèles regex larges. De plus, nettoyez les données sensibles au niveau de l'application avant d'écrire sur stdout.
Récupération : Si des secrets sont divulgués, faites immédiatement tourner les informations d'identification compromises, supprimez les journaux sensibles de toutes les destinations et mettez à jour la configuration de journalisation pour exclure ces variables.
Piège 3 : Contre-pression du driver réseau
Les drivers de journalisation distants comme fluentd, gelf, splunk et awslogs peuvent subir une latence réseau ou des pannes. Selon le driver, un tampon plein peut amener le conteneur à bloquer sur les écritures vers stdout, gelant l'application.
Comment éviter : Choisissez des drivers avec des mécanismes de mise en mémoire tampon et de nouvelles tentatives (par exemple, fluentd avec l'option fluentd-async). Définissez des limites de tampon raisonnables et surveillez le pipeline de journalisation.
Récupération : Si le conteneur est bloqué, arrêtez-le (si possible), corrigez le réseau ou le service de journalisation, puis redémarrez. Si le conteneur ne peut pas être arrêté proprement, redémarrez le démon Docker, ce qui peut entraîner une perte de journaux. Prévoyez une mise en mémoire tampon des journaux pour éviter la perte de données.
Piège 4 : Problèmes de compatibilité des drivers
Tous les drivers ne sont pas disponibles sur toutes les plateformes. Par exemple, journald est uniquement Linux et peut ne pas fonctionner sur les conteneurs Windows. awslogs nécessite des métadonnées et des autorisations spécifiques à AWS. L'utilisation d'un driver non pris en charge fait échouer le démarrage du conteneur avec une erreur comme :
docker: Error response from daemon: failed to initialize logging driver: journald is not supported on this platform.
Comment éviter : Vérifiez la disponibilité du driver sur votre plateforme avant le déploiement. Testez dans un environnement de préproduction.
Récupération : Choisissez un driver compatible et mettez à jour la configuration. Si le conteneur est géré par un orchestrateur, mettez à jour la définition du pod ou de la tâche et redéployez.
Piège 5 : Ignorer les risques du driver none
Le driver none supprime tous les journaux. Bien qu'il puisse réduire les frais généraux, il rend le débogage presque impossible en cas de problème.
Comment éviter : Utilisez none uniquement pour les conteneurs qui n'ont vraiment pas besoin de journaux, comme les travaux par lots de courte durée avec des sidecars externes pour la journalisation. Sinon, évitez-le.
Récupération : Reconfigurez le conteneur pour utiliser un driver approprié et redéployez. Envisagez d'ajouter un sidecar ou un expéditeur de journaux si vous avez besoin de journaux mais souhaitez réduire les frais généraux.
Sujets avancés : journaux multilignes, journalisation structurée et expédition des journaux
Les applications du monde réel produisent souvent des journaux multilignes, comme des traces de pile ou des requêtes SQL. Par défaut, Docker traite chaque ligne comme une entrée de journal distincte, ce qui peut rompre le contexte des messages multilignes. Certains drivers de journalisation, comme fluentd, prennent en charge l'analyse multiligne du côté récepteur. Par exemple, dans Fluentd, vous pouvez utiliser le plugin parser pour fusionner des lignes en un seul événement basé sur une expression régulière.
Pour gérer les journaux multilignes avec le driver json-file, vous ne pouvez pas fusionner automatiquement les lignes, mais vous pouvez configurer votre application pour produire des journaux JSON où chaque entrée inclut un ID de requête unique et un horodatage. Cela facilite la corrélation des lignes dans les outils d'analyse de journaux.
La journalisation structurée (sortie JSON) est une bonne pratique pour les applications conteneurisées. Lorsque votre application émet des journaux JSON, les systèmes en aval peuvent les analyser sans regex personnalisée, et les champs comme level, message et request_id deviennent des citoyens de première classe. Pour en tirer parti, configurez la bibliothèque de journalisation de votre application pour produire du JSON sur stdout. Ensuite, choisissez un driver de journalisation qui préserve la structure, comme fluentd ou gelf, ou utilisez json-file et transférez les journaux vers un processeur.
Pour expédier des journaux vers un système centralisé, envisagez d'utiliser un expéditeur de journaux dédié comme Fluent Bit ou Logstash en tant que sidecar ou démon. Cela découple le driver de journalisation de la destination et vous donne plus de flexibilité pour les transformations, la limitation de débit et les nouvelles tentatives.
Modes de défaillance et récupération
Lorsque la journalisation échoue, la première étape consiste à déterminer l'étendue de la défaillance : s'agit-il d'un conteneur, d'un hôte ou de tout l'environnement ? Utilisez les étapes de diagnostic suivantes :
- Vérifiez les journaux du conteneur. Exécutez
docker logs <container> --tail 50pour voir la sortie récente. Si la commande renvoie une erreur, le driver de journalisation peut être mal configuré. - Vérifiez les journaux du démon Docker. Sur Linux,
journalctl -u docker.serviceou/var/log/docker.logpeut révéler des erreurs d'initialisation du driver. - Vérifiez le système de journalisation cible. Assurez-vous que le service distant (par exemple, Fluentd, CloudWatch, Splunk) est accessible et sain. Testez avec des outils comme
ncou un client simple. - Inspectez les métadonnées du conteneur.
docker inspect <container>affiche le driver de journalisation configuré et les options.
Si un conteneur ne démarre pas en raison d'une erreur de driver de journalisation, le message d'erreur de docker run indique généralement le problème. Par exemple :
docker: Error response from daemon: failed to initialize logging driver: cannot connect to Fluentd at localhost:24224.
Dans ce cas, démarrez Fluentd ou corrigez l'adresse et réessayez.
Pour les pannes de la cible de journalisation, le comportement dépend du driver. Certains drivers mettent les journaux en mémoire tampon ou sur disque et reprennent lorsque la cible est disponible ; d'autres abandonnent les journaux ou bloquent. Connaissez les caractéristiques de défaillance de votre driver et planifiez en conséquence. Envisagez de configurer des alertes sur le retard de livraison des journaux ou le nombre d'erreurs.
Liste de contrôle opérationnelle
Cette liste de contrôle résume les tâches opérationnelles clés pour la gestion des drivers de journalisation Docker. Chaque élément inclut un responsable suggéré et une fréquence d'examen basée sur des structures d'équipe typiques. Ajustez les noms et les fréquences en fonction de votre organisation.
| Tâche | Rôle responsable | Fréquence | Commande de vérification |
|---|---|---|---|
| Examiner la configuration du driver de journalisation pour tous les services | Ingénieur DevOps (par exemple, Alex Kim) | Mensuelle | docker service ls et inspecter les options de journalisation de chaque service |
| Tester les paramètres de rotation des journaux | Ingénieur fiabilité des sites (par exemple, Priya Shah) | Trimestrielle | docker run un conteneur de test avec options de rotation et observer la taille des fichiers |
| Vérifier que les journaux atteignent le système centralisé | Ingénieur plateforme (par exemple, Jordan Lee) | Hebdomadaire | Interroger le système de journalisation pour les entrées récentes de chaque service |
| Rechercher des données sensibles dans les journaux | Ingénieur sécurité (par exemple, Samira Chen) | Mensuelle | Utiliser un outil d'analyse de journaux sur des échantillons |
| Mettre à jour les drivers de journalisation lors de l'ajout de nouveaux services | Développeur principal (par exemple, Marcus Brown) | À chaque version | Examiner le Dockerfile et les manifestes de déploiement |
| Vérifier l'utilisation du disque sur les hôtes | Administrateur système (par exemple, Taylor Nguyen) | Hebdomadaire | df -h /var/lib/docker/containers |
Attribuez des responsables explicites à ces tâches pour vous assurer qu'elles ne sont pas négligées. Examinez les résultats de la liste de contrôle lors d'une réunion opérationnelle mensuelle.
Conclusion
Les drivers de journalisation Docker sont un composant essentiel de tout environnement conteneurisé. Comprendre leur fonctionnement interne, leurs options de configuration et leurs modes de défaillance est essentiel pour construire une stratégie de journalisation fiable. En suivant les bonnes pratiques et les exemples concrets de cet article, vous pouvez éviter les pièges courants, garantir que les journaux sont disponibles lorsque vous en avez besoin et récupérer rapidement en cas de défaillance.
Commencez par un changement à faible risque : choisissez un conteneur, passez-le à un driver de journalisation non par défaut dans un environnement de préproduction et observez les résultats. Ensuite, déployez progressivement les changements en production avec une surveillance appropriée et des plans de retour en arrière. N'oubliez pas que la journalisation ne consiste pas seulement à capturer la sortie ; il s'agit de rendre cette sortie utile pour le débogage, l'audit et l'observabilité.