## Introduction Les drivers de logging Docker contrôlent où sont envoyées les sorties stdout et stderr des conteneurs, mais ils sont souvent traités comme un détail de faible priorité dans l'automatisation CI/CD. Cela crée un écart dangereux : un pipeline peut déployer un conteneur avec succès tout en perdant silencieusement des logs, en divulguant des sorties sensibles ou en remplissant un disque parce que le mauvais driver est actif. Ce guide se concentre sur la sécurité opérationnelle lors des changements de driver de logging Docker dans les pipelines automatisés. Il relie le déploiement, la vérification et le retour arrière à des commandes concrètes, des sorties attendues, des signaux d'échec et des décisions de récupération. Les lecteurs cibles sont les développeurs, les consultants DevOps et les équipes techniques de startups qui utilisent déjà Docker mais veulent un flux de travail contrôlé pour changer de driver de logging. La règle de base est : observer avant de changer, limiter le rayon d'impact, utiliser des variables d'environnement plutôt que des secrets, vérifier le résultat et savoir comment récupérer si l'état attendu n'est pas atteint. ## Inventaire des versions et de l'environnement Avant de toucher à toute configuration de logging, identifiez la version exacte de Docker, la topologie déployée et le conteneur ou service concerné. Cela évite les erreurs de copier-coller qui supposent une fonctionnalité Docker plus récente ou une couche d'orchestration différente. Commencez par des commandes d'inventaire en lecture seule. Sur un hôte Docker autonome, exécutez : ```bash docker version --format '{{.Server.Version}}' ``` Sortie typique : `20.10.24` ou `24.0.7`. Le support des drivers de logging varie selon la version ; par exemple, le driver `awslogs` a été ajouté dans Docker 1.12, et le comportement de `journald` peut différer entre Docker 19.x et 20.x. Ne supposez pas qu'un driver existe simplement parce qu'il est mentionné dans la documentation. Ensuite, listez les conteneurs en cours d'exécution et leurs détails : ```bash docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" ``` Pour un conteneur spécifique, inspectez le driver de logging actuellement actif et ses options : ```bash docker inspect --format '{{.HostConfig.LogConfig.Type}} {{.HostConfig.LogConfig.Config}}' ``` Exemple de sortie : `json-file map[max-size:10m max-file:3]`. Cela confirme que le driver est `json-file` avec rotation. Si la sortie est `json-file map[]`, seule la rotation par défaut s'applique, ce qui peut entraîner une croissance illimitée des logs. Pour les projets basés sur Compose, l'inventaire équivalent est : ```bash docker compose config ``` Cela affiche la configuration effective complète, y compris toute section `logging:` pour chaque service. Si la section logging est absente, Docker utilise par défaut le driver `json-file` au niveau du démon. Pour vérifier l'état de persistance des données avant tout changement, inspectez les montages : ```bash docker inspect --format '{{json .Mounts}}' ``` Un volume nommé tel que `app_data:/var/lib/app` est géré par Docker et survit à la recréation du conteneur. Un montage bind tel que `./data:/var/lib/app` dépend de l'existence du chemin hôte avec les bonnes permissions. Si votre application écrit des logs dans un fichier à l'intérieur du conteneur, ce fichier vit dans la couche conteneur et sera perdu au redémarrage à moins d'être explicitement monté ou transmis à stdout. Confirmez où résident réellement les données de log avant de modifier la configuration de logging. Enfin, effectuez un test de redémarrage sur un clone de staging : ```bash docker stop && docker start docker logs --tail 20 ``` Si les 20 dernières lignes montrent que l'application démarre proprement et reçoit du trafic, le chemin de logging actuel est au moins assez stable pour être comparé après le changement. ## Chemin de configuration sûr Changer de driver de logging est un changement de configuration, pas un changement de code, et mérite la même discipline de revue et de retour arrière. Le chemin le plus sûr est de définir la configuration de logging souhaitée dans un fichier déclaratif, de la réviser en dehors de la production, de la valider dans un environnement local ou de staging, puis de la déployer via le pipeline. ### Étape 1 : Épingler le fichier Docker ou Compose Pour un conteneur autonome lancé directement par le pipeline, la configuration peut se trouver dans une commande Docker run ou une unité systemd. Pour Compose, elle se trouve dans `docker-compose.yml` ou `compose.yml`. Exemple de définition de service : ```yaml services: web: image: nginx:1.25 logging: driver: json-file options: max-size: "10m" max-file: "3" ``` Cela remplace le défaut par une rotation explicite : trois fichiers de 10 Mo maximum chacun. À titre de comparaison, le driver `json-file` par défaut sans options peut faire grossir un seul fichier de log indéfiniment jusqu'à épuisement du disque. ### Étape 2 : Choisir un driver candidat spécifique et justifier le changement Pour une journalisation centralisée, les choix courants sont Fluentd (`fluentd`), AWS CloudWatch (`awslogs`) ou le journal systemd (`journald`). La décision doit inclure le compromis opérationnel. Par exemple, passer de `json-file` à `fluentd` permet l'envoi des logs vers un agrégateur, mais cela supprime la capacité de la commande `docker logs` à afficher la sortie du conteneur à moins qu'un fallback du driver fluentd ou une configuration supplémentaire ne soit mis en place. Cette perte de visibilité peut casser les flux de débogage en production. Un déplacement incrémental plus sûr consiste souvent à conserver `json-file` mais à ajouter des options de rotation. Si la journalisation centralisée est requise, configurez le driver `fluentd` avec des détails de connexion explicites et des paramètres de nouvelle tentative : ```yaml logging: driver: fluentd options: fluentd-address: localhost:24224 fluentd-async: "true" fluentd-retry-wait: "5" fluentd-max-retries: "10" ``` ### Étape 3 : Valider la configuration statiquement Exécutez `docker compose config` après avoir modifié le fichier Compose. La sortie inclut un bloc `logging:` sous le service. Si le nom du driver est mal orthographié, Docker échouera à la création du conteneur avec une erreur comme : ``` failed to initialize logging driver: error looking up logging plugin fluentdd: plugin not found ``` Attraper cela dans le pipeline avant le déploiement est moins coûteux qu'après. ### Étape 4 : Tester dans un environnement local Lancez le service avec `docker compose up -d` et vérifiez que le driver prend effet : ```bash docker inspect --format '{{.HostConfig.LogConfig.Type}}' ``` Sortie attendue : le nouveau nom de driver, par exemple `fluentd`. Générez ensuite des lignes de log de test et confirmez qu'elles apparaissent dans la destination : ```bash docker exec sh -c 'echo test-log-$(date +%s)' ``` Si vous utilisez Fluentd, interrogez l'agrégateur pour la ligne récente : ```bash fluentd-cat test.tag < /dev/null && curl -s http://localhost:9880/api/plugins.json | jq '.plugins[] | select(.type=="output") | .config' ``` La vérification exacte dépend de votre backend de logging, mais le principe est : produire un événement unique, puis le rechercher dans le système cible. Si l'événement n'apparaît pas en quelques secondes, le pipeline est cassé. ## Vérification et diagnostics La vérification des changements de driver de logging comporte trois couches : acceptation du driver, flux de logs et détection des défaillances opérationnelles. ### Acceptation du driver Immédiatement après un déploiement, exécutez : ```bash docker ps --filter "name=" --format '{{.Names}} {{.Status}}' ``` Si le statut du conteneur n'est pas `Up`, le service est arrêté. Vérifiez ensuite le driver : ```bash docker inspect --format '{{.HostConfig.LogConfig.Type}}' ``` Attendu : le nouveau nom de driver. Si le driver est inchangé, le déploiement a probablement réutilisé un ancien conteneur ou le pipeline n'a pas appliqué les changements Compose. Forcez la recréation avec `docker compose up -d --force-recreate ` et revérifiez. ### Vérification du flux de logs Pour `json-file`, la rotation peut être vérifiée en examinant les fichiers sur l'hôte. Trouvez l'ID du conteneur : ```bash docker inspect --format '{{.Id}}' ``` Puis regardez le répertoire hôte (exemple de chemin sous Linux) : ```bash ls -lh /var/lib/docker/containers//-json.log* ``` Vous devriez voir plusieurs fichiers si la rotation est active (par exemple `-json.log`, `-json.log.1`, `-json.log.2`). Si un seul fichier existe et qu'il a dépassé `max-size`, la rotation ne fonctionne pas. Pour `fluentd`, vérifiez le processus fluentd ou le point de terminaison sur l'agrégateur. Une défaillance courante est un `fluentd-address` pointant vers un hôte obsolète. Testez la connectivité depuis le conteneur : ```bash docker exec sh -c 'nc -zv 24224' ``` Sortie attendue : `Connection to 24224 port [tcp/*] succeeded!` Si la connexion est refusée, le driver réessaiera selon `fluentd-max-retries` puis abandonnera les logs. Vérifiez la sortie stderr du conteneur pour les erreurs du driver : ```bash docker logs 2>&1 | grep -i fluentd ``` Des messages comme `Failed to write to fluentd` indiquent que le driver échoue. ### Détection de défaillance dans le pipeline Ajoutez un test de fumée post-déploiement qui appelle la source de logs. Pour un service web, déclenchez une requête avec un identifiant de trace unique : ```bash curl -H 'X-Request-ID: verify-log-123' http://localhost:8080/health ``` Puis interrogez le backend de logging pour cet identifiant. Si le log est attendu dans un fichier, utilisez `docker exec` pour lire le fichier de log du conteneur : ```bash docker exec sh -c 'grep verify-log-123 /var/log/app/*.log' ``` Si rien ne revient après trois tentatives sur 30 secondes, faites échouer le pipeline et déclenchez le retour arrière. ## Modes de défaillance et récupération Les modes de défaillance les plus courants pour les changements de driver de logging Docker sont : ### 1. Le conteneur ne démarre pas en raison d'un driver ou d'une option invalide **Symptôme** : Le pipeline rapporte une erreur de création de conteneur, par exemple `invalid log driver: fluent` ou `invalid option: max-size`. **Pourquoi** : Faute de frappe dans le fichier Compose ou driver non installé (par exemple `awslogs` nécessite que le démon Docker dispose du plugin cloudwatch logs). **Récupération** : Revenez au commit précédent du fichier Compose. Correctif immédiat : exécutez `docker update --log-driver json-file ` si le conteneur existe, mais cela ne change pas le fichier, donc la prochaine recréation cassera à nouveau. Corrigez la déclaration et redéployez. ### 2. Les logs cessent d'apparaître dans le système central après le basculement **Symptôme** : Dans l'agrégateur (par exemple Kibana, CloudWatch), les logs du service cessent de se mettre à jour, mais `docker ps` montre que le conteneur tourne. **Pourquoi** : Le driver de logging ne peut pas se connecter au distant (par exemple hôte Fluentd en panne, identifiants AWS manquants) ou le driver met en mémoire tampon indéfiniment en raison d'une charge élevée. **Récupération** : Revenez temporairement à `json-file` avec rotation pour restaurer la visibilité de `docker logs`. Ensuite, déboguez la connectivité distante séparément. Ne laissez jamais la production avec le driver de logging distant s'il n'est pas vérifié de bout en bout. ### 3. Le disque se remplit après le passage à `journald` ou au `json-file` par défaut **Symptôme** : L'utilisation du disque du serveur grimpe, et `docker ps` montre des conteneurs en mauvaise santé ou des plantages. **Pourquoi** : Le driver `journald` a ses propres paramètres de rotation mais peut encore consommer beaucoup d'espace s'il n'est pas limité, ou le défaut `json-file` du démon est petit et se remplit rapidement. **Récupération** : Définissez d'abord une rotation explicite pour `json-file`. Pour `journald`, configurez `SystemMaxUse` dans `/etc/systemd/journald.conf` et redémarrez `systemd-journald`. Surveillez l'espace disque comme métrique du pipeline. ### 4. La mise à jour progressive perd des logs pendant une courte fenêtre **Symptôme** : Pendant `docker stack deploy` ou `docker compose up -d` avec un changement de logging, l'ancien conteneur est arrêté et le nouveau démarré. Pendant quelques secondes, les logs de l'ancien conteneur peuvent ne pas être vidés. **Pourquoi** : Certains drivers vident de manière asynchrone. L'ancien conteneur peut être tué avant que ses logs en mémoire tampon ne soient écrits. **Récupération** : Acceptez la petite perte si l'application est tolérante, ou utilisez un expéditeur de logs sidecar qui lit depuis un montage de fichier, ce qui découple la collecte de logs du cycle de vie du driver. Évitez de compter uniquement sur le driver de logging pour les logs d'audit de grande valeur. Pour préparer la récupération, taguez toujours l'image ou la révision Compose précédente qui fonctionnait. Dans un pipeline GitOps, un retour arrière est un `git revert` du changement de logging, suivi du déploiement du commit précédent. Gardez la configuration du driver précédent visible dans l'historique du dépôt afin que les opérateurs puissent comparer. ## Liste de contrôle opérationnelle Utilisez cette liste de contrôle avant et après un changement de driver de logging en CI/CD. Chaque élément indique le responsable pour une équipe de startup typique et la fréquence de revue. | # | Élément | Responsable | Comment vérifier | Fréquence | |---|---------|-------------|------------------|-----------| | 1 | Version de Docker et support du démon pour le driver candidat | Ingénieur DevOps | `docker version` et `docker info --format '{{.LoggingDrivers}}'` | Avant chaque changement | | 2 | Driver actuel et options pour le service cible | Propriétaire du service (par exemple responsable de l'équipe backend) | Sortie de `docker inspect` | Avant chaque changement | | 3 | Santé de la destination des logs (par exemple endpoint Fluentd joignable, permissions CloudWatch) | Responsable de l'équipe plateforme | Exécuter un test de connectivité depuis un conteneur de test | Avant chaque changement | | 4 | Nouvelle configuration de logging déclarée dans Compose ou Dockerfile | Propriétaire du service | Diff de `docker compose config` | Avant la fusion | | 5 | Validation statique réussie | Pipeline CI | Code de sortie 0 de `docker compose config` | À chaque exécution du pipeline | | 6 | Limites de rotation définies (max-size, max-file) | Ingénieur DevOps | `docker inspect` montre une config non vide | Avant la fusion | | 7 | Déploiement en staging réussi avec le nouveau driver | Propriétaire du service | Statut du conteneur `Up` et driver changé | Après le déploiement en staging | | 8 | Événement de log généré et observé dans le système central | Responsable QA | Recherche d'une chaîne de test unique | Après le déploiement en staging | | 9 | Chemin de retour arrière défini et testé | Ingénieur DevOps | Simuler une défaillance et revenir en arrière | Après le déploiement en staging | | 10 | Le test de fumée du déploiement en production inclut une vérification des logs | Responsable SRE | Étape du pipeline échoue si le log est manquant | À chaque déploiement en production | Les responsables sont des individus nommés, pas des groupes. Si l'équipe compte moins de cinq personnes, la même personne peut posséder plusieurs éléments, mais chaque élément doit avoir un point de contact unique qui peut dire oui ou non avant de procéder. Revisitez le choix du driver trimestriellement : les backends de logging changent, le volume de logs augmente et les nouvelles versions de Docker ajoutent ou déprécient des drivers. ## Pièges courants et comment les éviter ### Piège 1 : Supposer que le logging par défaut de Docker est suffisant De nombreuses équipes ne configurent jamais le logging et comptent sur le défaut du démon `json-file` sans rotation. Sur un conteneur très actif, le fichier de log peut atteindre des dizaines de gigaoctets et remplir le disque hôte. **Pourquoi cela arrive** : Manque de visibilité sur l'utilisation du disque hôte et fausse impression que Docker gère automatiquement les logs. **Prévention** : Définissez `max-size` et `max-file` sur chaque conteneur, soit dans Compose, soit via les défauts du démon. Surveillez l'utilisation du disque par conteneur avec une métrique d'agent hôte. **Récupération** : Tronquez rapidement le fichier de log avec `truncate -s 0 /var/lib/docker/containers//-json.log` (nécessite root) ou redémarrez le conteneur avec la rotation configurée. ### Piège 2 : Passer à un driver de logging centralisé sans préserver `docker logs` pour le débogage Les développeurs comptent souvent sur `docker logs` pour un dépannage rapide. Lorsque vous passez à `fluentd` ou `syslog`, `docker logs` peut ne rien afficher, et les développeurs sont forcés d'utiliser un outil différent qu'ils ne connaissent pas. **Pourquoi cela arrive** : L'équipe assimile la journalisation centralisée à un meilleur débogage sans considérer le flux de travail local. **Prévention** : Gardez `json-file` comme driver pour le développement et le staging, et utilisez un sidecar ou une configuration au niveau du démon pour expédier les logs. En production, documentez la requête de log équivalente pour le système central. **Récupération** : Installez un agrégateur local tel que Fluent Bit qui accepte les logs du driver distant et les écrit dans un fichier pour un `grep` rapide, ou exécutez un conteneur frère temporaire avec `docker run --log-driver=json-file` pour le débogage. ### Piège 3 : Ignorer la rotation des logs lors de l'utilisation de `journald` Le driver `journald` transmet les logs à journald, mais journald a ses propres limites de stockage qui sont souvent laissées par défaut. Sur un système avec une petite partition `/var/log/journal`, cela peut faire planter le journal et casser la journalisation système, pas seulement les logs des conteneurs. **Pourquoi cela arrive** : Les opérateurs ne configurent que les options Docker et oublient le service système sous-jacent. **Prévention** : Configurez `SystemMaxUse=1G` dans `/etc/systemd/journald.conf` et redémarrez journald. Surveillez la taille du journal. **Récupération** : Si la partition du journal est pleine, exécutez `journalctl --vacuum-size=500M` pour libérer de l'espace immédiatement, puis ajustez la configuration. ### Piège 4 : Changer de driver de logging au milieu d'une mise à jour progressive sans drainage Dans une mise à jour progressive, les anciens conteneurs sont arrêtés au fur et à mesure que les nouveaux arrivent. Si l'ancien conteneur a des logs en mémoire tampon et que le nouveau conteneur utilise un driver différent, les logs en attente peuvent être perdus. **Pourquoi cela arrive** : Le processus de déploiement ne tient pas compte du comportement de vidage du driver. **Prévention** : Drainez les logs en attendant une période calme ou en envoyant un signal qui vide avant l'arrêt. Alternativement, concevez le logging pour qu'il aille directement de l'application à un sidecar, en contournant le driver. **Récupération** : Dans la plupart des cas, les logs perdus sont des messages de démarrage à faible volume, mais pour les logs d'audit, envisagez de répliquer vers un montage de fichier lu par un expéditeur de logs. ## Conclusion L'automatisation CI/CD des drivers de logging Docker est un processus reproductible, pas une commande ponctuelle. Chaque changement doit être versionné, observable et réversible. Le flux de travail décrit ici suit un schéma cohérent : inventorier l'état actuel, déclarer l'état souhaité dans un fichier révisé, valider localement, déployer via un pipeline qui vérifie le flux de logs, et maintenir un commit de retour arrière. Comme prochaine étape, choisissez un conteneur dans un environnement de staging qui repose actuellement sur le `json-file` par défaut. Ajoutez des options de rotation explicites dans Compose, déployez et vérifiez que le conteneur démarre avec les options et que la rotation des logs fonctionne après avoir généré un grand volume de logs de test. Documentez les commandes exactes et les sorties attendues dans le runbook de votre équipe, puis planifiez une revue trimestrielle pour réévaluer les choix de driver à mesure que le volume de logs et l'infrastructure évoluent. Un flux de travail technique fiable rend les défaillances visibles, protège les valeurs sensibles, limite les changements à la ressource prévue et définit la vérification de la récupération avant qu'un incident ne force la décision. Le logging est le dernier kilomètre de l'observabilité ; le traiter avec la même rigueur que le code applicatif permet aux équipes de déboguer, auditer et opérer en toute confiance.