【K8S 运维实战】22-故障演练ChaosMesh 故障演练:Chaos Mesh 与应急 SOP一句话定位:没出过事的集群最危险——主动制造故障,才能在真出事时从容应对。写在前面我带过一个团队,集群跑了半年没出过故障,大家觉得稳了。结果某天一个 etcd 节点磁盘满,触发连锁反应,半数 Pod 被驱逐,业务挂了 40 分钟才定位到根因。事后复盘,我们一致同意上 Chaos Mesh 做故障演练。半年里我们主动注入了 30 多种故障,提前暴露了 5 个潜在隐患。从此团队的口头禅变成:不演练,就没有真正的稳。这篇把 Chaos Mesh 故障注入和应急 SOP 一起讲,让主动出事成为运维习惯。核心问题没出过事的集群最危险,怎么主动制造故障?Chaos Mesh 注入网络/IO/Pod/时间等故障,模拟真实异常。演练怎么设计才不搞砸生产?稳态假设 → 受控注入 → 观察 → 恢复 → 复盘,严格守边界。出事时怎么快速响应?应急 SOP 分级响应,通报链清晰,复盘闭环。一、原理剖析1.1 Chaos Mesh 架构Chaos Mesh 是 PingCAP 开源的云原生混沌工程平台:调度监听 CRD注入故障网络/IO 操作记录创建实验chaos-mesh-controllerchaos-daemon DaemonSetChaosEngine CRD目标 Pod节点内核chaos-dashboardchaos-mesh CLI核心组件:chaos-controller-manager:控制器,监听 Chaos CRD,调度实验chaos-daemon:DaemonSet,在每个节点执行故障注入(网络 tc、IO 等)chaos-dashboard:Web UI,管理实验和归档chaosctl:命令行工具1.2 故障注入类型全景Chaos Mesh 提供丰富的 CRD,覆盖主流故障类型:CRD类型模拟什么真实场景对应PodChaosPodPod Kill/Pod Failure/Container Kill节点宕机、OOMKillNetworkChaos网络延迟/丢包/重复/带宽限制网络抖动、跨机房延迟IOChaos磁盘 IO读写延迟/错误/有限带宽磁盘慢、IO 阻塞TimeChaos时钟时间偏移NTP 失同步StressChaos资源CPU/内存压测资源争抢、内存泄漏DNSChaosDNSDNS 解析失败/延迟DNS 服务故障HTTPChaosHTTP请求延迟/错误响应上游服务异常JVMChaosJVM方法异常/延迟/GCJava 应用故障1.3 演练工作流设计一次完整的演练遵循稳态假设方法:是否1. 定义稳态假设2. 基线观察3. 注入故障4. 观察系统响应稳态是否保持?5a. 恢复,演练成功5b. 紧急回滚6. 事后复盘稳态假设(Steady State Hypothesis)是核心——先定义什么是正常,再注入故障看系统是否仍保持正常。比如P99 延迟 200ms“错误率 0.1%”,注入后系统违反假设就说明有隐患。二、实战操作2.1 Chaos Mesh 安装# 添加 Chaos Mesh 仓库helm repoaddchaos-mesh https://charts.chaos-mesh.org helm repo update# 安装(指定版本支持 K8s 1.30)helminstallchaos-mesh chaos-mesh/chaos-mesh\-nchaos-testing\--create-namespace\--version2.7.0\--setchaosDaemon.runtimecontainerd\--setchaosDaemon.socketPath/run/containerd/containerd.sock\--setcontrollerManager.replicaCount3\--setdashboard.replicaCount2\--setdashboard.securityModefalse# 生产可开启 RBAC# 验证kubectl get pods-nchaos-testing# chaos-controller-manager / chaos-daemon / chaos-dashboard 都 Running# 暴露 dashboard(测试用)kubectl port-forward-nchaos-testing svc/chaos-dashboard2333:2333# 访问 http://localhost:23332.2 PodChaos 实验:模拟 Pod 被杀模拟某个 Deployment 的 Pod 被随机杀死,验证副本自愈:# podchaos-kill.yamlapiVersion:chaos-mesh.org/v1chaoskind:PodChaosmetadata:name:pod-kill-app1namespace:chaos-testingspec:action:pod-kill# 杀 Podmode:one# 一次杀一个containerName:selector:namespaces:-app1labelSelectors:app:backend# 只针对 backendscheduler:cron:every 5m# 每 5 分钟杀一次duration:30m# 演练持续 30 分钟kubectl apply-fpodchaos-kill.yaml# 观察实验状态kubectl get podchaos-nchaos-testing kubectl describe podchaos pod-kill-app1-nchaos-testing# 观察 Pod 自愈watch-n2kubectl get pods -n app1 -l appbackend2.3 NetworkChaos 实验:模拟网络延迟模拟 app1 → app2 的网络延迟,验证超时重试:# networkchaos-delay.yamlapiVersion:chaos-mesh.org/v1chaoskind:NetworkChaosmetadata:name:net-delay-app1-to-app2namespace:chaos-testingspec:action:delaymode:all# 所有匹配 Podselector:namespaces:-app1labelSelectors:app:backenddirection:to# 出方向流量target:selector:namespaces:-app2labelSelectors:app:frontendmode:alldelay:latency:500ms# 延迟 500mscorrelation:50# 50% 相关性jitter:100ms# 抖动 100msduration:10mkubectl apply-fnetworkchaos-delay.yaml# 观察 app1 调 app2 的延迟变化kubectlexec-napp1 deploy/backend --curl-w%{time_total}\n-o/dev/null-shttp://frontend.app2:802.4 IOChaos 实验:模拟磁盘慢模拟 PV 读写延迟,验证应用对慢 IO 的容忍:# iochaos-delay.yamlapiVersion:chaos-mesh.org/v1chaoskind:IOChaosmetadata:name:io-delay-app1namespace:chaos-testingspec:action:latencymode:allselector:namespaces:-app1labelSelectors:app:dbvolumePath:/var/lib/postgresql/datapath:/var/lib/postgresql/data/**/*delay:200ms# 每次 IO 延迟 200mspercent:50# 50% 的 IO 受影响duration:10m2.5 StressChaos 实验:模拟 CPU 打满# stresschaos-cpu.yamlapiVersion:chaos-mesh.org/v1chaoskind:StressChaosmetadata:name:cpu-stress-app1namespace:chaos-testingspec:mode:oneselector:namespaces:-app1labelSelectors:app:backendstressors:cpu:workers:2load:80# CPU 打到 80%duration:5m2.6 演练工作流(Workflow CRD)把多步演练编排成 Workflow,串行/并行执行:# workflow-drill.yamlapiVersion:chaos-mesh.org/v1alpha1kind:Workflowmetadata:name:app1-drillnamespace:chaos-testingspec:entry:maintemplates:-name:maintemplateType:Serial# 串行children:-kill-pod-network-delay-cpu-stress-name:kill-podtemplateType:PodChaosdeadline:5mpodChaos:action:pod-killmode:oneselector:namespaces:[app1]labelSelectors:{app:backend}-name:network-delaytemplateType:NetworkChaosdeadline:10mnetworkChaos:action:delaymode:allselector:namespaces:[app1]labelSelectors:{app:backend}delay:latency:300msdirection:to-name:cpu-stresstemplateType:StressChaosdeadline:5mstressChaos:mode:oneselector:namespaces:[app1]labelSelectors:{app:backend}stressors:cpu:workers:2load:90kubectl apply-fworkflow-drill.yaml kubectl get workflow-nchaos-testing# dashboard 里可看到可视化执行流程三、踩坑与排查坑1:Chaos Mesh 注入后没生效现象:创建了 PodChaos,但目标 Pod 没被杀。原因:selector 没匹配到 Pod,或 chaos-daemon 没在该节点运行。解决:# 1. 检查 selector 是否匹配kubectl get pods-napp1-lappbackend# 没结果说明 label 写错# 2. 查看 experiment 状态kubectl get experiment-nchaos-testing kubectl describe experimentname-nchaos-testing# 看 failed 或 not match 信息# 3. 确认 chaos-daemon 在所有节点 Runningkubectl get ds-nchaos-testing chaos-daemon坑2:网络故障注入后没清理干净现象:NetworkChaos 已删除,但节点上 tc 规则还在,网络仍异常。原因:chaos-daemon 异常退出,没清理 tc 规则。解决:# 手动清理 tc 规则sshnodetc qdisc del dev eth0 root# 或用 chaosctl 工具清理curl-sSLhttps://mirrors.chaos-mesh.org/latest/install.sh|shchaosctl clean坑3:演练误伤生产,业务挂了现象:演练 Pod Kill 误删了没有副本的 Pod,业务中断。原因:selector 范围太大,或没设演练边界。解决(预防为主):演练前确认目标 Pod 都有 ≥2 副本 PDB用 namespace 隔离演练对象先在测试环境演练,验证后再上预发设置duration上限,防实验忘记删开启--webhook拦截高风险注入四、应急 SOP 与复盘4.1 应急响应分级等级定义响应时间通报范围处理人P0核心业务全挂5 分钟全员管理层值班 SREP1核心业务降级15 分钟SRE业务负责人值班 SREP2非核心受影响30 分钟SRE 团队值班 SREP3单节点/告警2 小时SRE 内部当班 SRE4.2 应急响应 SOP┌─────────────────────────────────────────────┐ │ 应急响应 SOP 流程 │ ├─────────────────────────────────────────────┤ │ 1. 告警触发 → 值班确认(5 分钟内) │ │ 2. 通报:群里发P0 事件,启动应急 │ │ 3. 止血:先恢复业务(重启/回滚/切流) │ │ 4. 定位:查日志、metrics、最近变更 │ │ 5. 修复:根因修复 │ │ 6. 验证:业务恢复正常 │ │ 7. 收尾:通报已恢复,建复盘工单 │ │ 8. 复盘:24 小时内出复盘报告 │ └─────────────────────────────────────────────┘4.3 事后复盘模板# 故障复盘报告:标题 ## 一、故障概述 - 发生时间:2026-07-18 02:00 ~ 02:40(40 分钟) - 影响范围:app1 命名空间所有服务,约 5000 用户受影响 - 故障等级:P0 ## 二、故障影响 - 业务层面:订单服务不可用,损失预估 X 万 - 数据层面:无数据丢失 - 用户层面:下单失败,部分用户重复下单 ## 三、时间线 | 时间 | 事件 | |---|---| | 02:00 | 告警触发:app1 Pod 大量 CrashLoopBackOff | | 02:05 | 值班 SRE 确认,启动应急 | | 02:10 | 初步定位:etcd db 满,apiserver 只读 | | 02:20 | 执行 etcd compact defrag | | 02:30 | apiserver 恢复,Pod 重建 | | 02:40 | 全部业务恢复 | ## 四、根因分析 - 直接原因:etcd db 写满(2GB quota),转只读保护 - 深层原因:未开启 auto-compaction,db 增长无监控 ## 五、改进措施 | 措施 | 负责人 | 截止日期 | 状态 | |---|---|---|---| | 开启 etcd auto-compaction | 张三 | 2026-07-20 | 进行中 | | 增加 etcd db size 监控告警(70%) | 李四 | 2026-07-19 | 完成 | | 把 etcd quota 调到 8GB | 王五 | 2026-07-20 | 进行中 | | 增加 Chaos Mesh 演练:etcd 满场景 | 赵六 | 2026-07-25 | 计划中 | ## 六、经验教训 - 备份和监控同等重要,缺一不可 - etcd 是集群命根子,要有专项巡检 - 应急流程要演练,不能只在文档里4.4 演练安全边界演练范围明确(selector 精确匹配,namespace 隔离)演练目标 Pod 必须有 ≥2 副本 PDB每个实验设duration上限,防遗忘先测试环境,再预发,最后生产灰度演练前通知业务方,避开高峰准备一键回滚(删除 Chaos CR 即可恢复)演练时有人盯监控,异常立即终止生产演练从低烈度开始(Pod Kill 单个 → 网络延迟 → 资源压力)记录演练日志,便于复盘五、最佳实践生产集群部署 Chaos Mesh,定期演练(每月一次)用 Workflow CRD 编排多步演练稳态假设前置:先定义 SLO,再注入故障演练覆盖:Pod/网络/IO/CPU/内存/DNS 全类型应急 SOP 贴在值班台,P0/P1 流程烂熟于心每次故障 24 小时内出复盘报告复盘聚焦改进措施,不追责改进措施跟踪到完成,闭环管理演练结果归档,形成故障知识库chaos-daemon 资源给足,避免自身故障dashboard 开启 RBAC,限制演练权限把演练成功率作为 SRE 团队 KPI六、小结混沌工程的核心思想是主动拥抱故障。与其等故障找上门,不如我们主动制造可控的故障,提前暴露系统的薄弱点。Chaos Mesh 让故障注入变得声明式、可编排、可观测,但工具只是手段,真正有价值的是稳态假设 → 注入 → 观察 → 复盘这套方法论。配合应急 SOP 和复盘机制,你的团队就能从被动救火升级为主动防御。没出过事的集群最危险——把这句话刻在心里,把演练变成习惯,真到出事那天,你才能从容不迫。思考题PodChaos 的pod-kill和container-kill有什么区别?分别模拟什么场景?演练时稳态假设 SLO 设的太严(如错误率 0),会导致什么问题?应该怎么设?生产环境做 Chaos Mesh 演练,最大的风险是什么?如何把风险降到最低?延伸阅读Chaos Mesh 官方文档:https://chaos-mesh.org/docs/混沌工程原则:https://principlesofchaos.org/Google SRE 应急响应:https://sre.google/sre-book/incident-response/