Simuler la catastrophe pour dormir tranquille
Et si le VPS brûlait ce soir ? 10 scénarios de disaster recovery, une VM QEMU jetable, 407 lignes de Bash. RTO mesuré : 3 minutes 30.
La question qui empêche de dormir
Mon infra cloud tourne. 21 rôles Ansible, 15 services, monitoring, backups. Tout est automatisé. Mais une question me rongeait : si le VPS disparaissait ce soir - crash disque, erreur OVH, apocalypse - combien de temps pour tout reconstruire ?
“Normalement ça marche” n’est pas une réponse acceptable. La seule façon de savoir, c’est de simuler.
QEMU comme terrain de jeu
L’idée : une VM locale qui simule un VPS Ubuntu vierge. On joue les playbooks Ansible de production contre cette VM. On mesure le temps. On casse des trucs. On recommence.
# Créer un disque overlay de 20G
qemu-img create -f qcow2 -b base-ubuntu-24.04.qcow2 -F qcow2 dr-test.qcow2 20G
# Lancer la VM (4G RAM, 2 CPU, port SSH forwarded)
qemu-system-x86_64 \
-m 4096 -smp 2 -nographic \
-drive file=dr-test.qcow2,format=qcow2 \
-net nic -net user,hostfwd=tcp::2222-:22
Le disque overlay est la clé. vm.sh reset détruit l’overlay et en recrée un depuis l’image de base. Machine vierge en deux secondes. Pas de snapshot à gérer, pas de rollback compliqué - on efface et on recommence.
10 scénarios, 3 axes
J’ai structuré les tests en trois catégories :
Deploy from scratch (S1-S4). On part d’une machine nue. S1 installe Docker et le socle. S2 ajoute Traefik et le reverse proxy. S3 monte la stack monitoring complète. S4 déploie Ntfy et l’alerting. À chaque étape, on mesure le temps et on vérifie que les services répondent.
Résilience (S5-S7). C’est là que ça devient intéressant. S5 tue tous les conteneurs et vérifie l’auto-recovery via les restart policies. S6 fait un nuke total - docker system prune -af, suppression des volumes - puis rejoue tout le déploiement. S7 injecte volontairement un drift de configuration et vérifie qu’Ansible le détecte (--check --diff) et le corrige.
Non-régression (S8-S10). S8 vérifie l’idempotence : relancer le déploiement ne doit rien changer (changed=0). S9 audite la sécurité : no-new-privileges sur chaque conteneur, socket-proxy en lecture seule, pas de docker.sock monté sur Traefik. S10 vérifie les limites de ressources CPU/mémoire.
Le runner en 407 lignes
Pas de framework de test. Du Bash pur, idiomatique, avec des helpers colorés :
pass() { echo -e " ${GREEN}PASS${NC} $1"; ((PASS_COUNT++)); }
fail() { echo -e " ${RED}FAIL${NC} $1"; ((FAIL_COUNT++)); }
skip() { echo -e " ${YELLOW}SKIP${NC} $1"; ((SKIP_COUNT++)); }
Un timer_start/timer_stop pour mesurer chaque scénario. Un résumé final avec le score et le temps total. C’est simple, c’est lisible, et ça fait exactement ce qu’il faut.
Le choix de ne pas utiliser un framework comme BATS ou ShellSpec est délibéré. Pour 10 scénarios qui s’exécutent une fois de temps en temps, l’overhead d’un framework n’apporte rien. Le Bash brut est plus facile à lire pour quelqu’un qui découvre le projet.
Les résultats
9 runs en 35 minutes de test. Score final : 52 PASS / 1 FAIL.
| Mesure | Temps |
|---|---|
| Deploy socle complet | ~3m30s |
| Nuke total + redeploy | ~1m08s |
| Détection de drift | ~15s |
| Correction automatique | ~45s |
Le seul échec : les datasources Grafana à 0 via l’API. Un faux négatif - en production, les datasources sont provisionnées par fichier, pas par l’API. En contexte local QEMU, l’API retourne zéro alors que les datasources existent bien. Un cas limite que je pourrais corriger, mais qui ne reflète pas un vrai problème.
L’idempotence, le vrai test
Le scénario S8 est celui qui m’a le plus rassuré. Rejouer make deploy sur une infra déjà déployée ne doit rien modifier. Zéro changed. Si Ansible touche à quelque chose, c’est qu’un rôle n’est pas idempotent - et c’est un bug à corriger avant qu’il ne cause un incident en production.
C’est le genre de test qu’on ne fait jamais quand on configure à la main. On lance le playbook, ça marche, on passe à autre chose. Mais l’idempotence, c’est ce qui garantit qu’un déploiement automatique à 3h du matin ne cassera pas ce qui tournait à 2h59.
Ce que ça change
Avant DR Test, mon infra était “probablement” reconstructible. Maintenant, j’ai un chiffre : 3 minutes 30. Je sais que mes backups fonctionnent parce que je les ai testés. Je sais que la détection de drift fonctionne parce que j’ai injecté un drift et qu’Ansible l’a corrigé.
Le projet a pris une journée. Une seule. 407 lignes de Bash, une VM QEMU, et la tranquillité d’esprit. C’est le meilleur ratio effort/valeur de tous mes projets.