Chaos Engineering avec Chaos Mesh
Objectifs pédagogiques¶
- Expliquer la démarche du Chaos Engineering et ses principes fondateurs
- Formuler une hypothèse d'état stable mesurable à partir des SLO
- Borner une expérience : rayon d'impact, conditions d'arrêt, retour arrière
- Organiser un GameDay et analyser les points de défaillance uniques (SPOF)
- Installer et sécuriser Chaos Mesh sur un cluster k3s
- Écrire des expériences
PodChaos,NetworkChaos,StressChaos,HTTPChaoset les enchaîner dans unWorkflow
Chaos Engineering & Principes¶
Pourquoi casser volontairement ?¶
Les pannes arrivent de toute façon : la seule question est de savoir si on les découvre un mardi à 14h ou un samedi à 3h
- Un nœud disparaît, un disque se remplit, un lien réseau se dégrade
- Une dépendance répond lentement au lieu de répondre en erreur
- Un déploiement introduit une régression invisible en test
- Un composant « secondaire » (DNS, ingress) s'avère critique
Le Chaos Engineering remplace la confiance supposée par une confiance mesurée
Un peu d'histoire¶
- 2010 : Netflix migre vers AWS et crée Chaos Monkey, qui termine des instances de production au hasard, aux heures ouvrées
- 2011 : la Simian Army étend l'idée : Latency Monkey (latence), Chaos Gorilla (perte d'une zone entière)
- 2012 : Chaos Monkey devient open source
- Formalisation des principes sur principlesofchaos.org
- Aujourd'hui : outils natifs Kubernetes (Chaos Mesh, LitmusChaos), services managés des cloud providers
L'idée clé de Netflix : si une panne est inévitable, autant la provoquer quand tout le monde est là pour apprendre
Définition¶
Le Chaos Engineering est la discipline qui consiste à expérimenter sur un système afin de bâtir la confiance dans sa capacité à résister à des conditions turbulentes en production
- Ce n'est pas casser au hasard pour voir ce qui se passe
- C'est une démarche scientifique : hypothèse, expérience, mesure, conclusion
- Le résultat attendu est un apprentissage, pas une panne
- Une hypothèse invalidée est un succès de l'expérience : une faiblesse a été trouvée avant les clients
Les principes avancés¶
- Bâtir une hypothèse autour de l'état stable : mesurer une sortie du système, pas son fonctionnement interne
- Faire varier des événements du monde réel : pannes matérielles, latence, pics de trafic, dépendances défaillantes
- Expérimenter en production : seul l'environnement réel a le vrai trafic et la vraie configuration
- Automatiser les expériences pour les jouer en continu : la résilience régresse comme le reste
- Minimiser le rayon d'impact : commencer petit et élargir progressivement
En formation, la « production » est votre plateforme : l'exigence de rigueur reste la même
La boucle d'expérimentation¶
┌──────────────────────────────────────────────────────────┐
│ 1. Définir l'état stable → SLI mesurés avant l'injection │
│ 2. Formuler l'hypothèse → « le SLO tient malgré X » │
│ 3. Borner l'expérience → cible, durée, conditions │
│ d'arrêt, retour arrière │
│ 4. Injecter la panne → sous charge réaliste (k6) │
│ 5. Mesurer l'écart → SLI pendant et après │
│ 6. Conclure → validée ou invalidée │
│ 7. Corriger puis rejouer → la correction est prouvée │
└──────────────────────────────────────────────────────────┘
L'hypothèse d'état stable¶
L'état stable se décrit avec des indicateurs orientés utilisateur, mesurés avant l'injection
- Taux de succès des requêtes de paiement ≥ 99,5 %
- Latence p95 < 300 ms
- Débit k6 constant, sans erreur côté client
- Aucune alerte critique active
Mauvais indicateurs d'état stable : « le CPU est à 30 % », « tous les pods sont Running »
Formulation type : « Pendant la perte d'un pod de l'API, le taux de succès reste ≥ 99,5 % et la p95 < 300 ms »
Rayon d'impact & conditions d'arrêt¶
Rayon d'impact : ce que l'expérience peut toucher
- Un seul namespace, un sélecteur de labels précis
- Un pod avant tous les pods, une minute avant une heure
- Élargir uniquement quand l'itération précédente est comprise
Conditions d'arrêt : décidées avant l'injection
- Burn rate du SLO au-delà du seuil d'alerte rapide
- Alerte critique hors périmètre de l'expérience
- Échec d'un contrôle HTTP de santé sur plusieurs essais consécutifs
- Un bouton d'arrêt connu de tous :
kubectl deletede l'expérience
GameDay¶
Un exercice planifié où l'équipe joue des pannes ensemble
- Rôles : maître du jeu, opérateurs, observateurs, scribe
- Scénario : liste d'expériences, ordre, durée, conditions d'arrêt
- Annoncé ou non : commencer annoncé, puis tester aussi la détection
- Ce qu'on teste : la plateforme, mais aussi les alertes, les runbooks et la communication
- Débrief : chronologie, écarts à l'hypothèse, actions correctives avec responsables
Le GameDay produit des preuves datées et une liste d'améliorations, pas seulement des captures
Analyse des SPOF¶
Un SPOF (Single Point Of Failure) est un composant dont la perte rend le service indisponible
| Composant | Réplicas | Répartis sur plusieurs nœuds ? | Impact si perdu |
|---|---|---|---|
| API SecurePay | 3 | À vérifier | Faible si répartie |
| CoreDNS | À vérifier | À vérifier | Résolution de noms cassée |
| Ingress (Traefik) | À vérifier | À vérifier | Plus aucun trafic entrant |
| Nœud server k3d | 1 | Non | Plan de contrôle perdu |
Questions à poser : combien d'exemplaires, où tournent-ils, qui en dépend, que se passe-t-il s'il disparaît ?
Chaos Mesh¶
Présentation de Chaos Mesh¶
- Plateforme de Chaos Engineering native Kubernetes, projet CNCF en incubation
- Chaque expérience est une ressource personnalisée (CRD) : YAML versionnable et relisible en Merge Request
- Large catalogue de fautes : pods, réseau, ressources, HTTP, I/O, DNS, horloge
- Planification avec
Scheduleet orchestration de scénarios avecWorkflow - Dashboard web avec gestion des droits par RBAC Kubernetes
Épinglez une version vérifiée du chart et suivez les avis de sécurité du projet
Architecture¶
kubectl apply / Dashboard
│
▼
┌───────────────────────────────────────┐
│ chaos-controller-manager (Deployment) │ réconcilie les CRD,
│ │ gère Schedule et Workflow
└───────────────────┬───────────────────┘
│ gRPC
┌───────────────────▼───────────────────┐
│ chaos-daemon (DaemonSet privilégié) │ entre dans les namespaces
│ un pod par nœud │ réseau et PID des conteneurs
└───────────────────────────────────────┘ via le runtime (containerd)
chaos-dashboard : interface web, jetons RBAC
chaos-dns-server : réponses DNS falsifiées pour DNSChaos
Le catalogue des fautes¶
| CRD | Actions principales | Cas d'usage |
|---|---|---|
PodChaos | pod-kill, pod-failure, container-kill | Perte de réplicas |
NetworkChaos | delay, loss, duplicate, corrupt, partition, bandwidth | Réseau dégradé |
StressChaos | stress CPU, stress mémoire | Surcharge, OOMKill |
HTTPChaos | abort, delay, replace, patch | Dépendance HTTP défaillante |
IOChaos | latence, erreurs, attributs de fichiers | Disque lent ou en erreur |
DNSChaos | error, random | Résolution de noms cassée |
TimeChaos | décalage d'horloge | Expiration de jetons, certificats |
Sélectionner les cibles¶
apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
name: api-pod-kill
namespace: securepay
spec:
action: pod-kill
mode: one # one, all, fixed, fixed-percent, random-max-percent
selector:
namespaces:
- securepay
labelSelectors:
app.kubernetes.io/name: securepay-api
modeetvaluerèglent le rayon d'impact :fixed-percentavecvalue: "50"touche la moitié des podsdurationborne les fautes persistantes (pod-failure, réseau, stress)
NetworkChaos : latence¶
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: api-latency-300ms
namespace: securepay
spec:
action: delay
mode: all
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
delay:
latency: 300ms
jitter: 50ms
duration: 5m
action: lossavecloss: { loss: "20" }pour 20 % de perte de paquetsdirectionettargetlimitent la faute au trafic vers une dépendance précise
StressChaos : mémoire¶
apiVersion: chaos-mesh.org/v1alpha1
kind: StressChaos
metadata:
name: api-memory-stress
namespace: securepay
spec:
mode: one
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
stressors:
memory:
workers: 2
size: 512MB # taille totale, répartie entre les workers
duration: 3m
- Le stresseur s'exécute dans le cgroup du conteneur ciblé : au-delà de la limite mémoire, le conteneur est tué (
OOMKilled) stressors.cpuavecworkersetloadpour une surcharge CPU (throttling)
HTTPChaos : réponses en erreur¶
apiVersion: chaos-mesh.org/v1alpha1
kind: HTTPChaos
metadata:
name: api-http-500
namespace: securepay
spec:
mode: fixed
value: "1" # un seul pod sur les réplicas
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
target: Response
port: 3000
path: /api/*
replace:
code: 500
duration: 5m
- La « fraction du trafic » touchée dépend du nombre de pods ciblés
- HTTP en clair uniquement, et les connexions TCP déjà ouvertes ne sont pas affectées
Schedule : rejouer en continu¶
apiVersion: chaos-mesh.org/v1alpha1
kind: Schedule
metadata:
name: api-pod-kill-hourly
namespace: securepay
spec:
schedule: "0 * * * *"
historyLimit: 5
concurrencyPolicy: Forbid
type: PodChaos
podChaos:
action: pod-kill
mode: one
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
- Met en œuvre le principe « automatiser pour jouer en continu »
- À réserver aux expériences déjà maîtrisées en mode manuel
Workflow : un GameDay en YAML¶
apiVersion: chaos-mesh.org/v1alpha1
kind: Workflow
metadata:
name: gameday-securepay
namespace: securepay
spec:
entry: gameday
templates:
- name: gameday
templateType: Serial
deadline: 20m
children: [kill-one-pod, pause, add-latency]
- name: kill-one-pod
templateType: PodChaos
deadline: 1m
podChaos: { action: pod-kill, mode: one, selector: { labelSelectors: { app.kubernetes.io/name: securepay-api } } }
- name: pause
templateType: Suspend
deadline: 3m
- name: add-latency
templateType: NetworkChaos
deadline: 5m
networkChaos: { action: delay, mode: all, selector: { labelSelectors: { app.kubernetes.io/name: securepay-api } }, delay: { latency: 300ms } }
Workflow : condition d'arrêt automatique¶
- name: api-health-guard
templateType: StatusCheck
deadline: 20m
abortWithStatusCheck: true # arrête tout le Workflow en cas d'échec
statusCheck:
mode: Continuous
type: HTTP
intervalSeconds: 5
timeoutSeconds: 2
failureThreshold: 3 # trois échecs consécutifs
successThreshold: 1
http:
url: http://securepay-api.securepay.svc:3000/ready
method: GET
criteria:
statusCode: "200"
- Placé dans un nœud
Parallelà côté de la séquence d'expériences - Selon la documentation, les nœuds
StatusChecks'écrivent en YAML : le dashboard ne permet pas de les créer
Installation sur k3s¶
k3s embarque son propre containerd : le socket n'est pas au chemin standard
helm repo add chaos-mesh https://charts.chaos-mesh.org
helm upgrade --install chaos-mesh chaos-mesh/chaos-mesh \
--namespace chaos-mesh --create-namespace \
--version <version-verifiee> \
--set chaosDaemon.runtime=containerd \
--set chaosDaemon.socketPath=/run/k3s/containerd/containerd.sock \
--set controllerManager.enableFilterNamespace=true \
--set dashboard.securityMode=true
# Autoriser explicitement le namespace cible
kubectl annotate ns securepay chaos-mesh.org/inject=enabled
- Avec
enableFilterNamespace, seuls les namespaces annotés peuvent recevoir des fautes - Vérifiez les clés avec
helm show values chaos-mesh/chaos-meshpour la version choisie
Sécuriser le chaos¶
Un outil capable de tuer des processus partout est une cible de choix
- Périmètre :
enableFilterNamespaceet annotation des seuls namespaces autorisés - RBAC : rôles distincts pour créer des expériences et pour les consulter, jetons dédiés au dashboard
- Dashboard :
securityModeactif, jamais exposé publiquement, accès parport-forward - chaos-daemon : DaemonSet privilégié, à traiter comme un composant sensible
- Mises à jour : les failles « Chaotic Deputy » (2025) exposaient une API de debug non authentifiée du controller-manager, corrigées en 2.7.3
- Traçabilité : expériences versionnées, appliquées par une personne identifiée
Chaos et GitOps¶
- Versionnez les expériences dans
chaos/: elles sont relues en Merge Request comme le reste - Ne les synchronisez pas automatiquement avec ArgoCD : avec
selfHeal, une expérience supprimée serait recréée et relancée - Appliquez-les explicitement, au moment choisi, par une personne identifiée
- Exception : les
Schedulevalidées, volontairement déclarées comme état désiré
kubectl apply -f chaos/01-api-pod-kill.yaml
kubectl get podchaos -n securepay
kubectl delete -f chaos/01-api-pod-kill.yaml # bouton d'arrêt
Perte de nœud & Répartition¶
Que se passe-t-il quand un nœud disparaît ?¶
T0 Le nœud ne répond plus (k3d node stop k3d-securepay-agent-1)
T0 + ~50 s node-monitor-grace-period dépassé : nœud NotReady / Unknown
taint node.kubernetes.io/unreachable:NoExecute posé
pods du nœud marqués non prêts, retirés des endpoints
T0 + ~6 min tolérance par défaut de 300 s expirée : éviction des pods
le contrôleur recrée les pods sur les nœuds restants
- Les tolérances
not-readyetunreachablede 300 s sont ajoutées par le plugin d'admissionDefaultTolerationSeconds - Entre T0 et le retrait des endpoints, les requêtes routées vers le nœud perdu échouent
- Pendant six minutes, le service tourne avec une capacité réduite
Réduire l'impact de la perte d'un nœud¶
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/name: securepay-api
tolerations:
- key: node.kubernetes.io/unreachable
operator: Exists
effect: NoExecute
tolerationSeconds: 30
- key: node.kubernetes.io/not-ready
operator: Exists
effect: NoExecute
tolerationSeconds: 30
- Répartir : une partie du service survit immédiatement
- Raccourcir la tolérance : la capacité se reconstitue plus vite, au prix d'évictions lors de micro-coupures
LitmusChaos : l'alternative¶
| Chaos Mesh | LitmusChaos | |
|---|---|---|
| Statut CNCF | Incubation | Incubation |
| Modèle | Une CRD par type de faute | Expériences issues du ChaosHub, orchestrées par ChaosCenter |
| Validation de l'état stable | StatusCheck HTTP dans les Workflows | Probes intégrées (HTTP, commande, Prometheus, Kubernetes) |
| Interface | Dashboard | ChaosCenter (multi-clusters, multi-équipes) |
| Prise en main | Rapide, YAML direct | Plus riche, plus de composants |
Le choix d'outil compte moins que la rigueur de la démarche : hypothèse, bornes, mesure
Documenter : le rapport de résilience (exemple)¶
| Expérience | Hypothèse | Résultat | Impact SLO | Preuve | Action corrective |
|---|---|---|---|---|---|
| Pod-kill API | SLO tenu | Validée | Aucun | Capture Grafana 14h02 | Aucune |
| Perte de nœud | SLO tenu | Invalidée | 4 % d'erreurs pendant 50 s | Résumé k6 | Répartition + tolérance 30 s |
| Latence 300 ms | p95 < 300 ms | Invalidée | p95 à 420 ms | Capture Grafana | Timeouts et retries revus |
- Une ligne par expérience, rejouée après correction
- Les preuves sont horodatées et rangées avec le rapport
Synthèse¶
À retenir¶
- Le Chaos Engineering est une démarche expérimentale, pas une destruction aléatoire
- Pas d'expérience sans état stable mesuré, rayon d'impact borné et conditions d'arrêt
- Chaos Mesh décrit chaque faute en YAML : versionnable, relisible, rejouable
- Sur k3s, configurez le socket containerd
/run/k3s/containerd/containerd.sock - Restreignez le chaos aux namespaces annotés et protégez le dashboard
- La perte d'un nœud coûte jusqu'à six minutes de capacité par défaut : répartissez et réglez les tolérances
- Une hypothèse invalidée, corrigée puis rejouée, est le meilleur résultat d'un GameDay