## Introduction

Les pilotes de journalisation Docker contrôlent la façon dont les journaux de conteneurs sont collectés et stockés. Le pilote par défaut `json-file` écrit les journaux localement, mais d'autres pilotes peuvent les envoyer vers un système distant, ajouter des métadonnées ou réduire l'utilisation du disque. Mettre en place un laboratoire local vous permet de tester le comportement des pilotes sans toucher aux environnements de production.

Ce guide présente un laboratoire complet de pilotes de journalisation Docker sur un hôte Linux unique. Vous allez inspecter la configuration actuelle, configurer et tester plusieurs pilotes, apprendre à faire tourner et lire les journaux, et vous entraîner à la récupération en cas de problème. Chaque étape inclut des commandes à exécuter et les résultats attendus, afin de pouvoir vérifier chaque résultat avant de continuer.

Les exemples supposent Docker Engine 24.0 ou version ultérieure, avec la CLI Docker et Docker Compose v2 installés. Sans accès au journal systemd ou à rsyslog, certains pilotes peuvent ne pas fonctionner comme indiqué. Nous aborderons les prérequis pour chaque pilote.

## Inventaire de la version et de l'environnement

Avant de modifier toute configuration, enregistrez votre version de Docker, le pilote de stockage et la configuration de journalisation actuelle. Cela vous donne un point de restauration et vous aide à repérer les options incompatibles.

Exécutez ces commandes et sauvegardez la sortie :

```bash
docker version --format '{{.Server.Version}}'
docker info --format 'Storage Driver: {{.Driver}}'
docker info --format 'Logging Driver: {{.LoggingDriver}}'
```

La sortie attendue sur une installation Docker fraîche peut ressembler à ceci :

```text
24.0.7
Storage Driver: overlay2
Logging Driver: json-file
```

Si votre sortie diffère, notez-la. Par exemple, certaines images cloud définissent `journald` ou `syslog` comme pilote par défaut. Le laboratoire suppose que vous pouvez remplacer le pilote par conteneur au moment de l'exécution, ce que toutes les versions modernes de Docker prennent en charge.

Vérifiez également que vous avez la permission d'exécuter Docker sans `sudo`. Si ce n'est pas le cas, ajoutez votre utilisateur au groupe `docker` et reconnectez-vous. Ce n'est pas strictement requis, mais cela évite les erreurs de permission lors de la lecture des fichiers journaux.

## Chemin de configuration sûr

Nous allons configurer chaque pilote de journalisation avec un ensemble minimal d'options, puis exécuter un conteneur qui écrit des lignes de journal prévisibles. Cela permet de garder les modifications petites et faciles à annuler.

### Pilote json-file par défaut et rotation des journaux

Le pilote `json-file` stocke les journaux sous forme d'objets JSON dans `/var/lib/docker/containers/<container-id>/<container-id>-json.log`. Sans rotation, ce fichier peut croître jusqu'à remplir le disque. La meilleure pratique de production consiste à définir `max-size` et `max-file`.

Démarrez un conteneur avec des paramètres de rotation explicites :

```bash
docker run -d --name log-json \
  --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  alpine sh -c 'while true; do echo "$(date) hello from json-file"; sleep 1; done'
```

Cela écrit une ligne par seconde. Pour créer suffisamment de données pour la rotation, vous pouvez temporairement réduire `max-size` à `1k` dans un second conteneur :

```bash
docker run -d --name log-rotate-test \
  --log-driver json-file \
  --log-opt max-size=1k \
  --log-opt max-file=3 \
  alpine sh -c 'while true; do echo "$(date) rotate me"; done'
```

Après une minute environ, listez les fichiers journaux :

```bash
sudo ls -lh /var/lib/docker/containers/$(docker inspect -f '{{.Id}}' log-rotate-test)/
```

Vous devriez voir plusieurs fichiers se terminant par `-json.log`, `-json.log.1`, `-json.log.2`, et éventuellement un fichier compressé `.gz`, selon votre version de Docker. Cela confirme que la rotation fonctionne.

Arrêtez et supprimez les conteneurs de test avant de continuer :

```bash
docker rm -f log-json log-rotate-test
```

### Pilote syslog

Le pilote `syslog` envoie les journaux vers un démon syslog. Sur la plupart des hôtes Linux, `rsyslog` ou `syslog-ng` est déjà en cours d'exécution. Si ce n'est pas le cas, installez rsyslog :

```bash
sudo apt update && sudo apt install -y rsyslog   # Debian/Ubuntu
sudo systemctl start rsyslog
```

Exécutez un conteneur utilisant le pilote syslog :

```bash
docker run -d --name log-syslog \
  --log-driver syslog \
  --log-opt syslog-address=udp://127.0.0.1:514 \
  --log-opt tag="docker/{{.Name}}" \
  alpine sh -c 'echo "syslog test from container" && sleep 60'
```

Vérifiez le syslog de l'hôte :

```bash
sudo tail -n 5 /var/log/syslog | grep 'syslog test'
```

La sortie attendue inclut une ligne avec le tag `docker/log-syslog` et le message. Si vous ne voyez rien, confirmez que rsyslog écoute sur UDP 514 :

```bash
sudo ss -ulnp | grep 514
```

La sortie devrait montrer un processus comme `rsyslogd` écoutant sur `0.0.0.0:514`. Sinon, éditez `/etc/rsyslog.conf` et décommentez les lignes pour la réception UDP syslog, puis redémarrez rsyslog.

Arrêtez le conteneur après vérification :

```bash
docker rm -f log-syslog
```

### Pilote journald

Le pilote `journald` écrit les journaux dans le journal systemd. Cela nécessite que le démon Docker s'exécute sur un hôte avec systemd. Vérifiez si journald est disponible :

```bash
systemctl is-active systemd-journald
```

Sortie attendue : `active`. Si elle indique `inactive` ou `failed`, vous devez le démarrer avec `sudo systemctl start systemd-journald`.

Exécutez un conteneur avec le pilote journald :

```bash
docker run -d --name log-journald \
  --log-driver journald \
  --log-opt tag="docker-journald-test" \
  alpine sh -c 'echo "journald test" && sleep 60'
```

Lisez le journal depuis le journal systemd :

```bash
journalctl CONTAINER_NAME=log-journald --no-pager
```

La sortie attendue inclut la ligne `journald test` avec des métadonnées systemd. Si vous voyez une erreur de permission, exécutez `journalctl` avec `sudo` ou assurez-vous que votre utilisateur est dans le groupe `systemd-journal`.

### Pilote fluentd

Le pilote `fluentd` envoie les journaux vers une instance Fluentd. C'est utile lorsque vous exécutez déjà Fluentd pour l'agrégation de journaux. Pour un laboratoire rapide, démarrez un conteneur Fluentd qui écoute sur le port TCP 24224 et écrit les journaux transférés sur stdout.

Créez un fichier de configuration Fluentd minimal `fluent.conf` :

```text
<source>
  @type forward
  port 24224
</source>
<match **>
  @type stdout
</match>
```

Exécutez Fluentd :

```bash
docker run -d --name fluentd-lab \
  -p 24224:24224 \
  -v $(pwd)/fluent.conf:/fluentd/etc/fluent.conf \
  fluent/fluentd:v1.16-1
```

Attendez quelques secondes, puis exécutez un conteneur qui utilise le pilote fluentd :

```bash
docker run --rm --name log-fluentd \
  --log-driver fluentd \
  --log-opt fluentd-address=127.0.0.1:24224 \
  alpine echo "fluentd test from container"
```

Vérifiez les journaux de Fluentd pour voir l'entrée transmise :

```bash
docker logs fluentd-lab | tail -n 3
```

La sortie attendue inclut une ligne contenant `"fluentd test from container"` au format d'événement Fluentd. Si la connexion échoue, vérifiez que Fluentd écoute :

```bash
docker logs fluentd-lab | grep 'listening'
```

Vous devriez voir une ligne comme `listening fluent socket on 0.0.0.0:24224`.

Arrêtez Fluentd lorsque vous avez terminé :

```bash
docker rm -f fluentd-lab
```

### Pilote gelf (optionnel)

Le pilote `gelf` envoie les journaux vers un point de terminaison Graylog ou autre compatible GELF. Pour un laboratoire, vous pouvez utiliser un simple écouteur UDP pour tester le format. Voici un serveur UDP Python rapide qui imprime les datagrammes reçus :

```bash
docker run --rm -d --name gelf-listener \
  -p 12201:12201/udp \
  python:3.11-alpine python -c "
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('0.0.0.0', 12201))
while True:
    data, addr = s.recvfrom(65535)
    print(data.decode(), flush=True)
"
```

Maintenant, exécutez un conteneur qui journalise vers GELF UDP :

```bash
docker run --rm --name log-gelf \
  --log-driver gelf \
  --log-opt gelf-address=udp://127.0.0.1:12201 \
  alpine echo "gelf test"
```

Vérifiez la sortie de l'écouteur :

```bash
docker logs gelf-listener
```

Vous devriez voir une charge utile JSON GELF contenant le message `gelf test`. Sinon, vérifiez le mappage du port UDP avec `docker port gelf-listener`.

Nettoyez :

```bash
docker rm -f gelf-listener
```

## Vérification et diagnostic

Après avoir configuré un pilote, vous devez confirmer que les journaux circulent réellement et que le pilote ne laisse pas passer silencieusement des messages.

### Vérifier la sélection du pilote

Utilisez `docker inspect` pour voir quel pilote de journalisation un conteneur utilise et ses options :

```bash
docker inspect -f '{{.HostConfig.LogConfig.Type}} {{.HostConfig.LogConfig.Config}}' <container-name>
```

Par exemple, pour le conteneur `log-json` que vous avez exécuté précédemment, la sortie serait :

```text
json-file map[max-file:3 max-size:10m]
```

Exécutez cette commande pour chaque conteneur après sa création afin de détecter les fautes de frappe dans les noms de pilotes ou les options.

### Lire les journaux avec docker logs

`docker logs` fonctionne pour la plupart des pilotes, mais son comportement peut différer. Les pilotes `json-file` et `journald` prennent en charge `docker logs` nativement. Les pilotes `syslog` et `fluentd` ne renvoient pas les journaux via `docker logs` ; vous devez interroger la destination externe.

Testez ce comportement :

```bash
docker logs log-syslog
```

Attendu : une erreur comme `the logging driver "syslog" does not support the "logs" subcommand` ou aucune sortie du tout. C'est une limitation connue. Planifiez vos diagnostics en conséquence : pour les pilotes distants, vérifiez le point de terminaison de réception au lieu de `docker logs`.

### Inspecter les fichiers journaux sur le disque

Pour le pilote `json-file`, vous pouvez lire directement le fichier journal pour voir la structure JSON :

```bash
sudo cat /var/lib/docker/containers/$(docker inspect -f '{{.Id}}' <container>) /<container>-json.log | head -n 2
```

Chaque ligne est un objet JSON avec les clés `log`, `stream` et `time`. Par exemple :

```json
{"log":"hello from json-file\n","stream":"stdout","time":"2025-03-20T15:04:05Z"}
```

C'est utile pour les scripts ou lors du débogage d'outils d'analyse de journaux.

### Vérifier les métriques du pilote

Docker expose les erreurs du pilote de journalisation dans les journaux du démon. Pour voir si le démon a des difficultés avec un pilote, consultez le journal du démon Docker :

```bash
sudo journalctl -u docker.service --since "10 minutes ago" | grep -i 'log'
```

Recherchez des messages comme `Failed to log message` ou des erreurs spécifiques au pilote. Pour le pilote syslog, une erreur courante est `connection refused` si l'adresse syslog est incorrecte.

## Modes de défaillance et récupération

Les pilotes de journalisation peuvent échouer de manière non immédiatement évidente. Connaître les modes de défaillance courants vous aide à récupérer rapidement et à concevoir des configurations de journalisation robustes.

### Défaillance : les journaux json-file remplissent le disque

Symptôme : Les conteneurs cessent d'écrire des journaux, ou le démon Docker signale `no space left on device`. La cause racine est généralement l'absence de rotation des journaux.

Récupération :

1. Trouvez les fichiers journaux les plus volumineux :

   ```bash
   sudo find /var/lib/docker/containers -name '*-json.log' -size +100M -ls
   ```

2. Tronquez immédiatement les journaux surdimensionnés pour libérer de l'espace :

   ```bash
   sudo truncate -s 0 /var/lib/docker/containers/<container-id>/<container-id>-json.log
   ```

3. Prévenez la récurrence en définissant `max-size` et `max-file` sur le conteneur. Vous pouvez également définir des valeurs par défaut globales dans le fichier de configuration du démon `/etc/docker/daemon.json` :

   ```json
   {
     "log-driver": "json-file",
     "log-opts": {
       "max-size": "10m",
       "max-file": "3"
     }
   }
   ```

   Redémarrez Docker après avoir modifié `daemon.json` :

   ```bash
   sudo systemctl restart docker
   ```

   Remarque : Ce redémarrage arrêtera tous les conteneurs en cours d'exécution. Faites-le pendant une fenêtre de maintenance.

### Défaillance : le pilote syslog ne peut pas se connecter

Symptôme : Le conteneur démarre, mais aucun journal n'apparaît dans `/var/log/syslog`. Le journal du démon Docker affiche `connection refused` pour l'adresse syslog.

Récupération :

1. Vérifiez que le démon syslog est en cours d'exécution et écoute sur le socket attendu :

   ```bash
   sudo ss -ulnp | grep 514
   ```

2. Si rien n'écoute, démarrez rsyslog :

   ```bash
   sudo systemctl start rsyslog
   ```

3. Si vous exécutez un serveur syslog conteneurisé, assurez-vous que son port est publié correctement. Pour l'exemple précédent, le récepteur syslog utilisait `udp://127.0.0.1:514`. Si vous exécutez le récepteur dans un conteneur, vous devez publier le port UDP 514 et utiliser l'IP de l'hôte.

4. Pour éviter les échecs de connexion futurs, ajoutez une nouvelle tentative et un délai d'attente plus long aux options du pilote :

   ```bash
   --log-opt syslog-address=udp://127.0.0.1:514 \
   --log-opt syslog-retries=5 \
   --log-opt syslog-timeout=10s
   ```

### Défaillance : le pilote journald perd des journaux au redémarrage

Symptôme : Les journaux d'un conteneur sont manquants après son redémarrage. Le pilote `journald` étiquette les journaux avec l'ID du conteneur, pas le nom. Si le conteneur est supprimé et recréé, l'ID change et les anciens journaux sont plus difficiles à trouver.

Récupération :

1. Utilisez l'ID du conteneur pour interroger les journaux :

   ```bash
   journalctl CONTAINER_ID=<full-container-id>
   ```

2. Ajoutez un tag personnalisé incluant le nom du conteneur pour faciliter le filtrage :

   ```bash
   --log-opt tag="myapp-{{.Name}}"
   ```

   Puis interrogez avec :

   ```bash
   journalctl SYSLOG_IDENTIFIER=myapp-<name>
   ```

3. Dans les fichiers Compose, vous pouvez définir un nom de conteneur stable avec `container_name` pour rendre le tag prévisible.

### Défaillance : les tampons du pilote fluentd se remplissent

Symptôme : Les journaux du conteneur sont retardés, ou le pilote fluentd signale un débordement de tampon. Le pilote fluentd met en mémoire tampon les journaux lorsque le point de terminaison Fluentd est lent ou inaccessible. Si le tampon se remplit, le conteneur peut bloquer ou abandonner des journaux.

Récupération :

1. Vérifiez le journal du démon Docker pour les erreurs fluentd :

   ```bash
   sudo journalctl -u docker.service | grep fluentd
   ```

2. Augmentez la limite de tampon fluentd si vous vous attendez à des rafales :

   ```bash
   --log-opt fluentd-buffer-limit=64m
   ```

3. Assurez-vous que le point de terminaison Fluentd a une capacité suffisante. Ajustez les intervalles de vidage et les tailles de tampon côté serveur.

4. Pour la production, utilisez un collecteur de journaux dédié avec une file d'attente appropriée, comme Fluentd avec un tampon fichier.

### Défaillance : le pilote gelf perd des journaux via UDP

Symptôme : Certains journaux n'apparaissent jamais au point de terminaison GELF. UDP est sans connexion et ne garantit pas la livraison. Sous charge ou en cas de problèmes réseau, des paquets peuvent être perdus.

Récupération :

1. Utilisez TCP au lieu d'UDP pour GELF si votre point de terminaison le prend en charge :

   ```bash
   --log-opt gelf-address=tcp://127.0.0.1:12201
   ```

2. Augmentez le `gelf-compression-level` pour réduire la bande passante, mais cela n'empêche pas la perte UDP. Pour une livraison fiable, utilisez un pilote qui prend en charge TCP ou une file de messages.

3. Surveillez le point de terminaison pour les numéros de séquence manquants ou les lacunes dans les journaux.

## Pièges courants et comment les éviter

Plusieurs erreurs reviennent fréquemment lorsque l'on travaille avec les pilotes de journalisation Docker en laboratoire ou en production. En être conscient permet de gagner du temps et d'éviter la perte de données.

### Ignorer la prise en charge de docker logs par le pilote

Beaucoup d'utilisateurs supposent que `docker logs` fonctionne pour tous les pilotes. Ce n'est pas le cas. Les pilotes `json-file`, `journald` et `local` prennent en charge `docker logs`. Les pilotes `syslog`, `fluentd`, `gelf` et `awslogs` ne le prennent pas en charge. Si vous comptez sur `docker logs` pour le débogage, choisissez un pilote compatible.

**Comment éviter :** Avant de sélectionner un pilote, vérifiez la documentation Docker pour sa prise en charge de `docker logs`. Testez avec un petit conteneur tôt.

### Ne pas définir la rotation des journaux pour json-file

Le pilote `json-file` par défaut n'a pas de limite de taille. Au fil des mois, les journaux peuvent consommer tout l'espace disque, provoquant des défaillances de Docker et d'autres services.

**Comment éviter :** Définissez toujours `max-size` et `max-file` sur chaque conteneur utilisant `json-file`. Mieux encore, définissez des valeurs par défaut globales dans la configuration du démon.

### Utiliser des montages bind pour les fichiers journaux sans permissions appropriées

Lorsque vous montez un répertoire de l'hôte pour stocker les fichiers journaux, l'utilisateur du conteneur peut ne pas avoir la permission d'écriture, ce qui empêche l'application de démarrer.

**Comment éviter :** Vérifiez l'utilisateur du conteneur et les permissions du montage. Utilisez plutôt un volume nommé :

```bash
docker volume create app-logs
docker run -d --name app \
  -v app-logs:/var/log/app \
  --log-driver json-file \
  myapp
```

Les volumes nommés sont gérés par Docker et gèrent les permissions plus élégamment.

### Mélanger les options du pilote de journalisation avec les paramètres au niveau du démon

Si vous définissez un pilote de journalisation global dans `daemon.json` mais que vous passez aussi `--log-driver` sur le conteneur, l'option du conteneur remplace le global. Cela peut conduire à une journalisation incohérente.

**Comment éviter :** Documentez le pilote prévu pour chaque service. Utilisez des options explicites au niveau du conteneur uniquement pour les cas spéciaux. Vérifiez avec `docker inspect` après le démarrage.

### Oublier de publier les ports UDP pour les récepteurs de journalisation distants

Lorsque vous exécutez un récepteur syslog ou GELF dans un conteneur, vous devez publier son port UDP. Omettre `-p 514:514/udp` entraîne un échec silencieux ; le conteneur émetteur ne peut pas joindre le récepteur sur localhost.

**Comment éviter :** Vérifiez toujours les mappages de ports avec `docker port <receiver-container>`. Testez la connectivité avec `nc -u <host> <port>` avant de vous fier à la configuration.

### Ne pas nettoyer les conteneurs et fichiers de laboratoire

Après les tests, les conteneurs orphelins et les fichiers de configuration résiduels peuvent interférer avec les expériences ultérieures ou consommer des ressources.

**Comment éviter :** Gardez un script de nettoyage. Par exemple :

```bash
docker rm -f log-json log-syslog log-journald log-fluentd log-gelf
rm -f fluent.conf
```

Exécutez régulièrement `docker system prune` dans un environnement de laboratoire, mais soyez prudent sur les hôtes partagés ou de production.

## Liste de contrôle des opérations

Utilisez cette liste de contrôle chaque fois que vous déployez ou modifiez un pilote de journalisation Docker dans un environnement de laboratoire ou de type production.

| Étape | Action | Responsable | Fréquence de révision |
|------|--------|-------|-------------------|
| 1 | Confirmer la version de Docker et les valeurs par défaut du démon de journalisation avec `docker info` | Ingénieur plateforme | Mensuelle |
| 2 | Documenter la destination des journaux prévue et la politique de conservation par service | Responsable DevOps | Trimestrielle |
| 3 | Appliquer la rotation des journaux pour le pilote json-file globalement dans `daemon.json` | Ingénieur plateforme | Sur changement |
| 4 | Tester chaque pilote avec un conteneur jetable et vérifier les journaux à destination | Développeur | À chaque déploiement |
| 5 | Vérifier l'utilisation du disque et les tailles des journaux hebdomadairement | Équipe de surveillance | Hebdomadaire |
| 6 | Examiner la compatibilité du pilote avec `docker logs` pour les besoins de débogage | Développeur | Par service |
| 7 | Effectuer un exercice de défaillance : arrêter le récepteur de journaux et observer le comportement du pilote | SRE | Trimestrielle |
| 8 | Mettre à jour la documentation après tout changement de pilote | Rédacteur technique | Sur changement |

Chaque élément a un seul responsable chargé de l'exécution et du suivi. La fréquence de révision garantit que la liste de contrôle reste pertinente à mesure que l'infrastructure évolue.

### Exemple de configuration utilisant Docker Compose

Un fichier Compose complet pour un service web avec journalisation json-file et rotation :

```yaml
version: '3.8'
services:
  web:
    image: nginx:1.25
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
    deploy:
      resources:
        limits:
          memory: 128M
```

Pour un service qui envoie des journaux à un sidecar Fluentd, vous pouvez définir :

```yaml
services:
  app:
    image: myapp:latest
    logging:
      driver: fluentd
      options:
        fluentd-address: "fluentd:24224"
        tag: "app.{{.Name}}"
  fluentd:
    image: fluent/fluentd:v1.16-1
    ports:
      - "24224:24224"
    volumes:
      - ./fluent.conf:/fluentd/etc/fluent.conf
```

Cela garde la configuration de journalisation visible et sous contrôle de version.

## Conclusion

Un laboratoire local pour les pilotes de journalisation Docker vous offre un environnement sûr pour comprendre le comportement des pilotes, tester les options de configuration et vous entraîner à la récupération. En suivant les étapes de ce guide, vous avez configuré et vérifié les pilotes `json-file`, `syslog`, `journald`, `fluentd` et `gelf`, appris à lire les journaux de différentes destinations et vous êtes préparé aux défaillances courantes.

Rappelez-vous ces pratiques clés :

- Toujours définir la rotation des journaux pour les pilotes locaux.
- Vérifier si un pilote prend en charge `docker logs` avant de s'y fier pour le débogage.
- Vérifier la connectivité vers les points de terminaison de journaux distants du point de vue du conteneur.
- Utiliser `docker inspect` pour confirmer le pilote de journalisation effectif et ses options.
- Garder un plan de restauration : stocker la configuration précédente du démon et les commandes d'exécution des conteneurs.

Pour la production, choisissez un pilote de journalisation qui correspond à votre infrastructure de journaux centrale et à vos besoins de conservation. Testez-le avec des volumes de journaux réalistes et un test de charge. Documentez le comportement en cas de défaillance et les seuils de surveillance. Une bonne configuration de journalisation n'est pas statique ; elle nécessite une révision et un ajustement périodiques.

Commencez par un changement à faible risque dans votre laboratoire, observez le résultat, puis appliquez-le à un environnement de préproduction avant la production. Cette approche incrémentale renforce la confiance et réduit le risque de perte de journaux ou de perturbation du service.