Sauvegarde et restauration¶
Ce qu'il faut sauvegarder¶
| Élément | Emplacement | Criticité | Reconstructible ? |
|---|---|---|---|
| Secrets | .env |
critique | non — perte définitive |
| Métadonnées Metabase | base metabase |
haute | par script, sans les personnalisations manuelles |
| Métadonnées Airflow | base airflow |
moyenne | oui, l'historique est perdu |
| Entrepôt | base warehouse |
faible | oui, entièrement rejouable |
| Certificats TLS | data/letsencrypt/ |
faible | oui, réémission automatique |
| Code | dépôt Git | — | déjà versionné |
L'entrepôt est le moins critique : le jeu synthétique est déterministe et
l'open data est réingérable. En revanche, .env est irremplaçable :
MB_ENCRYPTION_SECRET_KEY déchiffre les secrets stockés par Metabase,
AIRFLOW_FERNET_KEY ceux d'Airflow. Les perdre rend ces bases inutilisables.
Deux dispositifs complémentaires¶
| Instantané OVH | Vidage logique | |
|---|---|---|
| Couvre | VPS détruit, disque perdu | erreur humaine, corruption, régression |
| Granularité | le VPS entier | une base, voire une table |
| Rétention | ~7 jours | 90 jours |
| Cohérence | au crash — équivalent d'une coupure de courant | logique, garantie par la transaction |
| Restauration | réinstallation complète | quelques secondes |
Les deux ne se substituent pas. L'instantané OVH traite le sinistre ; le vidage logique traite le cas bien plus fréquent de l'erreur humaine — casser une configuration Metabase pendant une démonstration, par exemple. Avec l'instantané seul, il faudrait restaurer tout le VPS et perdre les ingestions du jour.
Vidage logique quotidien¶
scripts/sauvegarde.sh, déclenché par un timer systemd à 3h.
sudo systemctl status metrika-sauvegarde.timer # état
systemctl list-timers metrika-sauvegarde.timer # prochaine exécution
sudo journalctl -u metrika-sauvegarde -n 20 # journal
sudo systemctl start metrika-sauvegarde.service # exécution immédiate
Les unités sont versionnées dans infra/systemd/. Installation :
sudo cp infra/systemd/metrika-sauvegarde.* /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now metrika-sauvegarde.timer
Un timer systemd plutôt que cron : Persistent=true rattrape l'exécution si
la machine était éteinte à l'heure prévue, la journalisation passe par
journalctl sans configuration, et aucun paquet supplémentaire n'est requis.
Ce qui est sauvegardé¶
| Élément | Taille | Format |
|---|---|---|
warehouse |
~4,8 Mo | pg_dump -Fc |
metabase |
~1,0 Mo | pg_dump -Fc |
airflow |
~0,2 Mo | pg_dump -Fc |
.env |
2 Ko | copie, permissions 600 |
| Mémoire de l'assistant | ~5 Ko | archive de ~/.claude/…/memory/ |
6 Mo par jour, soit 530 Mo pour 90 jours de rétention. Le format -Fc est
compressé et permet à pg_restore d'extraire sélectivement une seule table.
Le script échoue explicitement si un fichier produit fait moins de 512 octets : une sauvegarde vide qui réussit en silence est pire que pas de sauvegarde du tout. Ce contrôle a immédiatement révélé un cas réel — voir ci-dessous.
Les certificats TLS ne sont pas sauvegardés
data/letsencrypt/acme.json appartient à root (créé par le conteneur
Traefik) et n'est pas lisible par l'utilisateur qui exécute la sauvegarde.
Une première version produisait donc une archive vide de 127 octets, sans
rien signaler. Plutôt que d'ajouter une règle sudo, les certificats sont
exclus : Traefik les réémet en quelques secondes.
Mémoire de l'assistant
Le contexte de collaboration accumulé au fil des sessions vit dans
~/.claude/projects/-home/memory/. Il n'est ni versionné ni
reconstructible, d'où sa présence ici. Seul ce dossier est archivé :
le reste de ~/.claude contient des jetons d'authentification.
.env est irremplaçable
MB_ENCRYPTION_SECRET_KEY déchiffre les secrets stockés par Metabase,
AIRFLOW_FERNET_KEY ceux d'Airflow. Sans ce fichier, des bases restaurées
sont inexploitables. C'est le seul élément qu'aucun script ne peut
reconstruire.
Tout reste sur le même disque
Les vidages vivent dans /home/debian/sauvegardes, sur le disque qu'ils
sauvegardent. C'est l'instantané OVH qui couvre la perte du disque — d'où
l'importance de vérifier que cette option est bien active sur le VPS
(espace client → VPS → onglet Sauvegardes). Pour une protection contre la
perte simultanée des deux, il faudrait une copie chiffrée vers un stockage
objet externe.
Restauration¶
Test de restauration¶
Une sauvegarde jamais restaurée n'est pas une sauvegarde. Vérification dans une base jetable, sans toucher à la production :
SAUV=$(ls -d /home/debian/sauvegardes/*/ | tail -1)
docker compose exec -T postgres psql -U metrika -d postgres \
-c "CREATE DATABASE test_restauration OWNER warehouse;"
docker compose exec -T postgres pg_restore -U metrika -d test_restauration \
--no-owner --role=warehouse < "$SAUV/warehouse.dump"
docker compose exec -T postgres psql -U metrika -d test_restauration -Atc \
"SELECT count(*) FROM gold.fct_orders;" # doit correspondre à la production
docker compose exec -T postgres psql -U metrika -d postgres \
-c "DROP DATABASE test_restauration;"
Restauration réelle¶
# 1. Arrêter les consommateurs
docker compose stop metabase airflow-apiserver airflow-scheduler \
airflow-dag-processor airflow-triggerer
# 2. Restaurer une base
docker compose exec -T postgres psql -U metrika -d postgres \
-c "DROP DATABASE metabase;" -c "CREATE DATABASE metabase OWNER metabase;"
docker compose exec -T postgres pg_restore -U metrika -d metabase \
--no-owner --role=metabase < sauvegardes/20260819-0300/metabase.dump
# 3. Restaurer les secrets — obligatoire pour Metabase et Airflow
cp sauvegardes/20260819-0300/env .env
# 4. Redémarrer
docker compose up -d
Reconstruction complète sans sauvegarde¶
Si seul le code subsiste, l'entrepôt se reconstruit intégralement :
docker compose up -d postgres
docker compose exec airflow-scheduler airflow dags test 10_seed_bronze_demo
docker compose exec airflow-scheduler airflow backfill create \
--dag-id 20_ingest_eco2mix --from-date <début> --to-date <fin> \
--reprocess-behavior completed
python3 scripts/metabase_provision.py
Seules les personnalisations manuelles de Metabase sont perdues — c'est précisément l'intérêt d'avoir un provisionnement scripté.
Limite de l'open data
ODRÉ ne conserve qu'une fenêtre glissante d'environ 50 jours sur le jeu temps réel. Un historique plus profond ne peut pas être reconstitué depuis cette source : il faut la sauvegarde, ou basculer sur les jeux consolidés annuels.