21 - Sauvegardes et restauration
Ce que tu vas apprendre
- Faire un pg_dump depuis un conteneur Docker
- Automatiser les sauvegardes avec cron
- Sauvegarder des volumes Docker
- La différence entre export/import et save/load
- Restaurer une base de donnees proprement
- Tester ses backups (parce qu'un backup non teste n'existe pas)
Prerequisites
Avoir suivi l'article sur les bases de donnees dans Docker. Avoir PostgreSQL qui tourne dans un conteneur avec un named volume.
J'ai perdu des donnees une seule fois. C'etait un docker compose down -v un vendredi soir. Le -v supprime les volumes. J'avais tape trop vite, et la base de dev avec deux semaines de donnees de test a disparu. Depuis, je fais des backups, meme en dev.
pg_dump depuis un conteneur
La méthode la plus simple pour sauvegarder PostgreSQL :
bash# Dump SQL complet
docker exec db pg_dump -U myapp myapp_dev > backup.sql
# Dump au format custom (compresse, plus flexible pour la restauration)
docker exec db pg_dump -U myapp -Fc myapp_dev > backup.dump
# Dump avec timestamp dans le nom
docker exec db pg_dump -U myapp -Fc myapp_dev > "backup_$(date +%Y%m%d_%H%M%S).dump"
# Dump d'une seule table
docker exec db pg_dump -U myapp -t users myapp_dev > users.sql
Le format custom (-Fc) est celui que je recommande. Il est compresse, et tu peux restaurer des tables individuelles. Le format SQL brut est lisible par un humain, mais moins flexible.
Si tu veux un dump complet avec les rôles et les tablespaces :
bashdocker exec db pg_dumpall -U myapp > full_backup.sql
Automatiser avec cron
Un script de backup que j'utilise sur mes projets :
bash#!/bin/bash
set -e
BACKUP_DIR="/backups/postgres"
CONTAINER="db"
DB_USER="myapp"
DB_NAME="myapp_dev"
KEEP_DAYS=7
mkdir -p "$BACKUP_DIR"
FILENAME="$BACKUP_DIR/${DB_NAME}_$(date +%Y%m%d_%H%M%S).dump"
echo "Backup de $DB_NAME..."
docker exec "$CONTAINER" pg_dump -U "$DB_USER" -Fc "$DB_NAME" > "$FILENAME"
SIZE=$(du -h "$FILENAME" | cut -f1)
echo "Backup termine: $FILENAME ($SIZE)"
# Supprimer les backups de plus de 7 jours
find "$BACKUP_DIR" -name "*.dump" -mtime +$KEEP_DAYS -delete
echo "Anciens backups nettoyes (plus de $KEEP_DAYS jours)"
Et la crontab :
bash# Backup tous les jours a 3h du matin
0 3 * * * /home/deploy/scripts/backup-db.sh >> /var/log/backup.log 2>&1
Sur paltemps.fr, le script tourne une fois par jour et garde les 7 derniers jours. Pour un side project c'est largement suffisant. Pour de la prod serieuse, tu veux aussi envoyer les backups sur un stockage distant (S3, GCS).
Sauvegarder des volumes Docker
Parfois tu veux sauvegarder le volume entier, pas juste la base. La technique classique :
bash# Sauvegarder un volume dans une archive tar
docker run --rm \
-v pgdata:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/pgdata_backup.tar.gz -C /source .
# Restaurer depuis l'archive
docker run --rm \
-v pgdata:/target \
-v $(pwd):/backup \
alpine sh -c "cd /target && tar xzf /backup/pgdata_backup.tar.gz"
Le principe : on lance un conteneur Alpine temporaire qui a acces au volume (/source) et au dossier local (/backup), et on fait un tar. C'est générique, ca marche pour n'importe quel volume.
docker cp : copier des fichiers
Pour des fichiers individuels :
bash# Copier depuis le conteneur vers l'hote
docker cp db:/var/lib/postgresql/data/pg_hba.conf ./pg_hba.conf
# Copier depuis l'hote vers le conteneur
docker cp ./mon-script.sql db:/tmp/mon-script.sql
docker cp marche meme sur des conteneurs arretes. Pratique pour récupérer des logs ou des fichiers de config apres un crash, comme on l'a vu dans l'article sur le debug.
export/import vs save/load
Deux paires de commandes qui font des choses différentes :
bash# export/import : filesystem d'un CONTENEUR (pas les metadonnees)
docker export mon-conteneur > conteneur.tar
docker import conteneur.tar nouvelle-image:v1
# save/load : IMAGE complete (layers, metadonnees, tags)
docker save mon-image:v1 > image.tar
docker load < image.tar
export/import aplatit toutes les couches en une seule. Tu perds l'historique des layers, les variables d'environnement, le CMD. C'est utile pour transférer un filesystem, pas pour sauvegarder une image.
save/load garde tout intact. C'est ce que tu utilises pour deplacer une image entre machines sans passer par un registry. Par exemple, envoyer une image sur un serveur sans Docker Hub :
bashdocker save mon-app:v2 | gzip > mon-app-v2.tar.gz
scp mon-app-v2.tar.gz deploy@server:/tmp/
ssh deploy@server "docker load < /tmp/mon-app-v2.tar.gz"
Procedure de restauration
Le backup ne vaut rien si tu ne testes pas la restauration. Voici comment restaurer :
bash# Restauration depuis un dump SQL
docker exec -i db psql -U myapp myapp_dev < backup.sql
# Restauration depuis un dump custom
docker exec -i db pg_restore -U myapp -d myapp_dev --clean --if-exists < backup.dump
# Restauration dans une base neuve
docker exec db createdb -U myapp myapp_restored
docker exec -i db pg_restore -U myapp -d myapp_restored < backup.dump
Le --clean --if-exists supprime les objets existants avant de les recreer. Sans ca, tu auras des erreurs "already exists" partout.
Pour Redis, c'est plus simple. Si tu as active la persistance AOF ou RDB :
bash# Le fichier est dans le volume
docker cp redis:/data/dump.rdb ./redis-backup.rdb
# Pour restaurer, copie le fichier et redemarre
docker cp ./redis-backup.rdb redis:/data/dump.rdb
docker restart redis
Tester ses backups
J'ai un script qui teste la restauration automatiquement :
bash#!/bin/bash
set -e
BACKUP_FILE=$1
echo "Test de restauration de $BACKUP_FILE..."
# Lancer un PostgreSQL temporaire
docker run -d --name test-restore \
-e POSTGRES_USER=myapp \
-e POSTGRES_PASSWORD=test \
-e POSTGRES_DB=test_restore \
postgres:16-alpine
# Attendre que PostgreSQL soit pret
sleep 5
# Restaurer le backup
docker exec -i test-restore pg_restore \
-U myapp -d test_restore --clean --if-exists < "$BACKUP_FILE"
# Verifier qu'il y a des donnees
COUNT=$(docker exec test-restore psql -U myapp -d test_restore -t -c "SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public'")
echo "Tables trouvees: $COUNT"
# Nettoyer
docker rm -f test-restore
echo "Test de restauration reussi."
Fais tourner ce script apres chaque backup automatique. Un backup que tu n'as jamais teste, c'est un fichier qui prend de la place pour rien.
Résumé
pg_dump -Fcdonne un backup compresse et flexible a restaurer.- Un script cron avec rotation des fichiers gere les backups quotidiens.
- Les volumes se sauvegardent avec un conteneur Alpine temporaire et tar.
save/loadpour les images,export/importpour les filesystems de conteneurs.pg_restore --clean --if-existsrestaure proprement sur une base existante.- Teste tes backups. Toujours.
Article précédent : Docker 20 - Bases de donnees Article suivant : Docker 22 - Frontend