随着汤不热吧技术社区核心业务链路从单体演进到 30+ 微服务、每天承载数百万次请求,”系统能否在局部故障下继续提供服务”逐渐从一个理论问题变成了每月真实上演的线上事故。被动等待告警、人工复盘、打补丁的循环已经无法满足 99.95% 的可用性目标。为此,我们在 2026 年第三季度正式上线了统一的混沌工程平台,以 Chaos Mesh 2.7 为核心、Litmus Chaos 作为补充引擎,将”主动注入故障”固化为日常工程实践。本文完整记录选型、部署、实验编排、CI 集成与踩坑过程,供同行参考。
一、为什么是混沌工程:从”修 Bug”到”验证韧性”
传统的高可用建设路径是”出事 -> 定位 -> 修复 -> 加监控”,本质上是一种被动响应模式。这种模式的问题在于:只有在真实故障发生时,你才知道系统的韧性边界在哪。而生产环境的故障种类繁多——网络分区、磁盘满、Pod 被 OOM Kill、上游依赖超时、DNS 解染、证书过期——很多场景很难自然发生,等到它真的发生时往往已经造成不可逆的影响。
混沌工程的核心思想是主动、可控、小范围地注入故障,在故障还是”演习”的时候就暴露系统的薄弱环节,从而把”未知的未知”转化为”已知的已知”。Netflix 的 Chaos Monkey 是这一思想的鼻祖,而 CNCF 毕业项目 Chaos Mesh 则把混沌工程从”杀进程”扩展到了覆盖网络、磁盘、IO、时间、内核、JVM、HTTP 等 50+ 故障类型的完整平台。
我们给混沌工程平台设定了三个明确目标:
- 常态化演练:每周自动执行 20+ 个稳态假设实验,而非每季度一次的人工演练。
- 左移到 CI:核心服务的 PR 流水线中强制接入”故障注入通过率”作为合并门禁。
- 可量化韧性评分:每个服务拥有一个 0-100 的”韧性分”,由实验通过率、MTTR、降级覆盖率加权得出,写入服务目录。
二、平台选型:Chaos Mesh 与 Litmus 横向对比
在选型阶段,我们对 CNCF 生态中两个主流混沌工程平台做了深度对比。下表是核心维度评估:
| 维度 | Chaos Mesh 2.7 | Litmus Chaos 3.x |
|---|---|---|
| 架构 | CRD + controller-runtime,Dashboard 一体化 | ChaosCenter + Workflow CRD + Agent |
| 故障类型 | 50+(网络/磁盘/IO/时间/内核/JVM/HTTP/Stress/Pod/Container) | 200+ 实验库(ChaosHub),社区贡献多 |
| 调度 | Workflow + Serial/Parallel 节点,支持条件分支 | Litmus Workflow + argo-style DAG |
| 安全模型 | RemoteCluster + ServiceAccount + RBAC,支持多租户 | ChaosOperator + RBAC,多集群需自建 |
| 稳态检测 | 内置 SteadyState + 外部 Prometheus 查询 | 需要配合 Grafana + 自定义 probe |
| CI 集成 | 提供 chaos-mesh-action GitHub Action | Litmus CLI + Argo Workflow 集成成熟 |
| 社区活跃度 | CNCF Incubating,字节跳动主导,更新频繁 | CNCF Incubating,MayaData 主导 |
最终我们选择 Chaos Mesh 作为主引擎(覆盖日常稳态实验、内核级故障、JVM 故障),Litmus 作为补充(利用 ChaosHub 中现成的分布式系统实验,如 Cassandra 写冲突、Kafka 消费者漂移等场景)。两者通过统一的”实验流水线”层调度,对上层屏蔽差异。
三、Chaos Mesh 2.7 部署实践
Chaos Mesh 依赖 Kubernetes 1.23+ 与 cert-manager。我们在现有的 v1.29 集群上部署,使用了 Helm + 自定义 values 的方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 # 添加 Chaos Mesh 官方 Helm 仓库
helm repo add chaos-mesh https://charts.chaos-mesh.org
helm repo update
# 创建专用命名空间
kubectl create namespace chaos-testing
# 部署 Chaos Mesh 2.7(开启 chaosd 内核故障支持)
helm install chaos-mesh chaos-mesh/chaos-mesh \
--namespace chaos-testing \
--version 2.7.0 \
--set chaosDaemon.runtime=containerd \
--set chaosDaemon.socketPath=/run/containerd/containerd.sock \
--set dashboard.securityMode=true \
--set chaosd.enabled=true \
--set bpfki.enabled=true
# 验证安装
kubectl get pods -n chaos-testing
# chaos-mesh-chaos-controller-manager-xxxx 1/1 Running
# chaos-mesh-chaos-daemon-xxxx 1/1 Running
# chaos-mesh-chaos-dashboard-xxxx 1/1 Running
关键配置说明:
- chaosd.enabled:开启 chaosd,用于在节点级别注入内核故障(如修改 sysctl、篡改文件、内核网络故障)。
- bpfki.enabled:开启基于 eBPF 的内核故障注入(如 IO 慢、网络篡改),需要节点内核 >= 5.4 并挂载 BPF map。
- dashboard.securityMode:开启 Dashboard 的 RBAC,避免任何登录用户都能注入任意故障。
- containerd socket:务必与集群实际容器运行时匹配,否则 chaos-daemon 无法操作 Pod。
部署完成后,需要为目标命名空间打上
1 | chaos-mesh.org/inject=enabled |
标签,Chaos Mesh 的 webhook 才会注入 sidecar:
1
2
3
4 koLookup namespaces with chaos injection enabled
kubectl label namespace content-service chaos-mesh.org/inject=enabled
kubectl label namespace search-service chaos-mesh.org/inject=enabled
kubectl label namespace gateway chaos-mesh.org/inject=enabled
四、实验编排:稳态假设驱动的工作流
混沌实验的核心不是”注入故障”,而是”稳态假设(Steady-State Hypothesis)“——在注入故障前后,系统的关键指标必须保持在预期范围内。一个完整的实验包含四个要素:
- 稳态假设:例如”内容服务的 P99 延迟 < 200ms,错误率 < 0.1%"。
- 故障注入:例如”kill 掉 30% 的 content-service Pod”。
- 持续探测:实验期间持续从 Prometheus 拉取指标,对比阈值。
- 回滚:实验结束自动恢复故障。
下面是一个完整的 Chaos Mesh Workflow YAML,模拟”内容服务 30% Pod 被随机杀掉,持续 60 秒”的场景:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 apiVersion: chaos-mesh.org/v1alpha1
kind: Workflow
metadata:
name: content-service-pod-kill
namespace: chaos-testing
spec:
entry: main
templates:
- name: main
templateType: Serial
children:
- steady-state-check
- inject-pod-kill
- post-check
- name: steady-state-check
templateType: Task
task:
container:
name: prom-check
image: curlimages/curl:8.5.0
command:
- /bin/sh
- -c
- |
RESULT=$(curl -s "http://prometheus.monitoring:9090/api/v1/query?query=histogram_quantile(0.99,sum(rate(http_request_duration_seconds_bucket{service="content-service"}[1m]))by(le))" | jq '.data.result[0].value[1]')
if (( $(echo "$RESULT > 0.2" | bc -l) )); then
echo "P99 latency $RESULT exceeds 200ms"
exit 1
fi
echo "Steady state OK: P99=${RESULT}s"
- name: inject-pod-kill
templateType: PodChaos
podChaos:
action: pod-kill
mode: fixed-percent
value: "30"
selector:
namespaces:
- content-service
labelSelectors:
"app.kubernetes.io/name": content-service
scheduler:
cron: "@every 60s"
- name: post-check
templateType: Task
task:
container:
name: prom-check
image: curlimages/curl:8.5.0
command: ["sh", "-c", "echo 'Experiment completed, verifying recovery...'"]
这个 Workflow 会先做一次稳态检查,通过后才执行 Pod kill。如果稳态检查失败,整个 Workflow 会标记为 aborted,避免在不稳定的状态下注入故障。
4.1 网络故障实验:模拟下游依赖超时
社区的内容服务依赖 Elasticsearch 做全文检索。我们用 NetworkChaos 模拟”ES 网络延迟 500ms,丢包 10%”的场景,验证服务是否有合理的超时与降级:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: content-service-es-latency
namespace: chaos-testing
spec:
action: delay
mode: all
selector:
namespaces:
- content-service
labelSelectors:
"app.kubernetes.io/name": content-service
delay:
latency: "500ms"
correlation: "0"
jitter: "50ms"
loss:
loss: "10"
correlation: "20"
direction: to
target:
selector:
namespaces:
- search-service
labelSelectors:
"app.kubernetes.io/name": elasticsearch
duration: "120s"
scheduler:
cron: "@every 5m"
第一次跑这个实验时,我们立刻发现了一个隐患:内容服务的 ES 客户端超时设置为 30 秒,意味着在 ES 慢 500ms 的情况下,用户请求会堆积,线程池被打满,最终引发雪崩。这个隐患在没有混沌实验前从未被发现——因为 ES 在生产环境很少这么慢。修复方案是把超时从 30s 降到 2s,并引入 Bulkhead 线程池隔离 + Sentinel 熔断器,这样即便 ES 持续慢,内容服务也会快速失败而不是拖垮整个调用链。
五、与 CI/CD 流水线集成:把韧性左移
把混沌实验从”人工季度演练”升级为”每次 PR 自动验证”,是平台落地最关键的一步。我们基于 GitHub Actions 的
1 | chaos-mesh-action |
实现了流水线门禁:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 # .github/workflows/chaos-gate.yml
name: Chaos Resilience Gate
on:
pull_request:
paths:
- 'services/content-service/**'
- 'services/search-service/**'
jobs:
chaos-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Provision kind cluster
uses: helm/kind-action@v1
with:
config: .github/kind-config.yaml
- name: Install Chaos Mesh
uses: chaos-mesh/chaos-mesh-action@v2
with:
version: v2.7.0
chaosd: true
- name: Deploy service under test
run: |
helm install content-service ./services/content-service/chart \
--wait --timeout 120s
- name: Run resilience experiment
run: |
kubectl apply -f .github/chaos-experiments/content-service-pod-kill.yaml
# 等待实验完成或失败
kubectl wait workflow/content-service-pod-kill \
-n chaos-testing --for=condition=complete --timeout=300s
- name: Gate check
run: |
# 若实验失败,流水线报错阻断合并
STATUS=$(kubectl get workflow content-service-pod-kill -n chaos-testing -o jsonpath='{.status.conditions[?(@.type=="Complete")].reason}')
if [ "$STATUS" != "Succeeded" ]; then
echo "::error::Resilience experiment failed — merge blocked"
exit 1
fi
这条流水线的作用是:每次内容服务的 PR,都会在 ephemeral kind 集群中部署服务、注入 Pod kill、跑稳态假设,不通过则阻断合并。这意味着”不能扛住 30% Pod 故障的代码根本进不了主干“。落地两个月后,我们观察到内容服务的线上 MTTR 从 18 分钟下降到 6 分钟,故障驱动的 hotfix 数量下降 40%。
六、关键踩坑与经验总结
平台上线三个月,我们记录了若干血泪教训:
- 不要在生产环境跑”无主”实验。早期我们直接在 prod namespace 注入 Pod kill,结果一个 Workflow 的 selector 写错(label 写成
1app=content
而非
1app.kubernetes.io/name=content-service),误杀了一批无关服务。强烈建议所有生产实验都通过 Chaos Mesh 的 Schedule 资源 + 审批 webhook 走,并默认 blast radius 限制在固定百分比。
- 稳态假设要”窄而准”。一开始我们把稳态写成”P99 < 200ms 且错误率 < 0.1% 且 QPS > 1000″,结果几乎所有实验都因 QPS 波动失败。稳态假设应该聚焦于”故障相关的核心指标”,而不是全量 SLO。我们后来拆成两组:核心稳态(延迟 + 错误率)做硬门禁,业务指标(QPS、转化率)做软告警。
- chaosd 的内核故障需要 root + 特权容器。在 GKE 等托管集群上,daemonset 默认无特权,需要单独给节点池开
1--allow-privileged
或使用 chaosd 的 non-privileged 模式(功能受限)。我们最终建了专门的 chaos-nodepool,只在这批节点上注入内核级故障。
- BPF 故障注入对内核版本敏感。bpfki 在 5.4 内核上可用,但部分高级特性(如 SO_REUSEPORT 篡改)需要 5.10+。升级节点内核前务必跑
1chaosd check kernel
。
- Litmus 与 Chaos Mesh 的”目标选择器”语义不同。Litmus 用
1targetapplication
+
1applications字段,Chaos Mesh 用
1selector.labelSelectors。统一调度层要做好语义映射,否则容易出现”选错目标”。
七、下一步规划
混沌工程平台的下一步演进方向:
- 多集群混沌:Chaos Mesh 的 RemoteCluster 已支持多集群,下一步我们会把演练范围扩展到灾备集群,验证”主集群整体不可用”场景下的跨集群切换 RTO。
- 韧性评分自动化:把每个服务的实验通过率、降级覆盖率、MTTR 聚合成 0-100 的韧性分,写入服务目录与服务网格的权重计算,让韧性低的服务自动获得更低流量。
- AI 驱动的实验生成:基于历史告警、拓扑图、调用链自动生成”最可能暴露隐患”的实验组合,从”人写实验”演进为”AI 提议实验 + 人审批”。
- 游戏日(Game Day)常态化:每季度一次的全员游戏日,由平台自动编排”复合故障剧本”(如主库宕机 + 网络分区 + 证书过期同时发生),验证 oncall 团队的协同响应。
混沌工程的本质是”用可控的代价换取对系统边界的认知“。在汤不热吧,它已经从一个工具演进为一种工程文化——每一个新服务上线,都必须通过混沌实验门禁;每一次架构变更,都必须重新验证稳态假设。我们相信,主动拥抱故障,才是真正意义上的高可用。

如对本公告涉及的混沌工程平台部署细节、Chaos Mesh 自定义实验编排、CI 门禁流水线实现有任何疑问,欢迎在评论区留言或直接在 GitHub 仓库提 issue。我们将持续在「网站公告」分类发布后续演进实录。
汤不热吧