云原生混沌工程实战:基于Litmus的故障注入与弹性测试

微服务上云后的"黑天鹅":为什么需要混沌工程?

当微服务从开发环境迁移到生产 Kubernetes 集群后,我们往往依赖 Prometheus 告警和熔断降级来应对故障。但**"已知的未知"并不可怕,真正致命的是"未知的未知"**------比如某个依赖的 Redis 连接池耗尽后引发雪崩,或者网络抖动导致分布式事务超时。混沌工程的核心思想,正是主动制造故障,验证系统在真实异常下的弹性边界。

本文基于 Litmus(CNCF 沙箱项目)在 K8s 中实施混沌工程,覆盖从实验设计、自动化编排到可观测性闭环的全流程,并给出生产环境的最小爆炸半径策略。所有 YAML 和命令均可在 K8s 1.24+ 上直接运行。


1. Litmus 架构与工作流:从实验定义到结果报告

1.1 核心组件

Litmus 采用 Operator 模式,主要组件包括:

  • Chaos-Operator :监听自定义资源 ChaosExperimentChaosEngine,负责调度实验 Job。
  • Chaos-Exporter:将实验指标(如注入时长、目标 Pod 状态)暴露为 Prometheus metrics。
  • Litmus Portal(可选):Web UI,用于可视化管理实验和查看报告。

1.2 工作流

  1. 用户定义 ChaosExperiment(实验模板)和 ChaosEngine(实验实例,指定目标、参数)。
  2. Operator 根据 Engine 创建 Job,Job 在目标 Pod 的同一节点上运行 sidecar 或直接执行 chaos 二进制。
  3. 实验完成后,结果写入 ChaosResult 自定义资源,并可通过 Prometheus 采集。

关键点ChaosExperiment 是全局模板(ClusterScope),ChaosEngine 是命名空间级别的实例化,允许复用实验逻辑。

1.3 快速安装

bash 复制代码
# 使用 Helm 安装 Litmus
helm repo add litmuschaos https://litmuschaos.github.io/litmus-helm/
helm install chaos litmuschaos/litmus --namespace=litmus --create-namespace

# 验证组件
kubectl get pods -n litmus -l app.kubernetes.io/component=chaos-operator

2. 故障注入实验设计:四类典型故障

我们以一个订单服务(order-service,3 副本)为例,分别演示 Pod 删除、网络延迟、CPU 压力、HTTP 错误注入。

2.1 Pod 删除(模拟节点宕机或滚动更新失败)

原理 :Litmus 的 pod-delete 实验通过直接删除目标 Pod 并观察 Deployment 的 ReplicaSet 重建能力。

yaml 复制代码
# pod-delete-experiment.yaml
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
  name: order-pod-delete
  namespace: default
spec:
  appinfo:
    appns: default
    applabel: "app=order-service"
    appkind: deployment
  chaosServiceAccount: litmus-sa
  experiments:
    - name: pod-delete
      spec:
        components:
          env:
            # 设置删除比例,50% 的 Pod 会被删除
            - name: TOTAL_CHAOS_DURATION
              value: "30"          # 秒
            - name: CHAOS_INTERVAL
              value: "10"          # 每次删除间隔
            - name: FORCE
              value: "true"        # 强制删除 (等同于 kubectl delete --force)
            - name: RAMP_TIME
              value: "10"          # 实验前等待 10s 让监控数据稳定

注意事项

  • 如果 Pod 数量为 3,TOTAL_CHAOS_DURATION=30CHAOS_INTERVAL=10,则实验期间会删除 3 个 Pod(每个 10s 间隔)。

  • 生产环境必须设置 TARGET_PODS 指定最大删除数,避免无限制删除导致服务完全不可用。

错误写法(未限制范围):

yaml 复制代码
# 错误示范:没有 TARGET_PODS,可能导致全部 Pod 被删除
- name: TOTAL_CHAOS_DURATION
  value: "300"

正确做法

yaml 复制代码
- name: TARGET_PODS
  value: "1"   # 每次最多删除 1 个 Pod,保障最小副本数

2.2 网络延迟(模拟跨 AZ 或 Service Mesh 抖动)

使用 pod-network-latency 实验,在指定 Pod 的网卡上注入延迟。

yaml 复制代码
# network-latency.yaml
spec:
  experiments:
    - name: pod-network-latency
      spec:
        components:
          env:
            - name: NETWORK_LATENCY
              value: "2000"        # 延迟 2000ms
            - name: TARGET_CONTAINER
              value: "order-service"
            - name: NETWORK_INTERFACE
              value: "eth0"
            - name: TOTAL_CHAOS_DURATION
              value: "60"
            - name: JITTER
              value: "500"         # 抖动 500ms,模拟真实网络不稳定

效果验证:实验期间调用订单接口,P99 延迟从基线 35ms 飙升到 2.5s,之后恢复正常。若服务未配置超时重试,则会出现大量 5xx 错误。

2.3 CPU 压力(模拟突增计算任务或容器资源限制不足)

yaml 复制代码
# cpu-stress.yaml
spec:
  experiments:
    - name: pod-cpu-hog
      spec:
        components:
          env:
            - name: CPU_CORE
              value: "0.5"         # 占用 0.5 核
            - name: TOTAL_CHAOS_DURATION
              value: "120"
            - name: TARGET_CONTAINER
              value: "order-service"
            # 注意:若 Pod 的 resource.limits.cpu 为 1,注入 0.5 会占用 50% 分配

踩坑点

  • CPU_CORE 是绝对值,不是百分比。如果节点只有 2 核,设置 2 会导致整个节点 CPU 被打满,影响其他 Pod。

  • 生产环境建议使用 STRESSOR_ARGS 配合 --cpu 1 --timeout 60 更精细控制。

对比pod-cpu-hog vs pod-cpu-hog-exec(后者通过 exec 在容器内执行 stress 命令,无需额外镜像)。对于有 securityContext 限制的容器,优先使用 exec 模式。

2.4 HTTP 错误注入(模拟下游服务返回 500)

使用 pod-http-status 实验,拦截目标 Pod 的指定 HTTP 请求并返回自定义状态码。

yaml 复制代码
# http-error.yaml
spec:
  experiments:
    - name: pod-http-status
      spec:
        components:
          env:
            - name: TARGET_SERVICE_PORT
              value: "8080"
            - name: STATUS_CODE
              value: "500"
            - name: RESPONSE_HEADERS
              value: "Content-Type: application/json"
            - name: ROUTE
              value: "/api/orders"  # 只对 /api/orders 路径生效
            - name: TARGET_CONTAINER
              value: "order-service"

实现原理 :Litmus 使用 ebpfiptables (取决于内核版本)劫持流量,在应用层返回错误,无需修改代码。

关键注意事项ROUTE 必须与真实请求路径完全匹配,否则劫持失败。可搭配 TARGET_PODS 限制影响范围。


3. 实验编排与自动化:基于 GitOps 的混沌实验流水线

手动执行 ChaosEngine 无法在生产环境常态化。我们需要将混沌实验视为"基础设施即代码",通过 GitOps 工具(如 ArgoCD)自动同步,并集成 CI/CD 触发。

3.1 Git 仓库结构

复制代码
chaos-experiments/
├── engines/
│   ├── prod-pod-delete.yaml       # 生产环境,TARGET_PODS=1
│   ├── prod-network-latency.yaml
│   └── staging-all-experiments.yaml
├── experiments/                    # 复用 ChaosExperiment 模板
│   ├── pod-delete.yaml
│   └── network-latency.yaml
├── dashboards/                     # Grafana 面板 JSON
└── .argocd-app.yaml

3.2 ArgoCD 自动同步

yaml 复制代码
# .argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: chaos-experiments
spec:
  destination:
    namespace: litmus
    server: https://kubernetes.default.svc
  project: default
  source:
    path: chaos-experiments/engines
    repoURL: https://github.com/your-team/chaos-gitops.git
    targetRevision: main
  syncPolicy:
    automated: {}

改进点 :将 ChaosEngine 的 spec.schedule 字段设置为 Cron 语法,实现定期混沌实验(如每周三凌晨 3 点执行 15 分钟低风险实验)。但注意 Cron 模式只支持 Litmus 3.0+。

3.3 集成 CI 触发(仅对 staging 环境)

在 Jenkins/GitLab CI 中,可以通过 kubectl apply 临时创建 ChaosEngine,并等待 ChaosResult 状态:

bash 复制代码
# CI 脚本
kubectl apply -f chaos-engine-staging.yaml
# 等待实验完成(最多 5 分钟)
kubectl wait --for=condition=Complete chaosresult/order-pod-delete --timeout=300s
if [ $? -ne 0 ]; then
  echo "Chaos experiment failed! Failing build."
  exit 1
fi

4. 弹性验证与可观测性:结合 Prometheus/Grafana 分析 SLO 影响

实验本身没有价值,价值在于衡量故障对业务 SLO 的影响。我们需要同时采集 Litmus 指标和应用性能指标。

4.1 关键指标

指标来源 Prometheus Metric 含义
Litmus Exporter litmus_experiment_verdict 实验通过/失败
Istio/Envoy (若用 Service Mesh) istio_request_duration_milliseconds_bucket 请求延迟分布
K8s Metrics Server kube_pod_status_ready Pod 就绪数
Application Metrics http_requests_total 业务 QPS

4.2 自定义 Grafana 面板

分析逻辑

  1. 在面板上叠加 Litmus 实验时间窗口 (通过 litmus_experiment_start_timelitmus_experiment_end_time 计算)。

  2. 对比异常窗口前后的 P99 延迟、错误率、QPS。

示例 PromQL(计算实验期间的错误率变化):

promql 复制代码
# 错误率(5xx 占总请求比例)
sum(rate(http_requests_total{code=~"5.."}[1m])) / sum(rate(http_requests_total[1m]))

典型数据 (来自生产环境模拟):

| 实验类型 | 基线错误率 | 峰值错误率 | 恢复时间 | P99 延迟峰值 |

|---------|-----------|-----------|---------|------------|

| Pod 删除 | 0.01% | 0.5% | 20s | 120ms |

| 网络延迟 2s | 0.01% | 32% | 60s | 2500ms |

| CPU 压力 0.5核 | 0.01% | 1.2% | 90s | 800ms |

分析结论 :网络延迟实验暴露出下游服务的 重试风暴超时设置过短,导致大量 5xx。优化后将超时从 1s 改为 3s,并增加指数退避,再实验时峰值错误率降至 2.3%。


5. 生产环境最小爆炸半径策略

放任混沌实验随意运行是对生产的不负责。以下是必须遵守的策略:

5.1 实验范围限制

  • 命名空间过滤 :在 ChaosEngine 中通过 spec.appinfo.appns 指定单个命名空间,或使用 AUXILIARY_APPINFO 排除关键服务(如 etcd、kube-system)。
  • Pod 选择器黑名单 :添加环境变量 TARGET_PODS 限制最大数量,配合 PODS_AFFECTED_PERC(百分比)双重保险。
  • 时间窗口 :结合 SERVICEACCOUNT 的 RBAC,只允许在 01:00-04:00 创建 ChaosEngine(通过 OPA Gatekeeper 或 Kyverno)。

5.2 自动中止条件(Steady State Hypothesis)

Litmus 3.0 引入了 Probes 机制,可以在实验持续期间检查系统状态,一旦违反假设立即中止实验。

yaml 复制代码
# 在 ChaosEngine 中添加 probes
spec:
  experiments:
    - name: pod-network-latency
      probes:
        - name: error-rate-probe
          type: PromProbe
          mode: Continuous   # 持续检查
          runProperties:
            probeTimeout: 5s
            retry: 0
          promProbe/inputs:
            query: "sum(rate(http_requests_total{code=~\"5..\"}[1m])) / sum(rate(http_requests_total[1m])) > 0.05"
            comparator:
              type: float
              criteria: equals  # 如果错误率 >5% 则 fail
              value: "1"
          promProbe/data:
            # 需要提供 Prometheus 地址
            serverUrl: "http://prometheus-server.monitoring:9090"

工作原理 :当 Probe 返回 true(即错误率 >5%),Litmus 立即标记实验为 Failed,并执行 REMEDIATION_ACTION(默认终止实验并恢复)。

5.3 安全审计与回滚

  • 使用 Litmus Portal 的 审计日志 记录谁在何时执行了什么实验。
  • 所有 ChaosEngine 必须有对应的 rollback 策略:对于 Pod 删除这类无状态实验,Debployment 自动回滚;对于网络延迟,Litmus 会在实验结束后自动清除 iptables 规则。

总结

  • Litmus 的核心优势:声明式 API + 可编程探针,能嵌入 GitOps 和 CI/CD,实现"混沌即代码"。
  • 落地必须做的三件事
    1. 为每个实验配置 TARGET_PODSPODS_AFFECTED_PERC 双限制。
    2. 在 Prometheus 上建立 SLO 仪表盘,并配置 Probe 自动中止条件。
    3. 先从小范围(单副本、非核心服务)开始,稳定后再扩大至 2 副本和关键业务。
  • 常见踩坑 :网络延迟实验中 JITTER 值过大导致容器内进程卡死;CPU_CORE 超过节点容量引发节点 NotReady;ROUTE 路径不匹配导致劫持失效。

混沌工程不是破坏,而是用科学实验验证系统的韧性。当生产真的发生故障时,你会感谢这些提前暴露的"已知未知"。

相关推荐
探索云原生1 小时前
Kueue 如何管理 DRA 模式下的 GPU 配额
ai·云原生·kubernetes·kueue
Aray12343 小时前
论服务网格在云原生微服务项目中的设计与落地实践
微服务·云原生·架构
Zhao_yani4 小时前
k8s基础知识
云原生·容器·kubernetes
styshoo4 小时前
NVSentinel 数据流梳理
kubernetes·gpu·ai-infra·nvsentinel
运维大师5 小时前
【云原生与DevOps】07-Istio服务网格落地:从试点到全量的踩坑记录
云原生·istio·devops
zx78545 小时前
Kubernetes 生产级实战:从零部署 LNMP 架构 ECShop 商城(完整指南)
容器·架构·kubernetes
IT大白鼠6 小时前
K8S发展历史及未来展望
云原生·容器·kubernetes
运维大师6 小时前
【云原生与DevOps】08-多云容灾架构设计:跨Region自动切换实践
运维·云原生·devops
weixin_439930647 小时前
Kubernetes(K8s)入门实践
云原生·容器·kubernetes·k8s