Paillasse/docs/postmortems/2026-10-12-vm-figee-self-healing.md
2026-10-12 21:12:43 +02:00

79 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.