Paillasse/docs/postmortems/2026-10-12-vm-figee-self-healing.md

80 lines
4.1 KiB
Markdown
Raw Normal View History

# Post-mortem — Panne provoquée : VM figée, réparation automatique
**Date** : 2026-10-12. **Gravité** : aucune (panne provoquée volontairement,
sur le serveur réel, pour valider le self-healing du bloc A, semaine 6).
**Impact réel** : nul — une seule VM de test, aucun élève.
## Scénario
Une VM d'élève (3 machines du lab 08, prises du stock chaud et attribuées à
une session de test) est gelée avec `virsh suspend`, qui simule un noyau
planté ou un blocage matériel : le processeur virtuel s'arrête, l'agent
invité ne répond plus, mais la VM reste en mémoire (état libvirt `paused`).
## Déroulé observé
| Heure (locale) | Événement |
|---|---|
| 21:08:00 | VM `pc-a` mise en pause (`virsh suspend`) ; `routeur` et `pc-b` intactes |
| 21:08–21:10 | Sondes automatiques (`labs:surveiller-vm`, chaque minute) : `pc-a` muette, `routeur`/`pc-b` répondent |
| ≈ 21:10 | 3 sondes ratées de suite atteintes : Nova reçoit l'ordre de redémarrage forcé (`reboot --hard`) sur `pc-a` ; `routeur` et `pc-b` jamais touchées |
| + quelques secondes | `pc-a` repasse de `paused` à `running` ; la sonde suivante la trouve de nouveau vivante |
| — | `lab_session_machines.sante` = `relancee`, horodatée ; les deux autres machines restent `null` |
**Aucune intervention humaine entre la mise en pause et la réparation.**
## Preuve
```
# Avant : pc-a « running »
# Panne : virsh suspend → domstate « paused »
3 VM sondées, 1 muettes ; élèves : 1 VM relancée(s), 0 irréparable(s)
# Après : domstate « running »
3 VM sondées, 0 muettes ; élèves : 0 VM relancée(s), 0 irréparable(s)
sante = "relancee", sante_a = 2026-10-12 19:08:11
```
## Ce qui a bien fonctionné
- La sonde (correcteur) distingue bien une VM gelée (`paused`) d'une VM
éteinte (`shut off`) et d'une VM saine : seule `pc-a` a été touchée, les
deux autres machines de la même session n'ont jamais reçu d'action.
- Le redémarrage forcé a suffi : pas besoin de reconstruire la stack Heat ni
de perdre le travail de l'élève sur les deux autres machines.
- Le compteur de relances par heure a empêché une boucle : si la VM était
restée muette, elle serait passée « irréparable » après 2 tentatives, pas
redémarrée indéfiniment.
## Ce qui a été découvert pendant le test (pas un défaut, une leçon)
Le scheduler Laravel tourne **chaque minute en continu**, y compris pendant
qu'on teste à la main : les appels manuels de `labs:surveiller-vm` se sont
mélangés avec les passages automatiques du cron. Le seuil de 3 sondes
ratées a donc été atteint plus vite qu'en comptant seulement les commandes
tapées à la main. **À refaire** : pour un test reproductible au chronomètre,
désactiver temporairement le cron du scheduler (ou observer uniquement les
métriques, sans lancer la commande soi-même) — noté pour le prochain test
(montée en charge, panne générale).
Un piège trouvé **avant** ce test, pendant le déploiement : le correcteur
n'avait pas encore été recompilé avec la sonde quand le nouveau code
Laravel a commencé à l'appeler (cron déjà actif après `ansible-playbook
portail.yml`, avant `ansible-playbook correcteur.yml`). Les VM sont
apparues « muettes » quelques minutes à tort (erreur `requete_invalide` de
l'ancien binaire, pas une vraie panne). **Correction pour la suite** :
toujours déployer `correcteur.yml` avant `portail.yml` quand les deux
changent ensemble (le contraire de l'ordre suivi cette fois).
## Comprendre
Un self-healing qui ne distingue pas « cette VM précise est malade » de
« tout l'hôte est en panne » ferait plus de mal que de bien : redémarrer en
boucle 20 VM parce que l'hyperviseur lui-même est surchargé n'aiderait en
rien, et ajouterait de la charge au pire moment. La règle « toutes muettes à
la fois → aucune action » (vérifiée mais non provoquée pendant ce test,
seulement en test Pest) existe pour cette raison. L'autre leçon, plus
générale, rejoint celle de l'étape 7 : un service qui tourne en tâche de
fond (ici le scheduler, chaque minute) continue de tourner pendant qu'on
observe à la main — il faut en tenir compte en testant, pas le découvrir
après coup.