Tous les articles [ Ingénierie ] N° 05 / 16 S3 7 min de lecture // Read in English
Mille crashs par nuit : l'anti-cascade comme exigence testée
La supervision d'OC2-Edge est une machine à états pure au temps injecté. Les tests chaos exécutent 1 000 cycles de crash par nuit, avec contrôle négatif, pour prouver que l'isolation en oignon confine chaque défaillance.
Sur un nœud de commandement, la défaillance d’un module ne doit pas devenir la défaillance du nœud. OC2-Edge formule cette propriété comme une exigence : un crash reste confiné au périmètre du module qui le subit, la supervision le détecte, nettoie ses ressources et le redémarre selon sa politique, sans effet sur les autres modules ni sur la COP (Common Operational Picture, image tactique partagée). Une exigence non testée est une opinion. Celle-ci est testée chaque nuit, par injection de fautes, dans le dépôt public.
Une supervision déterministe : machine à états pure, temps injecté
La supervision d’OC2-Edge est le composant qui décide du sort de chaque module : démarrage, surveillance, confinement, redémarrage, révocation. Son cœur est une machine à états pure : une fonction qui reçoit un état et un événement, et qui retourne un nouvel état et une liste d’actions. Elle ne lit pas l’horloge, ne touche pas au système de fichiers, n’ouvre pas de socket. Le temps lui est injecté comme un événement parmi d’autres.
Cette contrainte d’architecture a deux conséquences directes.
Premièrement, le déterminisme : à séquence d’événements identique, la supervision produit une séquence de décisions identique. Les stratégies de redémarrage, les délais d’escalade et les seuils de révocation se testent sans démarrer un seul processus réel, en déroulant des séquences d’événements en mémoire. Un scénario de panne complexe (crashs en rafale, expirations croisées, révocation pendant un redémarrage) tient dans un test unitaire qui s’exécute en millisecondes.
Deuxièmement, la rejouabilité : toute anomalie observée en production ou en campagne de test se réduit à une séquence d’événements. Cette séquence se rejoue telle quelle contre la machine à états, dans le dépôt, comme test de non-régression. Le bug d’hier devient le test de demain, à l’identique, sans dépendre d’une plateforme ni d’une course de threads. Cette approche relève du test par injection de fautes : provoquer des défaillances contrôlées pour vérifier que le système y répond comme spécifié [7].
La machine à états pure teste la logique de décision. Elle ne teste pas le monde réel : les processus qui meurent vraiment, les descripteurs de fichiers qui fuient, les cgroups qui restent orphelins. C’est le rôle des campagnes chaos.
Chaos v0 : mille cycles, zéro ressource orpheline
La première campagne, chaos v0, vise l’endurance du cycle de vie élémentaire. Chaque nuit, la CI exécute 1 000 cycles de crash et de redémarrage d’un module réel sur un nœud réel (émulé x86-64 et ARM64). Le principe rejoint celui du chaos engineering : formuler une hypothèse d’état stable, injecter des défaillances réelles, vérifier que l’hypothèse tient [1].
Chaque cycle applique la même séquence : le module démarre, le harnais le tue (terminaison brutale, sans préavis ni nettoyage), la supervision détecte la mort, nettoie, redémarre, et le harnais vérifie le retour à l’état stable. Le critère de succès porte sur deux invariants, vérifiés après chaque cycle et en fin de campagne :
- disponibilité : les autres services du nœud répondent pendant toute la campagne ; aucun crash ne se propage hors du périmètre du module ;
- zéro ressource orpheline : après le dernier cycle, l’inventaire des processus, des points de montage, des interfaces réseau virtuelles et des cgroups du nœud est identique à l’inventaire initial. Une fuite d’une ressource par cycle serait invisible sur un test unitaire ; sur 1 000 cycles, elle devient un écart d’inventaire flagrant. C’est la raison du volume : le nombre ne cherche pas l’impressionnant, il cherche l’accumulation.
Chaos v1 : seize modules, tempête de crashs, convergence
La campagne chaos v1 étend le modèle à la concurrence. Le nœud héberge 16 modules ; le harnais déclenche une tempête de crashs : terminaisons simultanées, en rafales, sur des sous-ensembles aléatoires de modules, y compris pendant les redémarrages provoqués par les crashs précédents. C’est le régime où les superviseurs naïfs se dégradent : verrous croisés, files d’événements en retard, redémarrages en boucle qui saturent le nœud.
Le critère de succès est la convergence : après la fin des injections, le nœud retrouve en temps borné un état où chaque module est soit actif, soit arrêté conformément à sa politique, et où l’invariant zéro ressource orpheline tient. La graine aléatoire de chaque campagne est journalisée : une tempête qui révèle un défaut se rejoue à l’identique, ce qui ramène le débogage de la concurrence dans le champ du reproductible.
Le contrôle négatif : prouver que le test mord
Un test qui ne peut pas échouer ne prouve rien. Un harnais chaos peut passer au vert pour de mauvaises raisons : injection qui ne tue pas vraiment le processus, vérification qui interroge le mauvais nœud, invariant qui compare deux inventaires vides. Ce risque a un remède classique en méthode expérimentale : le contrôle négatif.
Chaque campagne chaos inclut donc une exécution où l’isolation est volontairement cassée. Le harnais démarre un module dans une configuration privée d’une couche d’isolation, telle qu’un crash y a des effets observables hors de son périmètre. Le résultat attendu de cette exécution est l’échec du test. Si le harnais déclare cette exécution réussie, c’est le harnais qui est défaillant, et la campagne entière est invalidée. Le contrôle négatif vérifie que le test mord : qu’il détecte réellement la classe de défaut qu’il prétend détecter, et que le vert des autres exécutions a une valeur de preuve.
L’isolation en oignon
Le confinement vérifié par ces campagnes repose sur des couches successives, chacune avec un rôle propre. Aucune couche ne suffit seule ; leur composition fait la profondeur de défense.
- Namespaces : le noyau Linux donne au module une vue privée du système (processus, points de montage, réseau, identifiants) [2]. Le module ne voit pas les autres modules ; ce qu’il ne voit pas, il ne peut ni le lire ni le tuer.
- Cgroups : le noyau borne les ressources du module (CPU, mémoire, nombre de processus, entrées-sorties) [3]. Un module qui fuit ou qui boucle épuise son budget, pas celui du nœud. C’est la couche qui transforme une défaillance de ressources en événement local.
- Seccomp : un filtre limite les appels système que le module peut invoquer, avec la liste réduite dont il a besoin [4]. La surface d’attaque du noyau exposée au module diminue d’autant ; un module compromis dispose de moins de leviers.
- MicroVM : pour les modules au risque le plus élevé, l’exécution passe dans une machine virtuelle légère, sur le modèle de Firecracker [5]. La frontière n’est plus une structure du noyau partagé mais une interface de virtualisation matérielle : une évasion exige de traverser l’hyperviseur.
- WASI : les modules compilés en WebAssembly s’exécutent sous WASI (WebAssembly System Interface), un modèle où toute capacité (fichier, réseau, horloge) doit être accordée explicitement [6]. Par défaut, le module ne peut rien ; le déni est l’état initial et l’autorisation, l’exception.
Le harnais chaos exerce ces couches avec les modules réels du nœud. Le contrôle négatif décrit plus haut consiste précisément à retirer une de ces couches et à vérifier que le harnais s’en aperçoit.
Ce que cela engage
Les campagnes chaos v0 et v1 font partie des chaînes CI du dépôt public, aux côtés des autres suites (~930 tests automatisés au vert, 9 chaînes CI). Leurs harnais, leurs invariants et leurs journaux d’exécution sont dans le dépôt : une instance de la BITD (base industrielle et technologique de défense) peut les rejouer sur sa propre configuration, avec ses propres modules, et publier ses propres résultats. L’article n° 2 décrit comment reproduire le scénario de faute unitaire sur émulateur [voir /blog/rejouer-la-demo-emulateur/] ; les campagnes complètes s’exécutent avec les mêmes outils. La propriété d’anti-cascade n’est pas un argument commercial : c’est une exigence, un harnais qui la vérifie, et un contrôle négatif qui vérifie le harnais.
Sources
- Principles of Chaos Engineering, « Principles of Chaos Engineering », 2019, https://principlesofchaos.org/
- man7.org, « namespaces(7), Linux manual page », https://man7.org/linux/man-pages/man7/namespaces.7.html
- man7.org, « cgroups(7), Linux manual page », https://man7.org/linux/man-pages/man7/cgroups.7.html
- The Linux Kernel documentation, « Seccomp BPF (SECure COMPuting with filters) », https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html
- Firecracker, « Firecracker : Secure and fast microVMs for serverless computing », https://firecracker-microvm.github.io/
- WASI, « WebAssembly System Interface », https://wasi.dev/
- A. Basiri et al., « Chaos Engineering », IEEE Software, vol. 33, n° 3, 2016, https://arxiv.org/abs/1702.05843