8.7 混沌工程入门——Chaos Mesh 与 Litmus 实战

预计阅读时间:15 分钟

📖 目录

6.2:Kubernetes 入门 搭建了 K8s 集群,6.15:HA 集群 保障了高可用。但生产环境永远有意外——节点宕机、网络抖动、磁盘满。混沌工程通过在受控环境中主动注入故障,验证系统的韧性,在真正事故发生前发现问题。

学习目标

  • 理解"建立稳态假设 → 注入故障 → 观察反应 → 持续验证"的混沌工程循环
  • 能对比 Chaos Mesh 与 Litmus 的定位与能力,并做出选型
  • 掌握 PodChaos、NetworkChaos、StressChaos 等故障注入资源的编写
  • 能用 ChaosWorkflow 编排多步骤的混沌实验
  • 能通过爆炸半径、deadline 与 staging 先行控制实验风险
  • 能结合监控指标评估系统韧性并沉淀韧性手册

前置知识

混沌工程原则

  1. 建立稳态假设:先定义正常状态的指标(延迟 P99 < 200ms、错误率 < 1%)
  2. 注入真实故障:模拟生产中实际会发生的问题
  3. 观察系统反应:监控指标是否偏离稳态
  4. 持续验证:故障恢复后指标应回到稳态

方案对比

Chaos MeshLitmus Chaos
CNCF 阶段孵化项目毕业项目
故障类型Pod/网络/文件系统/JVM/HTTPPod/节点/网络/IO/Chaos Hub
实验编排Chaos Dashboard + CRDChaosHub + Workflow
多集群支持支持
学习曲线
推荐 新团队从 Chaos Mesh 开始——Dashboard 直观,CRD 声明式。Litmus 更适合需要 ChaosHub 社区实验库的场景。

1. Chaos Mesh 安装

# 安装 Chaos Mesh
helm repo add chaos-mesh https://charts.chaos-mesh.org
helm install chaos-mesh chaos-mesh/chaos-mesh \
  -n chaos-mesh --create-namespace \
  --set chaosDaemon.runtime=containerd \
  --set chaosDaemon.socketPath=/run/containerd/containerd.sock

# 验证
kubectl get pods -n chaos-mesh

# 访问 Dashboard
kubectl port-forward -n chaos-mesh svc/chaos-dashboard 2333:2333
# 浏览器打开 http://localhost:2333

2. 常见故障注入

Pod 故障——杀 Pod

# 随机杀掉 1 个 frontend Pod
apiVersion: chaos-mesh.org/v1alpha1
kind: PodChaos
metadata:
  name: pod-kill
  namespace: default
spec:
  action: pod-kill
  mode: one
  selector:
    namespaces: [default]
    labelSelectors:
      app: frontend
  scheduler:
    cron: "@every 5m"  # 每 5 分钟执行一次

网络故障——延迟注入

# 给 backend 服务注入 200ms 网络延迟
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
  name: network-delay
spec:
  action: delay
  mode: all
  selector:
    namespaces: [default]
    labelSelectors:
      app: backend
  delay:
    latency: "200ms"
    jitter: "50ms"
    correlation: "50"
  direction: to
  target:
    selector:
      labelSelectors:
        app: database
    mode: all

网络故障——丢包

# 给指定 Pod 注入 30% 丢包率
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
  name: network-loss
spec:
  action: loss
  mode: one
  selector:
    namespaces: [default]
    labelSelectors:
      app: payment
  loss:
    loss: "30"
    correlation: "50"

磁盘故障——填充磁盘

# 填充 /var/lib/docker 目录 5GB
apiVersion: chaos-mesh.org/v1alpha1
kind: StressChaos
metadata:
  name: disk-fill
spec:
  mode: one
  selector:
    namespaces: [default]
    labelSelectors:
      app: worker
  stressors:
    memory:
      workers: 1
      size: "5GB"
  stressngStressors: "--hdd 1 --hdd-bytes 5G --hdd-dir /var/lib/docker"

CPU 压力

# 消耗 2 个 CPU 核心
apiVersion: chaos-mesh.org/v1alpha1
kind: StressChaos
metadata:
  name: cpu-stress
spec:
  mode: all
  selector:
    namespaces: [default]
    labelSelectors:
      app: api
  stressors:
    cpu:
      workers: 2
      load: 80

I/O 故障——磁盘读写延迟与错误

# 让 worker 的 /data 目录写入延迟 50ms、每 10 次写 1 次失败
apiVersion: chaos-mesh.org/v1alpha1
kind: IOChaos
metadata:
  name: io-fault
spec:
  action: latency
  mode: one
  selector:
    namespaces: [default]
    labelSelectors:
      app: worker
  volumePath: /data
  path: "/var/lib/mysql/**"
  delay: "50ms"
  percent: 100
  duration: "5m"
  errno: 5
# 指定路径 100% 注入 EIO 错误(模拟磁盘损坏)
apiVersion: chaos-mesh.org/v1alpha1
kind: IOChaos
metadata:
  name: io-error
spec:
  action: fault
  mode: all
  selector:
    labelSelectors:
      app: worker
  volumePath: /data
  path: "/data/**"
  percent: 100
  errno: 5  # EIO

HTTP 故障——接口延迟与返回码篡改

# 对 frontend 的 /api 路径注入 500 错误,占比 50%
apiVersion: chaos-mesh.org/v1alpha1
kind: HTTPChaos
metadata:
  name: http-500
spec:
  mode: one
  selector:
    namespaces: [default]
    labelSelectors:
      app: frontend
  target: Request
  port: 8080
  path: "/api/**"
  abort: true
  code: 500
  duration: "3m"

时间故障——时钟偏移

# 将认证服务的时间向前拨 30 分钟,验证 JWT/会话是否过期
apiVersion: chaos-mesh.org/v1alpha1
kind: TimeChaos
metadata:
  name: clock-skew
spec:
  mode: one
  selector:
    labelSelectors:
      app: auth
  timeOffset: "-30m"
  clockIds: ["CLOCK_REALTIME"]

故障注入类型一览

类型资源典型动作适用验证场景
Pod 故障PodChaospod-kill / pod-failure / container-killDeployment 副本自愈、重启策略
网络故障NetworkChaosdelay / loss / duplicate / corrupt / partition超时重试、熔断降级
磁盘 I/OIOChaoslatency / fault / attrOverride存储层限流、慢盘降级
压力注入StressChaosCPU / 内存 / 磁盘压满OOMKilled、驱逐策略、容量上限
HTTP 故障HTTPChaosabort / delay / replace bodyAPI 网关容错、重试语义
时间偏移TimeChaos时钟快进/回拨Token 过期、证书校验、定时任务
DNS 故障DNSChaos域名解析错误/随机 IP服务发现依赖、DNS 缓存

3. 实验编排——ChaosWorkflow

# 先杀 Pod,等 10 秒,再注入网络延迟,观察恢复
apiVersion: chaos-mesh.org/v1alpha1
kind: Workflow
metadata:
  name: api-resilience-test
spec:
  entry: api-chaos
  templates:
  - name: api-chaos
    templateType: Serial
    children:
    - step-kill-pod
    - step-network-delay
    - step-observe

  - name: step-kill-pod
    templateType: PodChaos
    embed:
      apiVersion: chaos-mesh.org/v1alpha1
      kind: PodChaos
      metadata:
        name: step-kill-pod
      spec:
        action: pod-kill
        mode: one
        selector:
          labelSelectors:
            app: api

  - name: step-network-delay
    templateType: Schedule
    embed:
      apiVersion: chaos-mesh.org/v1alpha1
      kind: Schedule
      metadata:
        name: step-delay
      spec:
        schedule: "@every 1m"
        concurrencyPolicy: Forbid
        type: NetworkChaos
        networkChaos:
          action: delay
          mode: all
          selector:
            labelSelectors:
              app: api
          delay:
            latency: "500ms"

Workflow 进阶:并行阶段与恢复模板

# Parallel:同一时刻对多个目标注入(验证链路同时故障)
- name: multi-target-parallel
  templateType: Parallel
  children:
  - step-backend-delay
  - step-db-loss
# 注意:Parallel 内每个子步骤的 deadline 要一致,
# 否则先结束的故障恢复、后结束的还在注入,无法对比

# Suspend:在步骤之间暂停固定时长(等待系统收敛再注入下一步)
- name: wait-settle
  templateType: Suspend
  duration: 30s

# 失败处理:Serial 中某一步失败时后续步骤是否继续
# 默认失败即中断——推荐保持该行为:注入失败说明环境已异常,
# 继续注入只会把问题搅浑,先止损再排查
串行与并行的选择 验证「单故障韧性」用 Serial + Suspend;验证「多故障叠加」(如磁盘满 + 网络抖动同时发生)才用 Parallel——叠加实验要提前约定主次故障,避免事后无法归因。

4. 混沌实验 Checklist

实验故障类型验证指标
Pod 故障恢复随机杀 PodDeployment 自动恢复,服务可用
节点故障模拟节点 NotReadyPod 被驱逐到其他节点
网络分区跨可用区网络中断服务降级但不崩溃
数据库故障主库宕机自动切换到从库
磁盘满填满磁盘空间日志不丢失,服务优雅降级
时钟偏移NTP 同步异常证书/Token 不过期

5. 安全边界

  • 先在 staging 执行,观察一段时间后再上生产
  • 设置爆炸半径:通过 mode: onemode: fixed(1) 限制影响范围
  • 配置自动恢复:Chaos Mesh 实验默认在 deadline 后自动停止
  • 禁止在无备份时注入数据库故障
  • 监控告警:实验期间保持 Prometheus + Grafana 监控面板打开

6. Litmus 完整案例

Litmus 的核心概念是 ChaosExperiment(故障定义模板,多来自 ChaosHub)+ ChaosEngine(实验实例,绑定目标应用)。实验由 chaos-operator 调度,通过 RBAC 限定的 ServiceAccount 执行。

# 1. 安装 Litmus(Helm 方式)
helm repo add litmuschaos https://litmuschaos.github.io/litmus-helm/
helm install litmus litmuschaos/litmus --namespace litmus --create-namespace

# 2. 从 ChaosHub 安装 pod-delete 实验模板
kubectl apply -f https://hub.litmuschaos.io/api/chaos/2.16.0?file=charts/generic/pod-delete/experiment.yaml
# 3. 定义 ChaosEngine:只对 payment 应用的 Pod 生效
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
  name: payment-pod-delete
  namespace: default
spec:
  appinfo:
    appns: default
    applabel: "app=payment"
    appkind: deployment
  chaosServiceAccount: litmus-admin
  experiments:
  - name: pod-delete
    spec:
      components:
        env:
        - name: TOTAL_CHAOS_DURATION
          value: "60"
        - name: CHAOS_INTERVAL
          value: "10"
        - name: FORCE
          value: "false"
  # 只允许在 22:00-06:00 之外执行(安全边界)
  annotationCheck: "true"

执行流程:kubectl apply -f engine.yaml 后,operator 监听 ChaosEngine 变更,创建 ChaosRun 与对应 Job;Job 内的 experiment pod 对目标 Deployment 注入 pod-delete;期间 Litmus 通过 litmus-check 观察应用恢复;实验结束生成 ChaosResult 记录结果。

# 4. 查看实验结果
kubectl get chaosresult payment-pod-delete-pod-delete -o jsonpath='{.status.experimentStatus.verdict}'
# 输出 Pass / Fail / Stopped

# 5. 查询实验事件详情
kubectl describe chaosengine payment-pod-delete

7. 实验编排与设计原则

混沌实验不是随机破坏,而是带着假设的验证工程。设计一个实验前先回答三个问题:系统正常时的稳态指标是什么?我要验证哪个韧性假设?最坏情况下爆炸半径多大?

  • 单一变量:一次实验只注入一类故障,否则无法定位根因;多条链路要验证时拆成 Workflow 的串行步骤
  • 从组件到链路:先验证单组件自愈(Pod 重启),再验证链路韧性(网络分区下的重试与降级),最后才做跨区域演练
  • 最小爆炸半径:优先 mode: one / fixed(1),用 labelSelectors 精确圈定目标 Pod 而非整个 Deployment;生产环境先跑 1% 流量再逐步放大
  • 预设终止条件:每个实验必须携带 durationdeadline,并设定自动熔断指标(如错误率 > 5% 立即停止)

一个完整实验的前中后步骤:

# 实验前(T-30min)
# 1. 检查变更窗口:确认无发布、无迁移任务在跑
# 2. 备份稳态基线:Prometheus 导出最近 24h 的 P99 延迟与错误率
# 3. 通知干系人,准备好停止开关(kill ChaosResource / 撤销 CRD)

# 实验中
# 4. 按预设顺序注入,每个阶段停留 2-3 个观察周期
# 5. 观察指标偏离,记录现象时间线与 SLO 违反情况

# 实验后
# 6. 等待 deadline 自动恢复,或手动删除 ChaosResource
# 7. 确认指标回归基线,输出实验报告并决定是否修复代码

8. 安全边界与演练隔离

  • 白名单机制:用 --set controllerManager.allowedNamespaces(Chaos Mesh)限定故障注入只允许在指定 Namespace 执行;Litmus 通过 RBAC 的 chaosServiceAccount 只授予目标应用的权限
  • 演练环境隔离:生产演练优先选择独立 Namespace、独立 Service 与独立的降级链路(如影子流量副本);数据面与应用面都连接到演练专用实例,避免误伤真实用户
  • 明确终止条件:除 CRD 自带的 duration 外,设置人工熔断开关——kubectl delete podchaos --all -n prod 应能在 30 秒内清空所有注入;演练前把该命令写进 runbook
  • 审计与回溯:Chaos Mesh Dashboard 的审计日志与 K8s Event 保留注入历史,出事故时可快速定位"谁在何时注入了什么故障"
  • 禁止注入清单:有真实备份任务的节点、承载 DB 主库的 Pod、未做演练审批的敏感系统,列入 Namespace/标签级禁止名单

熔断开关与演练审批

# 演练前把这三条命令写进 runbook,任何异常 30 秒内止损:
kubectl delete podchaos -A --all        # 立即删除所有 Pod 注入
kubectl delete networkchaos -A --all    # 立即删除所有网络注入
kubectl delete workflow -n prod --all   # 停止所有编排中的实验

# 演练审批单(git issue 模板)至少包含:
# 目标组件 / 注入类型与参数 / 计划窗口(避开发布与备份)
# 稳态基线(P99、错误率)/ 熔断指标(如错误率 > 5% 即停)
# 干系人通知列表 / 恢复验证人

审批不是形式主义——它强迫演练负责人提前回答「出了事怎么办」,这本身就是演练的一部分:如果熔断命令写不出来,说明这个实验还没准备好执行。

9. 指标验证与结果分析

混沌实验的价值在于可量化的对比。以"backend → database 网络延迟 +200ms"实验为例,注入前后采集同一组指标:

指标注入前基线注入期间恢复后结论
P99 延迟120ms380ms125ms未超 SLO 500ms,通过
错误率0.2%1.8%0.3%重试机制生效,未级联
可用 Pod 数666副本无驱逐,通过
数据库连接池占用40%92%45%接近上限,需调优连接池
# 用 PromQL 拉取注入前后对比(注入时间为 15:00-15:05)
# 延迟:avg by (pod) (rate(http_request_duration_seconds_sum[1m])) / 
#        avg by (pod) (rate(http_request_duration_seconds_count[1m]))
# 错误率:sum(rate(http_requests_total{status=~"5.."}[1m])) /
#         sum(rate(http_requests_total[1m]))

# 生成对比报告的关键字段:实验 ID、注入类型、目标、起止时间、
# 基线值、峰值、恢复时长、SLO 是否违反、遗留问题、修复建议

结果分析的原则:故障恢复不等于实验通过——若恢复依赖人工介入或超时时间过长,说明韧性假设不成立;把每次实验的"峰值 / 恢复时长 / 违反的 SLO"沉淀进韧性手册,作为下一次实验的基线。

实验报告与韧性指标沉淀

# 每次实验固定输出一份报告,字段固定,便于横向对比:
# 实验 ID / 日期 / 注入类型与参数 / 目标组件 / 起止时间
# 基线指标(P99、错误率、可用副本数)
# 峰值指标 / 恢复时长(注入结束 → 指标回归基线)
# SLO 是否违反 / 是否需人工介入 / 遗留问题 / 修复负责人与截止日期
韧性指标定义参考目标
恢复时长(MTTR)故障注入结束到指标回归基线的时间< 5 分钟(自动恢复)
自愈率无需人工介入即可恢复的实验占比> 90%
SLO 违反次数实验期间违反既定 SLO 的次数0(或记录为待修复项)
回归缺口恢复后指标未回到基线 ±10% 内的项0 项

季度性把这些指标汇总成「韧性趋势图」:恢复时长逐季缩短、自愈率逐季上升,说明混沌演练在真实地提升系统韧性——这是向管理层证明混沌工程价值的核心数据。

常见错误

  • Chaos Mesh Dashboard 无法访问:检查 port-forward 是否正常,确认 chaos-dashboard Pod 状态为 Running,查看 Pod 日志排查 TLS 证书或端口冲突问题。
  • 故障注入后 Pod 未被杀掉selector.labelSelectors 与目标 Pod 标签不匹配。用 kubectl get pods --show-labels 确认标签,注意 YAML 缩进导致的 YAML 解析错误。
  • NetworkChaos 不生效:集群网络插件不兼容(如某些 CNI 不支持 tc)。确认 Chaos Mesh 的 chaosDaemon.runtimesocketPath 与节点容器运行时一致。
  • 实验超时后状态未恢复:手动删除残留的 ChaosResource:kubectl get podchaos -A 检查并删除未结束的实验。
  • Litmus ChaosEngine 报错 " ChaosResult not found":ChaosEngine 所在命名空间需要与 Litmus 组件在同一集群,检查 RBAC 权限和 ServiceAccount 绑定。
  • Parallel 步骤 deadline 不一致导致对比失真:Parallel 内各子步骤的 duration / deadline 必须一致,否则先恢复的故障会掩盖叠加效应的观测。
  • 实验报告只记「通过/失败」:没有记录峰值、恢复时长与 SLO 对比的实验结果不可复用——后续实验缺少基线,无法判断韧性是否在改善。

最佳实践

  • 从小范围开始:首次实验使用 mode: one 只影响单个 Pod,确认恢复机制正常后再扩大爆炸半径。
  • 先在 staging 验证:所有混沌实验在预发布环境跑通后再应用到生产,避免未知风险。
  • 配合监控观察:实验前打开 Prometheus + Grafana 面板,实时观察延迟、错误率、CPU 等指标变化。
  • 设置合理超时:为每个实验配置 deadline,防止故障无限注入导致级联故障。
  • 记录实验结果:每次实验记录故障类型、影响范围、系统反应和修复时间,逐步完善韧性手册。
  • 固定报告模板:每次实验输出固定字段的报告并归档,季度汇总成韧性趋势(MTTR、自愈率、SLO 违反次数)。
  • 混沌演练纳入发布流程:重大架构变更(引入缓存、换数据库驱动)后 24-48 小时内补一次针对性混沌实验,验证新组件没有悄悄降低韧性。
  • 演练后 48 小时内复盘:实验结束后 48 小时内完成报告归档与问题指派——超过一周的复盘结论基本不会落地。

练习题

  1. 使用 Chaos Mesh 注入一个网络延迟实验,让 backend 服务到 database 的延迟增加 300ms,持续 5 分钟,观察服务的错误率变化。
  2. 编写一个 ChaosWorkflow:先执行 Pod 残杀(pod-kill),等待 30 秒后注入 CPU 压力(2 核),观察 Deployment 是否能自动恢复。
  3. 对比 Chaos Mesh 和 Litmus 的实验编排能力:在 Litmus 中创建一个等效于上述 Workflow 的 ChaosEngine,记录两者的配置差异。
  4. 用 ChaosWorkflow 的 Parallel + Suspend 编排一次「磁盘满 + 网络抖动」叠加实验,观察两个故障同时发生时系统的表现,并写一份带指标对比的报告。
  5. 连续三个月每月跑一次同一实验(Pod 随机杀死),汇总 MTTR 与自愈率的变化趋势,分析韧性是否改善。
  6. 设计并演练一次「节点断网」实验:封禁一台节点的外部流量 10 分钟,验证集群的 NotReady 处理与 Pod 驱逐逻辑。

学习检查点

学完本章后,请检验自己是否掌握以下内容:

检查项自测问题验证方法
概念理解能用自己的话解释混沌工程的核心原则和稳态假设尝试向他人讲解
命令操作能不查文档完成 Chaos Mesh/Litmus 安装和实验创建在终端实际执行
原理掌握能说出混沌实验的爆炸半径控制和观测原理画出流程图
故障排查能独立排查混沌实验无法执行或影响范围过大的问题模拟故障并修复
最佳实践能说明为什么混沌实验需要从 staging 环境开始对比不同方案

本章总结

混沌工程的核心方法论是主动而非被动——在受控环境中有意识地注入真实故障,验证系统的稳态假设是否成立。工具层面,Chaos Mesh 的 CRD 声明式与 Litmus 的 ChaosHub 各有所长,但真正的价值来自纪律:staging 先行、限制爆炸半径、设置 deadline、全程监控,并把每次实验沉淀为韧性手册,让故障恢复能力成为可验证的系统属性。

延伸阅读

↑ 回到顶部