Rotation des logs Docker : empêcher vos logs de saturer le disque VPS
Le driver de logs par défaut de Docker stocke des données sans limite. Un seul conteneur actif peut remplir un disque de 50 Go en quelques jours. Ce tutoriel configure la rotation globale des logs, les limites par service dans Compose, le nettoyage automatisé et la surveillance de l'espace disque.
La configuration de logging par défaut de Docker n'a aucune limite de taille. Chaque ligne écrite par vos conteneurs sur stdout ou stderr est stockée sur disque indéfiniment. Sur un VPS avec 25 Go ou 50 Go de stockage, un seul conteneur bavard peut consommer tout l'espace disponible en quelques jours.
Ce tutoriel corrige ce problème. Vous allez configurer la rotation globale des logs, définir des limites par service dans Docker Compose, automatiser le nettoyage du disque et mettre en place une surveillance pour ne jamais être pris au dépourvu.
Toutes les commandes sont testées sur Debian 12 et Ubuntu 24.04 avec Docker Engine 28.x/29.x.
Prérequis :
- Un VPS sous Debian 12 ou Ubuntu 24.04 avec Docker installé
- Un accès SSH avec un utilisateur sudo
- Une familiarité de base avec Docker et Docker Compose
Pourquoi les logs des conteneurs Docker remplissent-ils votre disque ?
Le driver de logs par défaut de Docker est json-file. Il capture tout ce qu'un conteneur écrit sur stdout et stderr, puis le stocke au format JSON dans /var/lib/docker/containers/<container-id>/<container-id>-json.log. Par défaut, il n'y a aucune taille maximale et aucune rotation. Le fichier grossit jusqu'à ce que votre disque soit plein.
Une application Node.js qui log au niveau INFO produit environ 50 Mo par jour. Un reverse proxy sous trafic modéré peut générer 200 Mo ou plus. Sur un VPS de 50 Go, un seul conteneur non géré peut consommer tout l'espace libre en quelques semaines.
Quand le disque est plein, tout casse en même temps : les conteneurs ne peuvent plus écrire, les bases de données plantent, les sessions SSH peuvent se figer, et vous ne pouvez même plus vous connecter pour résoudre le problème.
Comment vérifier l'utilisation actuelle du disque
Avant de modifier quoi que ce soit, mesurez les dégâts :
df -h /var/lib/docker
Cette commande affiche l'espace utilisé par le répertoire de données Docker. Ensuite, obtenez un détail spécifique à Docker :
docker system df
Sortie attendue :
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 5 3 1.2GB 450MB (37%)
Containers 8 4 3.8GB 3.1GB (81%)
Local Volumes 3 2 500MB 120MB (24%)
Build Cache 12 0 800MB 800MB (100%)
La ligne « Containers » affiche la taille des fichiers de logs. Si ce nombre est disproportionné, les logs sont le problème.
Pour un détail par conteneur :
docker system df -v
Cette commande liste chaque conteneur avec la taille de ses logs. Identifiez les responsables.
Comment trouver directement les plus gros fichiers de logs
Si docker system df confirme le problème, trouvez exactement quels logs consomment de l'espace :
sudo find /var/lib/docker/containers/ -name "*-json.log" -exec ls -sh {} + | sort -rh | head -10
Cette commande liste les 10 plus gros fichiers de logs de conteneurs avec leurs tailles.
Triage d'urgence : récupérer de l'espace disque immédiatement
Si votre disque est déjà plein ou presque, corrigez le problème immédiat avant de configurer la rotation.
Tronquer le fichier de log d'un conteneur spécifique (sans arrêter le conteneur) :
sudo truncate -s 0 /var/lib/docker/containers/<container-id>/<container-id>-json.log
Remplacez <container-id> par l'identifiant réel du conteneur obtenu via docker ps --no-trunc -q.
Pour tronquer tous les fichiers de logs Docker d'un coup :
sudo sh -c 'truncate -s 0 /var/lib/docker/containers/*/*-json.log'
Vérifiez que l'espace a été récupéré :
df -h /var/lib/docker
C'est un correctif temporaire. Les logs vont repousser. Les sections suivantes rendent le correctif permanent.
Comment configurer la rotation des logs dans daemon.json ?
Le fichier daemon.json définit les options de logging par défaut pour tous les nouveaux conteneurs. Le driver json-file de Docker supporte max-size (taille maximale par fichier de log avant rotation) et max-file (nombre de fichiers de rotation conservés). Toutes les valeurs dans log-opts doivent être des chaînes de caractères, même les nombres.
Créez ou éditez la configuration du daemon :
sudo nano /etc/docker/daemon.json
Si le fichier n'existe pas, créez-le. S'il contient déjà une configuration (registres personnalisés, DNS, etc.), ajoutez les clés log-driver et log-opts à côté des options existantes.
Recommandations de dimensionnement par taille de disque VPS
Choisissez les valeurs en fonction de la taille du disque de votre VPS :
| Taille du disque VPS | max-size |
max-file |
Max log par conteneur | Justification |
|---|---|---|---|---|
| 25 Go | 5m |
3 |
15 Mo | Disque limité ; logs minimaux |
| 50 Go | 10m |
5 |
50 Mo | VPS standard ; rétention équilibrée |
| 100 Go | 25m |
5 |
125 Mo | Disque généreux ; rétention plus longue |
| 200 Go+ | 50m |
5 |
250 Mo | Grand disque ; débogage prolongé |
Pour un VPS de 50 Go (le choix le plus courant), utilisez cette configuration :
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
Enregistrez le fichier, puis redémarrez Docker :
sudo systemctl restart docker
Vérifiez que les nouveaux paramètres par défaut sont actifs :
docker info --format '{{.LoggingDriver}}'
Sortie attendue :
json-file
Confirmez que les options de log s'appliquent aux nouveaux conteneurs en en lançant un et en l'inspectant :
docker run -d --name log-test alpine echo "test" && docker inspect --format '{{.HostConfig.LogConfig}}' log-test && docker rm log-test
Sortie attendue :
{json-file map[max-file:5 max-size:10m]}
Que se passe-t-il pour les conteneurs en cours d'exécution après modification de daemon.json ?
Les conteneurs existants conservent leur configuration de logs d'origine. Les nouveaux paramètres ne s'appliquent qu'aux conteneurs créés après le redémarrage. Les conteneurs en cours d'exécution doivent être recréés pour hériter des nouveaux paramètres.
Si vous utilisez Docker Compose :
docker compose down && docker compose up -d
Pour les conteneurs autonomes, arrêtez-les et supprimez-les, puis relancez-les. Le flag --force-recreate fonctionne aussi :
docker compose up -d --force-recreate
Vérifiez qu'un conteneur spécifique utilise la nouvelle configuration :
docker inspect --format '{{.HostConfig.LogConfig}}' <container-name>
Sortie attendue :
{json-file map[max-file:5 max-size:10m]}
Comment définir les limites de logs dans Docker Compose ?
La configuration de log par service dans Docker Compose remplace les valeurs par défaut de daemon.json. Cela permet de donner des limites plus strictes aux services bavards et plus de marge aux services silencieux.
Ajoutez le bloc logging sous n'importe quel service :
services:
web:
image: nginx:alpine
logging:
driver: json-file
options:
max-size: "5m"
max-file: "3"
ports:
- "80:80"
api:
image: node:22-alpine
logging:
driver: json-file
options:
max-size: "20m"
max-file: "5"
ports:
- "3000:3000"
Pour éviter de répéter le bloc logging dans chaque service, utilisez une ancre YAML :
x-logging: &default-logging
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
services:
web:
image: nginx:alpine
<<: *default-logging
ports:
- "80:80"
api:
image: node:22-alpine
<<: *default-logging
ports:
- "3000:3000"
worker:
image: myapp/worker:latest
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
Le service worker remplace l'ancre par ses propres limites. Tous les autres services héritent de la configuration partagée.
Appliquez la configuration :
docker compose up -d --force-recreate
Contrôle :
docker inspect --format '{{.HostConfig.LogConfig}}' web
Quelle est la différence entre les drivers de logs json-file, local et journald ?
Docker fournit trois drivers de logs qui stockent les logs sur l'hôte. Chacun a ses compromis. Le driver json-file est celui par défaut. Le driver local est la recommandation de Docker pour l'efficacité disque. Le driver journald s'intègre au journal de systemd.
| Fonctionnalité | json-file | local | journald |
|---|---|---|---|
| Rotation par défaut | Aucune | Oui (100 Mo au total) | Gérée par journald |
| Compression | Optionnelle (compress: "true") |
Activée par défaut | Gérée par journald |
Support de docker logs |
Oui | Oui | Oui |
| Format des logs | JSON (lisible) | Binaire (interne) | Binaire (journald) |
| Accès par outils externes | Facile (fichiers texte) | Non supporté | Via journalctl |
| max-size par défaut | Illimité | 20 Mo par fichier | Défini dans journald.conf |
| max-file par défaut | 1 (pas de rotation) | 5 fichiers | N/A |
Quand utiliser chaque driver
json-file est le choix sûr par défaut. Il fonctionne partout, supporte docker logs, et les fichiers de logs sont du JSON lisible que n'importe quel outil peut analyser. Ajoutez max-size et max-file et il convient à la plupart des configurations VPS.
local est plus efficace en termes d'espace disque. La compression est activée par défaut, la rotation est intégrée (5 fichiers de 20 Mo = 100 Mo par conteneur), et vous n'avez rien à configurer. Le compromis : les fichiers de logs utilisent un format binaire interne. Les outils d'acheminement de logs qui lisent directement les fichiers (comme Filebeat en mode fichier) ne peuvent pas les analyser. Si vous ne lisez les logs que via docker logs ou les expédiez via un plugin de logging Docker, passez à local.
journald est le bon choix si vous utilisez déjà le journal de systemd pour tous vos autres services et que vous voulez les logs de conteneurs au même endroit. La rotation est gérée par la configuration propre de journald (/etc/systemd/journald.conf). Vous lisez les logs avec journalctl au lieu de docker logs (bien que docker logs fonctionne toujours).
Comment passer au driver local
Éditez /etc/docker/daemon.json :
{
"log-driver": "local",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
Redémarrez Docker :
sudo systemctl restart docker
Contrôle :
docker info --format '{{.LoggingDriver}}'
Sortie attendue :
local
Recréez les conteneurs pour appliquer le nouveau driver :
docker compose up -d --force-recreate
Comment utiliser le driver journald
Éditez /etc/docker/daemon.json :
{
"log-driver": "journald"
}
Redémarrez Docker :
sudo systemctl restart docker
Lisez les logs d'un conteneur spécifique :
sudo journalctl CONTAINER_NAME=mycontainer --no-pager -n 50
Suivez les logs en temps réel :
sudo journalctl CONTAINER_NAME=mycontainer -f
La rotation de journald se configure dans /etc/systemd/journald.conf. Paramètres importants :
[Journal]
SystemMaxUse=500M
SystemMaxFileSize=50M
MaxRetentionSec=7day
Après modification, redémarrez journald :
sudo systemctl restart systemd-journald
Comment automatiser le nettoyage Docker avec cron ou les timers systemd ?
La rotation des logs empêche chaque conteneur de grossir sans limite. Mais Docker accumule aussi des conteneurs arrêtés, des images inutilisées, du cache de build orphelin et des réseaux non utilisés. docker system prune nettoie tout cela.
Que supprime réellement docker system prune ?
Par défaut, docker system prune supprime :
- Tous les conteneurs arrêtés
- Tous les réseaux non utilisés par un conteneur en cours d'exécution
- Toutes les images pendantes (images non taguées et non référencées par un conteneur)
- Tout le cache de build inutilisé
Il ne supprime pas :
- Les conteneurs en cours d'exécution
- Les volumes nommés (vos données de base de données sont en sécurité)
- Les images taguées encore référencées
- Les images utilisées par des conteneurs en cours d'exécution
Le flag --all supprime en plus toutes les images inutilisées (pas seulement les pendantes). Le flag --volumes ajoute les volumes anonymes au nettoyage. Utilisez --volumes avec prudence : il détruit les données des volumes anonymes.
Option 1 : tâche cron
Créez une tâche de nettoyage hebdomadaire :
sudo crontab -e
Ajoutez :
0 3 * * 0 /usr/bin/docker system prune -f >> /var/log/docker-prune.log 2>&1
Cette commande s'exécute chaque dimanche à 03h00. Le flag -f désactive la demande de confirmation. La sortie est redirigée dans un fichier de log pour l'audit.
Vérifiez que le crontab a été enregistré :
sudo crontab -l
Option 2 : timer systemd (recommandé)
Les timers systemd sont plus fiables que cron. Ils enregistrent dans le journal, gèrent les exécutions manquées (si le serveur était éteint) et sont plus faciles à surveiller.
Créez l'unité de service :
sudo nano /etc/systemd/system/docker-prune.service
[Unit]
Description=Docker system prune
Wants=docker.service
After=docker.service
[Service]
Type=oneshot
ExecStart=/usr/bin/docker system prune -f --filter "until=168h"
Le flag --filter "until=168h" ne nettoie que les objets datant de plus de 7 jours. Cela protège les conteneurs récemment arrêtés que vous pourriez vouloir inspecter.
Créez le timer :
sudo nano /etc/systemd/system/docker-prune.timer
[Unit]
Description=Run Docker prune weekly
[Timer]
OnCalendar=Sun *-*-* 03:00:00
Persistent=true
RandomizedDelaySec=1800
[Install]
WantedBy=timers.target
Persistent=true signifie que si le serveur était éteint pendant l'heure prévue, la tâche s'exécute au prochain démarrage. RandomizedDelaySec répartit la charge si vous avez plusieurs serveurs.
Activez et démarrez le timer :
sudo systemctl daemon-reload
sudo systemctl enable --now docker-prune.timer
enable le rend persistant après redémarrage. --now le démarre immédiatement.
Vérifiez que le timer est actif :
sudo systemctl status docker-prune.timer
Vérifiez quand il s'exécutera :
sudo systemctl list-timers docker-prune.timer
Testez-le manuellement :
sudo systemctl start docker-prune.service
Vérifiez le résultat :
sudo journalctl -u docker-prune.service --no-pager -n 20
Comment nettoyer les volumes Docker en toute sécurité ?
Les volumes contiennent des données persistantes : bases de données, fichiers uploadés, configuration. Soyez prudent ici.
Listez tous les volumes et leur utilisation :
docker volume ls
Affichez uniquement les volumes non rattachés à un conteneur :
docker volume ls -f dangling=true
Supprimez les volumes pendants :
docker volume prune -f
Cette commande ne supprime que les volumes non utilisés par un conteneur (en cours d'exécution ou arrêté). Les volumes nommés rattachés à des conteneurs arrêtés sont en sécurité.
Vérifiez ce qui reste :
docker volume ls
N'exécutez jamais docker volume prune juste après docker system prune --volumes. Le system prune avec --volumes gère déjà le nettoyage des volumes. Exécuter les deux est au mieux redondant.
Pour supprimer un volume spécifique que vous avez identifié comme inutile :
docker volume rm <volume-name>
Vérifiez toujours les données contenues dans un volume avant de le supprimer :
docker volume inspect <volume-name>
Le champ Mountpoint indique où les données se trouvent sur le disque. Vous pouvez inspecter son contenu :
sudo ls -la $(docker volume inspect --format '{{.Mountpoint}}' <volume-name>)
Comment surveiller l'utilisation disque de Docker sur un VPS ?
La surveillance automatisée prévient les surprises. Cette section met en place une alerte de seuil qui vérifie l'utilisation disque de Docker et envoie un avertissement quand elle dépasse une limite.
Vérification manuelle rapide
Exécutez ces deux commandes quand vous voulez un état des lieux :
df -h /var/lib/docker
docker system df
Pour un détail par conteneur et par image :
docker system df -v
Script d'alerte automatisé
Créez un script de surveillance :
sudo nano /usr/local/bin/docker-disk-alert.sh
#!/bin/bash
# Alert when Docker's partition exceeds a usage threshold
THRESHOLD=80
MAILTO="admin@example.com"
USAGE=$(df /var/lib/docker | awk 'NR==2 {gsub(/%/,""); print $5}')
if [ "$USAGE" -ge "$THRESHOLD" ]; then
DOCKER_DF=$(docker system df 2>&1)
DISK_DF=$(df -h /var/lib/docker 2>&1)
TOP_LOGS=$(find /var/lib/docker/containers/ -name "*-json.log" -exec ls -sh {} + 2>/dev/null | sort -rh | head -5)
BODY="Docker disk usage on $(hostname) is at ${USAGE}%.
Disk usage:
${DISK_DF}
Docker breakdown:
${DOCKER_DF}
Largest log files:
${TOP_LOGS}"
echo "$BODY" | mail -s "ALERT: Docker disk at ${USAGE}% on $(hostname)" "$MAILTO"
logger -t docker-disk-alert "Docker disk usage at ${USAGE}% - alert sent"
fi
Définissez les permissions :
sudo chmod 750 /usr/local/bin/docker-disk-alert.sh
Vérifiez les permissions :
ls -la /usr/local/bin/docker-disk-alert.sh
Sortie attendue :
-rwxr-x--- 1 root root 612 Mar 19 12:00 /usr/local/bin/docker-disk-alert.sh
Le script nécessite mailutils (ou mailx) pour l'envoi d'e-mails. Installez-le s'il n'est pas présent :
sudo apt install -y mailutils
Testez le script :
sudo /usr/local/bin/docker-disk-alert.sh
Si votre utilisation disque est sous le seuil, rien ne se passe. Pour tester le chemin d'alerte, définissez temporairement THRESHOLD=1 dans le script, exécutez-le, puis remettez la valeur d'origine.
Planifier l'alerte avec un timer systemd
Créez le service :
sudo nano /etc/systemd/system/docker-disk-alert.service
[Unit]
Description=Check Docker disk usage
[Service]
Type=oneshot
ExecStart=/usr/local/bin/docker-disk-alert.sh
Créez le timer :
sudo nano /etc/systemd/system/docker-disk-alert.timer
[Unit]
Description=Check Docker disk usage every 6 hours
[Timer]
OnCalendar=*-*-* 00/6:00:00
Persistent=true
[Install]
WantedBy=timers.target
Activez-le :
sudo systemctl daemon-reload
sudo systemctl enable --now docker-disk-alert.timer
Contrôle :
sudo systemctl list-timers docker-disk-alert.timer
Dépannage
Le disque est plein et Docker ne démarre pas
Si Docker refuse de démarrer parce que le disque est complètement plein :
sudo truncate -s 0 /var/lib/docker/containers/*/*-json.log
sudo systemctl start docker
Puis configurez immédiatement la rotation des logs comme décrit plus haut.
Une erreur de syntaxe dans daemon.json empêche Docker de démarrer
Docker ne démarre pas si daemon.json contient du JSON invalide. Validez le fichier :
sudo python3 -m json.tool /etc/docker/daemon.json
Si la commande affiche le JSON formaté, la syntaxe est valide. Si elle affiche une erreur, corrigez la ligne indiquée.
Consultez le message d'erreur de Docker :
sudo journalctl -u docker.service -n 20 --no-pager
Les logs continuent de grossir après la configuration de la rotation
La rotation ne s'applique qu'aux nouveaux conteneurs. Les conteneurs existants conservent leur configuration d'origine. Recréez-les :
docker compose up -d --force-recreate
Vérifiez que la nouvelle configuration est bien appliquée :
docker inspect --format '{{.HostConfig.LogConfig}}' <container-name>
docker system prune n'a pas libéré beaucoup d'espace
docker system prune ne touche pas aux conteneurs en cours d'exécution, à leurs logs, ni aux volumes nommés. Si le problème d'espace vient spécifiquement des logs, tronquez les fichiers de logs ou configurez la rotation. Si ce sont les volumes, utilisez docker volume prune après avoir vérifié qu'aucune donnée nécessaire ne sera perdue.
Vérifiez ce qui consomme de l'espace :
sudo du -sh /var/lib/docker/*
Cette commande détaille l'utilisation par sous-système Docker : containers (logs), overlay2 (images/couches), volumes, et autres.
Résumé
Une gestion complète des logs Docker sur un VPS repose sur quatre niveaux :
- Rotation globale dans
/etc/docker/daemon.jsonavecmax-sizeetmax-fileempêche la croissance illimitée des logs pour tous les conteneurs. - Limites par service dans Docker Compose pour donner des limites plus strictes aux services bavards.
- Nettoyage automatisé avec
docker system prunesur un timer systemd pour supprimer les conteneurs morts, les images inutilisées et le cache de build. - Surveillance du disque avec un script d'alerte pour détecter les problèmes avant qu'ils ne provoquent des pannes.
Après cette mise en place, vérifiez que tout fonctionne : contrôlez docker inspect sur vos conteneurs, exécutez docker system df pour confirmer l'utilisation actuelle, et attendez que le timer de nettoyage s'exécute au moins une fois. Consultez journalctl -u docker-prune.service pour confirmer qu'il a fonctionné.
Copyright 2026 Virtua.Cloud. Tous droits réservés. Ce contenu est une création originale de l'équipe Virtua.Cloud. Toute reproduction, republication ou redistribution sans autorisation écrite est interdite.