GameDay SecurePay avec Chaos Mesh¶
Objectifs pédagogiques¶
À la fin de ce TP, vous devez être capables de :
- installer Chaos Mesh sur un cluster k3s en confinant les fautes à un seul namespace
- mesurer l'état stable de l'API avant toute injection
- concevoir, borner et jouer au moins cinq expériences sous charge réaliste
- identifier un point de défaillance unique (SPOF), le corriger puis rejouer l'expérience
- orchestrer un GameDay rejouable avec un
Workflowmuni d'une condition d'arrêt automatique - produire un rapport de résilience appuyé sur des preuves horodatées
Prérequis¶
- Le cluster k3d
securepay(1 server + 2 agents) tourne dans la VMsecurepay-prod - L'API SecurePay est déployée dans le namespace
securepayavec au moins 3 réplicas et des probesliveness/readinessconfigurées - La stack
kube-prometheus-stackest installée dansmonitoringet un dashboard Grafana affiche le taux de succès et la latence p95 de l'API - Un scénario k6 de charge nominale est disponible (par exemple
tests/robustness/nominal.js) kubectl,helm,k3detk6sont installés
Labels, ports et noms
Les exemples supposent que les pods de l'API portent le label app.kubernetes.io/name: securepay-api, que le conteneur écoute sur le port 3000 et que le Service securepay-api expose ce même port. Adaptez ces valeurs à votre chart Helm.
Consignes de sécurité¶
- Ne ciblez que le namespace
securepay, sauf expérience explicitement annoncée et bornée dans le temps - Chaque expérience a un bouton d'arrêt connu de toute l'équipe :
kubectl delete -f <fichier> - Aucune injection sans observabilité : le dashboard Grafana doit être ouvert avant de commencer
- N'exposez jamais le dashboard Chaos Mesh hors du cluster : accès par
port-forwarduniquement - Annoncez chaque injection à voix haute et notez l'heure exacte : elle servira à horodater les preuves
Contexte¶
SecurePay prépare sa mise en production et le comité de direction ne lèvera le gel qu'au vu de preuves de résilience. Vous organisez le premier GameDay de la plateforme : une série de pannes contrôlées, jouées sous charge, dont chaque résultat est mesuré, documenté et, si besoin, corrigé puis rejoué.
Les expériences sont versionnées dans le dossier chaos/ du dépôt securepay-platform, et les résultats consignés dans docs/resilience.md avec leurs preuves dans docs/preuves/.
Atelier 1 : Installer et confiner Chaos Mesh¶
Contexte¶
Chaos Mesh repose sur un DaemonSet privilégié capable d'agir dans n'importe quel conteneur du nœud. Avant la première expérience, son périmètre doit être restreint et son dashboard protégé.
Travail demandé¶
- Installez Chaos Mesh dans le namespace
chaos-meshavec le socket containerd propre à k3s et le filtrage par namespace activé
helm repo add chaos-mesh https://charts.chaos-mesh.org
helm repo update
helm show values chaos-mesh/chaos-mesh --version <version-verifiee> | less
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
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: chaos-mesh
namespace: argocd
spec:
project: default
source:
repoURL: https://charts.chaos-mesh.org
chart: chaos-mesh
targetRevision: <version-verifiee>
helm:
valuesObject:
chaosDaemon:
runtime: containerd
socketPath: /run/k3s/containerd/containerd.sock
controllerManager:
enableFilterNamespace: true
dashboard:
securityMode: true
destination:
server: https://kubernetes.default.svc
namespace: chaos-mesh
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
Version
Épinglez une version vérifiée du chart, postérieure aux correctifs de sécurité « Chaotic Deputy » (2.7.3), et contrôlez le nom des clés avec helm show values : elles peuvent évoluer d'une version à l'autre.
CRD volumineuses
Les CRD de Chaos Mesh sont volumineuses. Si la synchronisation ArgoCD échoue sur la taille d'une annotation, l'option ServerSideApply=true résout le problème.
- Autorisez explicitement le namespace applicatif à recevoir des fautes
Dans une démarche GitOps, portez plutôt cette annotation dans le manifest du namespace versionné dans securepay-platform.
- Vérifiez l'installation : un
chaos-controller-manager, unchaos-daemonpar nœud (3 au total), lechaos-dashboardet, selon la version, lechaos-dns-server
-
Prouvez le confinement : appliquez une expérience
PodChaos(pod-kill,mode: one) ciblant le namespacemonitoring, non annoté. L'expérience ne doit trouver aucune cible et aucun pod demonitoringne doit redémarrer. Supprimez-la ensuite. -
Créez un accès au dashboard limité au namespace
securepay
apiVersion: v1
kind: ServiceAccount
metadata:
name: chaos-operator
namespace: securepay
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: chaos-operator
namespace: securepay
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["chaos-mesh.org"]
resources: ["*"]
verbs: ["get", "list", "watch", "create", "delete", "patch", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: chaos-operator
namespace: securepay
subjects:
- kind: ServiceAccount
name: chaos-operator
namespace: securepay
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: chaos-operator
kubectl create token chaos-operator -n securepay --duration=8h
kubectl -n chaos-mesh port-forward svc/chaos-dashboard 2333:2333
Connectez-vous sur http://localhost:2333 avec le jeton généré.
Ce que vous devez observer¶
- un
chaos-daemonsur chacun des trois nœuds k3d - une expérience visant un namespace non annoté reste sans effet
- le dashboard refuse l'accès sans jeton et ne montre que ce que le RBAC autorise
Critère de réussite de l'atelier 1¶
L'atelier est réussi si vous pouvez démontrer que Chaos Mesh est opérationnel, que les fautes sont confinées au namespace securepay et que le dashboard n'est accessible qu'avec un jeton à droits restreints.
Atelier 2 : Mesurer l'état stable et cartographier les SPOF¶
Contexte¶
Une expérience sans état stable de référence ne prouve rien. Avant d'injecter quoi que ce soit, mesurez le comportement nominal de l'API et identifiez les composants dont la perte serait fatale.
Travail demandé¶
- Lancez la charge nominale pendant 10 minutes et relevez les indicateurs de référence
Si vous n'avez pas encore de scénario, partez de ce script minimal :
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 20,
duration: '10m',
thresholds: {
http_req_failed: ['rate<0.005'],
http_req_duration: ['p(95)<300'],
},
};
const BASE_URL = __ENV.BASE_URL || 'http://api.securepay.local';
const payload = JSON.stringify({ amount: 42.5, currency: 'EUR', recipientId: 'merchant-001' });
export default function () {
const res = http.post(`${BASE_URL}/api/payments/process`, payload, {
headers: { 'Content-Type': 'application/json' },
});
check(res, { 'paiement accepté': (r) => r.status === 201 });
sleep(0.5);
}
Requêtes PromQL de référence (adaptez le nom du label de code HTTP à votre instrumentation) :
# Taux de succès sur 1 minute
sum(rate(http_requests_total{namespace="securepay", code!~"5.."}[1m]))
/
sum(rate(http_requests_total{namespace="securepay"}[1m]))
# Latence p95
histogram_quantile(0.95,
sum by (le) (rate(http_request_duration_seconds_bucket{namespace="securepay"}[1m])))
-
Consignez l'état stable dans
docs/resilience.md: taux de succès, p95, débit, nombre de pods prêts, alertes actives -
Cartographiez les SPOF de la plateforme
kubectl get pods -n securepay -o wide
kubectl -n kube-system get deploy coredns traefik
kubectl get nodes -o wide
Complétez un tableau composant → réplicas → nœuds → dépendants → impact si perdu pour au moins l'API, CoreDNS, Traefik, le nœud k3d-securepay-server-0 et Prometheus.
- Préparez une fiche par expérience dans
docs/resilience.md
### E<n> - <titre de l'expérience>
- Hypothèse :
- Cible et rayon d'impact :
- Durée :
- Condition d'arrêt :
- Bouton d'arrêt :
- Indicateurs observés :
- Résultat (validée / invalidée) :
- Impact sur le SLO :
- Preuves :
- Action corrective :
Ce que vous devez observer¶
- un état stable chiffré qui respecte le SLO (≥ 99,5 % de succès, p95 < 300 ms)
- la répartition réelle des pods de l'API sur les nœuds
- au moins un composant à réplica unique ou concentré sur un seul nœud
Critère de réussite de l'atelier 2¶
L'atelier est réussi si l'état stable est mesuré et consigné, et si la cartographie des SPOF est documentée.
Atelier 3 : Le catalogue d'expériences du GameDay¶
Contexte¶
Chaque expérience se joue sous charge nominale, avec l'heure d'injection notée, le dashboard Grafana ouvert et le bouton d'arrêt prêt. Une hypothèse invalidée n'est pas un échec : elle révèle une faiblesse que vous corrigerez puis prouverez en rejouant l'expérience.
Travail demandé¶
Jouez au minimum les cinq expériences obligatoires E1 à E5. E6 est fortement recommandée, car elle prépare le TP d'auto-remédiation.
E1 - Perte d'un pod de l'API¶
- Hypothèse : pendant la perte d'un pod, le taux de succès reste ≥ 99,5 % et la p95 < 300 ms
- Condition d'arrêt : taux de succès < 99 % pendant plus d'une minute
apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
name: api-pod-kill
namespace: securepay
spec:
action: pod-kill
mode: one
gracePeriod: 0
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
Jouez l'expérience une première fois avec gracePeriod: 0 (suppression brutale), puis avec gracePeriod: 30. Comparez les erreurs observées par k6 : les requêtes en cours sur le pod tué sont-elles perdues ? L'application gère-t-elle SIGTERM proprement ?
E2 - Perte d'un nœud¶
Cette expérience se joue hors de Chaos Mesh, en arrêtant un nœud k3d depuis la VM.
- Hypothèse : les réplicas restants absorbent la charge, le taux de succès reste ≥ 99,5 %
- Condition d'arrêt : taux de succès < 95 % : redémarrez immédiatement le nœud
kubectl get pods -n securepay -o wide # quels pods tournent sur agent-1 ?
date +%H:%M:%S && k3d node stop k3d-securepay-agent-1
kubectl get nodes -w # dans un autre terminal
kubectl get pods -n securepay -o wide -w # dans un troisième terminal
k3d node start k3d-securepay-agent-1 # retour à la normale
Mesurez trois durées : apparition de l'état NotReady, éviction des pods du nœud perdu, retour au nombre de réplicas prêts attendu.
Plan de contrôle
N'arrêtez pas k3d-securepay-server-0 dans cette expérience : il porte le plan de contrôle (API server, ArgoCD ne pourra plus synchroniser, le HPA ne réagira plus). Sa perte peut faire l'objet d'une expérience avancée, annoncée et bornée.
Action corrective attendue si l'hypothèse est invalidée : topologySpreadConstraints sur kubernetes.io/hostname et tolérances node.kubernetes.io/unreachable / not-ready réduites (par exemple 30 s), puis nouvelle exécution de l'expérience.
E3 - Coupure de la résolution DNS¶
CoreDNS est un service critique partagé par toute la plateforme. Deux variantes sont possibles :
Le rayon d'impact est limité aux pods de l'API : elles ne peuvent plus résoudre aucun nom.
apiVersion: chaos-mesh.org/v1alpha1
kind: DNSChaos
metadata:
name: api-dns-error
namespace: securepay
spec:
action: error
mode: all
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
duration: 3m
Sans champ patterns, la faute s'applique à tous les noms de domaine. Le serveur DNS de chaos est déployé par défaut depuis Chaos Mesh 2.6 ; sur une version antérieure, activez-le avec --set dnsServer.create=true.
Expérience annoncée, limitée à 2 minutes, hors Chaos Mesh, car elle touche kube-system :
kubectl -n kube-system get deploy coredns # notez le nombre de réplicas
kubectl -n kube-system scale deploy coredns --replicas=0
# ... observation pendant 2 minutes maximum ...
kubectl -n kube-system scale deploy coredns --replicas=<valeur-initiale>
Observez ce qui casse au-delà de l'API : Grafana interroge Prometheus par son nom DNS, ArgoCD résout l'adresse de la forge Git.
- Hypothèse à formuler vous-mêmes : selon que l'API appelle ou non des dépendances par leur nom, l'impact sur son SLO peut être nul alors que l'observabilité ou le GitOps sont touchés. Documentez-le : c'est un résultat
- Action corrective si CoreDNS est un SPOF : plusieurs réplicas répartis et un PDB
Composants packagés de k3s
k3s réapplique ses manifests packagés (CoreDNS, Traefik) au redémarrage du serveur : une modification faite avec kubectl peut être écrasée. Documentez la correction pérenne retenue, par exemple la désactivation du composant packagé au profit d'un chart géré en GitOps.
E4 - Dégradation réseau : latence puis perte de paquets¶
- Hypothèse : la latence ajoutée se répercute sur la p95 sans provoquer d'erreurs en cascade ; l'alerte de latence se déclenche
- Condition d'arrêt : taux de succès < 99 %
Jouez d'abord 300 ms de latence pendant 5 minutes (manifest NetworkChaos avec action: delay vu en cours), puis 20 % de perte de paquets pendant 5 minutes :
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: api-packet-loss
namespace: securepay
spec:
action: loss
mode: all
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
loss:
loss: "20"
correlation: "0"
duration: 5m
Surveillez aussi les probes : la faute réseau s'applique au trafic du pod, y compris aux réponses aux probes du kubelet. Un pod dont la readinessProbe échoue est retiré du trafic, ce qui peut transformer une dégradation partielle en perte de capacité.
E5 - Stress mémoire jusqu'à l'OOMKill¶
- Prérequis : une limite mémoire est définie sur le conteneur de l'API (par exemple
256Mi) - Hypothèse : un pod tué par dépassement mémoire est redémarré sans impact sur le SLO, les autres réplicas absorbant la charge
- Condition d'arrêt : plus d'un pod en redémarrage simultanément
apiVersion: chaos-mesh.org/v1alpha1
kind: StressChaos
metadata:
name: api-memory-oom
namespace: securepay
spec:
mode: one
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
stressors:
memory:
workers: 2
size: 512MB
duration: 3m
Vérifiez la cause du redémarrage :
La section Last State doit indiquer Terminated avec la raison OOMKilled. Observez également si le stress est réinjecté après le redémarrage du conteneur pendant la durée de l'expérience.
E6 - Réponses HTTP 500 sur une fraction du trafic¶
- Hypothèse : avec un pod sur trois renvoyant des erreurs 500, l'alerte de burn rate rapide se déclenche en moins de 5 minutes
- Condition d'arrêt : durée de 5 minutes atteinte
apiVersion: chaos-mesh.org/v1alpha1
kind: HTTPChaos
metadata:
name: api-http-500
namespace: securepay
spec:
mode: fixed
value: "1"
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
target: Response
port: 3000
path: /api/*
replace:
code: 500
duration: 5m
Réutilisation des connexions
HTTPChaos ne s'applique qu'aux nouvelles connexions TCP. Le trafic qui passe par Traefik réutilise des connexions déjà ouvertes vers les pods : appliquez l'expérience avant de lancer k6, et si aucune erreur n'apparaît, redémarrez Traefik (kubectl -n kube-system rollout restart deploy/traefik) ou générez la charge depuis un pod du cluster avec l'option k6 noConnectionReuse: true. Cette limite est en elle-même un enseignement à consigner.
Ce que vous devez observer¶
- E1 : un nouveau pod remplace le pod tué ; l'écart entre
gracePeriod: 0etgracePeriod: 30révèle la qualité de l'arrêt propre - E2 : un délai d'environ 50 s avant
NotReady, puis environ 5 minutes supplémentaires avant l'éviction avec les tolérances par défaut - E3 : l'impact réel de la perte du DNS, souvent ailleurs que là où on l'attendait
- E4 : une p95 dégradée, et potentiellement des pods retirés du trafic par leurs probes
- E5 : un conteneur
OOMKilledet son compteur de redémarrages qui augmente - E6 : un taux d'erreur proche d'un tiers et le déclenchement de l'alerte de burn rate
Critère de réussite de l'atelier 3¶
L'atelier est réussi si au moins cinq expériences ont été jouées sous charge, chacune avec sa fiche complète, et si au moins un SPOF ou une faiblesse a été corrigé puis validé par une seconde exécution.
Atelier 4 : Un GameDay rejouable avec un Workflow¶
Contexte¶
Un GameDay manuel est difficile à rejouer à l'identique. Un Workflow Chaos Mesh enchaîne les expériences, insère des pauses de récupération et s'arrête de lui-même si l'API devient indisponible.
Travail demandé¶
- Autorisez le contrôle de santé du Workflow à joindre l'API : il est émis depuis le namespace
chaos-mesh, bloqué par une NetworkPolicy en refus par défaut
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-chaos-status-check
namespace: securepay
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: securepay-api
policyTypes: [Ingress]
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: chaos-mesh
ports:
- protocol: TCP
port: 3000
- Écrivez
chaos/gameday-workflow.yaml: un nœudParallelqui exécute en même temps un garde-fouStatusChecket la séquence d'expériences
apiVersion: chaos-mesh.org/v1alpha1
kind: Workflow
metadata:
name: gameday-securepay
namespace: securepay
spec:
entry: gameday
templates:
- name: gameday
templateType: Parallel
deadline: 25m
children: [api-health-guard, scenario]
- name: api-health-guard
templateType: StatusCheck
deadline: 25m
abortWithStatusCheck: true
statusCheck:
mode: Continuous
type: HTTP
intervalSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
successThreshold: 1
http:
url: http://securepay-api.securepay.svc:3000/ready
method: GET
criteria:
statusCode: "200"
- name: scenario
templateType: Serial
deadline: 24m
children: [kill-one-pod, recover-1, add-latency, recover-2, http-errors]
- name: kill-one-pod
templateType: PodChaos
deadline: 1m
podChaos:
action: pod-kill
mode: one
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
- name: recover-1
templateType: Suspend
deadline: 3m
- name: add-latency
templateType: NetworkChaos
deadline: 5m
networkChaos:
action: delay
mode: all
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
delay:
latency: 300ms
jitter: 50ms
- name: recover-2
templateType: Suspend
deadline: 3m
- name: http-errors
templateType: HTTPChaos
deadline: 5m
httpChaos:
mode: fixed
value: "1"
selector:
namespaces: [securepay]
labelSelectors:
app.kubernetes.io/name: securepay-api
target: Response
port: 3000
path: /api/*
replace:
code: 500
- Lancez le Workflow sous charge k6 et suivez son exécution
kubectl apply -f chaos/gameday-workflow.yaml
kubectl get workflow -n securepay
kubectl get workflownode -n securepay -w
kubectl describe workflow gameday-securepay -n securepay
- Prouvez la condition d'arrêt : ajoutez temporairement à la séquence une expérience
PodChaospod-failureenmode: allsur l'API, rejouez le Workflow et vérifiez qu'il est interrompu après trois échecs consécutifs du contrôle de santé, et que l'expérience en cours est levée
Pas de synchronisation automatique
Versionnez le Workflow dans chaos/ mais ne le faites pas synchroniser automatiquement par ArgoCD : avec selfHeal, un Workflow supprimé serait recréé et rejoué sans que personne ne l'ait décidé.
Ce que vous devez observer¶
- les expériences s'enchaînent avec leurs pauses de récupération
- le garde-fou tourne pendant toute la durée du scénario
- un Workflow qui rend l'API indisponible est interrompu de lui-même
Critère de réussite de l'atelier 4¶
L'atelier est réussi si le GameDay est rejouable par une seule commande et si l'arrêt automatique sur échec du contrôle de santé est démontré.
Atelier 5 : Rapport de résilience et preuves¶
Contexte¶
Pour le comité de direction comme pour un auditeur, seule compte une séquence horodatée et mesurée : avant, pendant et après chaque panne.
Travail demandé¶
-
Pour chaque expérience, rangez dans
docs/preuves/au minimum une capture Grafana couvrant avant, pendant et après l'injection, ainsi que l'export JSON du résumé k6 (fonctionhandleSummary). Nommez chaque fichierAAAA-MM-JJ_HHMM_<scenario>.<ext> -
Complétez la synthèse de
docs/resilience.md
| Expérience | Hypothèse | Résultat | Impact SLO | Preuve | Action corrective |
|---|---|---|---|---|---|
| E1 - Pod-kill | |||||
| E2 - Perte de nœud | |||||
| E3 - Coupure DNS | |||||
| E4 - Latence / perte | |||||
| E5 - OOMKill | |||||
| E6 - HTTP 500 |
- Pour chaque hypothèse invalidée, décrivez la correction appliquée et joignez la preuve de la seconde exécution
Critère de réussite de l'atelier 5¶
L'atelier est réussi si chaque ligne du rapport renvoie à une preuve horodatée et si chaque hypothèse invalidée est suivie d'une correction prouvée.
Questions de synthèse¶
- Pourquoi l'état stable doit-il s'exprimer en indicateurs orientés utilisateur plutôt qu'en consommation de ressources ?
- Quelle expérience a invalidé votre hypothèse de départ, et qu'avez-vous appris sur la plateforme ?
- Pourquoi la perte d'un nœud dégrade-t-elle le service pendant plusieurs minutes, et quels réglages réduisent cette fenêtre ?
- En quoi le confinement par namespace et le RBAC de Chaos Mesh relèvent-ils de la sécurité, et pas seulement du confort ?
- Quelles expériences de ce GameDay mériteraient d'être automatisées avec un
Schedule, et à quelles conditions ?