Introduction
Les sauvegardes ne servent à rien tant que vous ne pouvez pas les restaurer. Ce guide explique comment réaliser un Docker Compose backup et une Docker Compose restore fiables et répétables. Vous apprendrez quoi sauvegarder, comment capturer les données de services courants (PostgreSQL, Redis, Nginx), comment valider une restauration et comment planifier un Docker Compose disaster recovery et un Docker Compose rollback sans stress. Les commandes proposées sont sûres à exécuter sur un laptop développeur ou un petit hôte de production.
Vue d'ensemble du workflow
Un workflow simple et répétable réduit les erreurs :
- Inventorier: lister tout ce qui contient de l'état (volumes, bind mounts, bases, configs d'app, secrets).
- Quiescer si nécessaire: suspendre les écritures ou utiliser les outils natifs de dump.
- Sauvegarder: capturer données et configs dans une archive horodatée.
- Stocker: sauvegarder sur un stockage durable et hors hôte.
- Vérifier: calculer un checksum et faire un test-restore dans un environnement jetable.
- Documenter: noter commandes exactes, versions et emplacements.
- Automatiser: scripter les étapes et les planifier.
- Réviser: s'entraîner à une restauration complète régulièrement.
Que sauvegarder
Dans Docker Compose, sauvegardez :
- Fichiers Compose: docker-compose.yml, compose.override.yml et .env.
- Configs de service: conf Nginx, fichiers de configuration app, certificats TLS.
- Volumes nommés: bases de données et état persistant (ex: pgdata, redisdata).
- Répertoires bind-mount: contenus servis par Nginx ou uploads d'app.
- Secrets et identifiants: stockés de manière sécurisée, pas dans les images.
- Infos de version: tags d'images et versions de plugins.
Astuce: exécutez docker compose config pour développer et inspecter la configuration effective.
Stratégies de sauvegarde
Ci-dessous, une stack minimale et des commandes pratiques. Adaptez les noms à votre projet.
Exemple de docker-compose.yml :
version: "3.9"
services:
db:
image: postgres:16
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redisdata:/data
nginx:
image: nginx: alpine
ports:
- "8080:80"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d: ro
- ./site:/usr/share/nginx/html: ro
volumes:
pgdata:
redisdata:
Préparation générale :
mkdir -p backups
TS=$(date -u +%Y%m%d_%H%M%S)
- Sauvegarder les fichiers Compose et les contenus bind-mount :
# Fichiers Compose et .env
tar czf backups/compose_${TS}.tgz docker-compose.yml .env || exit 1
# Config Nginx et contenu du site (bind mounts)
tar czf backups/nginx_${TS}.tgz nginx/conf.d site || exit 1
- PostgreSQL : privilégier un dump logique pour une cohérence à chaud.
# Dump logique (recommandé)
PGPASSWORD=secret docker compose exec -T db pg_dump -U app -d app | gzip > backups/pg_app_${TS}.sql.gz
Si vous devez snapshotter le répertoire de données (assurez-vous qu'il n'y a pas d'écritures, ou arrêtez la base) :
# Plus risqué : snapshot filesystem. Quiescez ou arrêtez d'abord.
# docker compose stop app-writers ...
docker compose exec -T db sh -c 'tar czf - /var/lib/postgresql/data' > backups/pgdata_${TS}.tgz
- Redis : déclencher une sauvegarde en arrière-plan, puis archiver les données.
# S'assurer d'un dump à jour (AOF ou RDB présent)
docker compose exec redis redis-cli SAVE
# Archiver le répertoire de données
docker compose exec -T redis sh -c 'tar czf - /data' > backups/redis_${TS}.tgz
- Optionnel : checksums d'intégrité.
(cd backups && sha256sum *.tgz *.gz > SHA256SUMS_${TS}.txt)
- Copie hors hôte : utilisez un stockage sûr et chiffré. Conservez plusieurs générations avec une politique de rétention.
Stratégies de restauration
Restaurez toujours d'abord dans un environnement jetable.
- Restaurer les fichiers Compose et les bind mounts :
# Remplacez ou mettez en scène dans un répertoire vierge, puis :
tar xzf backups/compose_${TS}.tgz
mkdir -p nginx/conf.d site
tar xzf backups/nginx_${TS}.tgz -C .
- Démarrer les services principaux :
docker compose up -d db redis nginx
- Restaurer PostgreSQL depuis un dump logique :
gunzip -c backups/pg_app_${TS}.sql.gz | docker compose exec -T db psql -U app -d app
Si vous avez sauvegardé le répertoire de données brut (assurez-vous d'utiliser la même version majeure de Postgres) :
docker compose stop db
# Nettoyer le répertoire de données dans le conteneur
docker compose run --rm db sh -c 'rm -rf /var/lib/postgresql/data/*'
# Extraire l'archive vers le chemin absolu inclus dans le tar
cat backups/pgdata_${TS}.tgz | docker compose run --rm -T db sh -c 'tar xzf - -C /'
# Redémarrer la base
docker compose up -d db
- Restaurer Redis :
docker compose stop redis
# Nettoyer et restaurer
docker compose run --rm -T redis sh -c 'rm -rf /data/* && tar xzf - -C /' < backups/redis_${TS}.tgz
docker compose up -d redis
- Recharger Nginx si les configs ont changé :
docker compose exec nginx nginx -t && docker compose exec nginx nginx -s reload
Note : les noms de volumes peuvent être préfixés par le projet. Utiliser exec/run dans le service évite d'avoir à deviner le nom exact du volume.
Contrôles de validation
Avant de servir du trafic, vérifiez la cohérence (Docker Compose validation) :
- Conteneurs en bonne santé :
docker compose ps
docker compose logs --since=2m db redis nginx
- Sanity PostgreSQL :
docker compose exec -T db psql -U app -d app -c "select count(*) as tables from information_schema.tables where table_schema='public';"
- Sanity Redis :
docker compose exec -T redis redis-cli ping
docker compose exec -T redis redis-cli dbsize
- Nginx répond :
curl -I http://localhost:8080/
- Contrôles ciblés des données : lignes connues, fichiers et comptes utilisateurs présents.
- Checksums : si vous avez stocké des SHA256SUMS, validez-les :
(cd backups && sha256sum -c SHA256SUMS_*.txt)
- Accès et permissions : l'app peut lire/écrire où nécessaire.
Disaster recovery et rollback
Préparez le pire pour une reprise sereine et rapide :
- RPO (Recovery Point Objective) : tolérance à la perte de données. Ajustez la fréquence de sauvegarde en conséquence.
- RTO (Recovery Time Objective) : délai de remise en ligne. Prépositionnez images et scripts.
- Stockage : conservez des copies chiffrées hors hôte et, si critique, hors région.
- Gel des versions : alignez les versions majeures d'images pour éviter les incompatibilités de fichiers de données.
- Plan de rollback : gardez au moins un snapshot précédent prêt. En cas d'échec, restaurez la dernière sauvegarde connue bonne et redémarrez les services.
- Restauration en parallèle : faites monter une stack de test avec un nom de projet différent :
# Utiliser un projet différent pour ne pas écraser les volumes de prod
export COMPOSE_PROJECT_NAME=stack_restore_test
docker compose up -d
- Runbook : documentez les commandes exactes, emplacements des fichiers et critères de succès. Entraînez-vous selon un calendrier.
Plan pilote local
Démarrez petit pour mesurer vite :
Périmètre :
- Services : PostgreSQL et Redis uniquement.
- Données : un fichier SQL seed qui crée quelques tables et lignes ; quelques clés Redis.
Étapes :
- Démarrer la stack, charger les données seed.
- Exécuter les commandes de sauvegarde pour produire des archives horodatées.
- Démonter la stack et supprimer les volumes.
- Restaurer dans une stack neuve en utilisant les archives.
- Valider avec des requêtes SQL et Redis dbsize ; vérifier les logs.
Critères de succès (mesurables) :
- Sauvegarde en moins de 2 minutes pour les données seed.
- Restauration sans erreurs dans les logs.
- Comptes de tables et lignes exacts ; nombre de clés Redis identique.
- Commandes scriptées dans un backup.sh et un restore.sh qui retournent 0 en cas de succès.
Ce pilote étroit et mesurable permet d'inspecter les résultats localement et de gagner en confiance avant d'élargir le périmètre.
Erreurs courantes
Évitez ces pièges :
- Sauvegarder les conteneurs au lieu des données : les conteneurs sont éphémères ; sauvegardez volumes, bind mounts et dumps.
- Sauter les dumps logiques pour les bases : les tars de bases en cours d'écriture peuvent être incohérents.
- Oublier .env et les fichiers de config : la restauration échoue ou diverge.
- Ne pas tester les restaurations : les sauvegardes non testées échouent souvent le jour J.
- Dérive de version : restaurer un data dir Postgres 16 dans Postgres 15 (ou l'inverse) échouera.
- Restaurer dans le mauvais projet : crée des volumes inattendus ; validez COMPOSE_PROJECT_NAME.
- Permissions et ownership manquants : assurez-vous que tar préserve modes et propriétaires si pertinent.
- Pas de politique de rétention : les anciennes sauvegardes écrasent les nouvelles, ou le stockage se remplit.
- Ignorer les codes de sortie : échecs de pipe ou archives partielles non détectés.
- Laisser des services écrire pendant la sauvegarde : quiescez ou utilisez les outils natifs.
Conclusion
La valeur d'un Docker Compose backup se mesure à votre capacité à exécuter une Docker Compose restore rapidement et avec confiance. Définissez ce qu'il faut protéger, utilisez les outils natifs des services pour une donnée cohérente, archivez configs et volumes, et validez avec des contrôles concrets (Docker Compose validation). Démarrez par un pilote local, mesurez, puis automatisez. Figez les versions, externalisez les sauvegardes et répétez une restauration complète pour être prêt lorsque cela comptera vraiment.