混沌测试工具调研

1. Chaos Mesh

Chaos Mesh 是一个云原生混沌工程平台,可在 Kubernetes 环境中编排混沌,用户可以在开发测试以及生产环境中模拟现实世界中可能出现的各类异常,帮助用户发现系统潜在的问题。

Chaos Mesh 由 PingCAP 公司开源,起源 TiDB 的核心测试平台,发布初期即继承了大量 TiDB 已有的测试经验。同时,Chaos Mesh 主要为 Kubernetes 场景设计,可以快速部署在被测 Kubernetes 集群中,并且无需修改被测系统(SUT)的部署逻辑。Chaos Mesh 在 Kubernetes 中定义了大量 CRD ,用户可以通过创建/编辑/删除这些对象,实现故障的编排。

Chaos Mesh 主要包括以下三个组件:

  • Chaos Dashboard:可视化组件,用户可通过该界面对混沌实验进行操作和观测。同时,Chaos Dashboard 还提供了 RBAC 权限管理机制。
  • Chaos Controller Manager:Chaos Mesh 的核心逻辑组件,主要负责混沌实验的调度与管理。该组件包含多个 CRD Controller,例如 Workflow Controller、Scheduler Controller 以及各类故障类型的 Controller。
  • Chaos Daemon:Chaos Mesh 的主要执行组件。Chaos Daemon 以 DaemonSet 的方式运行,默认拥有 Privileged 权限(可以关闭)。该组件主要通过侵入目标 Pod Namespace 的方式干扰具体的网络设备、文件系统、内核等。

2. Quick Start

1. 基于 Helm 部署

Chaos Mesh 官方提供了 Helm 包用于在 Kubernetes 上快速安装:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
helm repo add chaos-mesh https://charts.chaos-mesh.org
helm upgrade --install chaos-mesh chaos-mesh/chaos-mesh --create-namespace \
--namespace=chaos-testing \
--set images.registry="registry.lqingcloud.cn" \
--set controllerManager.podChaos.pauseImage="registry.lqingcloud.cn/chaos-mesh/pause:latest" \
--set controllerManager.enableFilterNamespace=false \ # 基于命名空间注入故障
--set chaosDaemon.runtime=docker \ # 根据 Kubernetes 环境使用的 CRI 类型配置,包括:docker、containerd、crio
--set chaosDaemon.socketPath=/var/run/docker.sock \
--set dashboard.persistentVolume.enabled=true \
--set dashboard.persistentVolume.storageClassName=local \
--set dashboard.securityMode=false \
--set dnsServer.create=true \
--set dnsServer.image="registry.lqingcloud.cn/chaos-mesh/coredns:v0.2.1"

Chaos Mesh 官方提供了明确的版本计划:每个版本的支持期限为六个月,每三个月发布一个新版本,当前 Chaos Mesh 和 Kubernetes 的兼容关系可以参考官网。

2. 注入故障

Chaos Mesh 相比于其他 Chaos 工具最大的特点就是基于自定义 CRD 来描述故障。对于 Chaos Mesh 中的已有故障,用户可以统一通过的 Yaml 文件描述,以下示例定义了 NetworkChaos 类型的故障,它使带有指定标签的 Pod 产生 10ms 的网络时延。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
  name: network-delay          # 故障名称
spec:
  action: delay                # 故障内容,delay 表示网络时延
  mode: one                    # 表示符合筛选条件的其中一个 Pod 
  selector:                    # 筛选指定 Pod
    namespaces:
      - default
    labelSelectors:
      app: centos-ping
  delay:
    latency: '10ms'            # 时延 10ms
  duration: '1h'               # 持续时间

3. 故障类型

Chaos Mesh 支持在 Kubernetes Pod 和物理机中注入不同类型的故障。

1. Kubernetes Pod

Kubernetes Pod 可以注入以下类型故障:

  • PodChaos 模拟指定 Pod 或者容器发生故障的情景,包括以下几种情景:

    • Pod Failure:向指定的 Pod 中注入故障,使得该 Pod 在一段时间内处于不可用的状态(官方文档中提到注入该类型的故障是通过替换镜像实现的)。
    • Pod Kill:杀死指定的 Pod 。为了保证 Pod 能够成功重启,需要配置 ReplicaSet 或者类似的机制。
    • Container Kill:杀死位于目标 Pod 中的指定容器。
  • NetworkChaos 模拟集群中网络故障的场景,包括以下几种情景:

    • Partition:网络断开、分区。
    • Net Emulation:用于模拟网络状态不良的情况,比如高延迟、高丢包率、包乱序等情况(依赖 linux 内核拥有 NET_SCH_NETEM 模块,Centos 需要额外安装 kernel-modules-extra )。
    • Bandwidth:用于限制节点之间通信的带宽。
  • IOChaos 模拟文件系统发生故障的情景,包括以下几种情景:

    • latency:为文件系统调用加入延迟
    • fault:使文件系统调用返回错误
    • attrOverride:修改文件属性
    • mistake:使文件读到或写入错误的值
  • DNSChaos 用于模拟错误的 DNS 响应,例如在收到 DNS 请求时返回错误,或者返回随机的 IP

    • random:DNS 服务返回随机的 IP 地址
    • error:DNS 服务返回错误
  • TimeChaos 用于模拟时间偏移的场景。需要注意:TimeChaos 只影响容器中 PID 命名空间的 PID 1 进程,以及 PID 1 的子进程。例如,通过kubectl exec 启动的进程不会被影响。

  • KernelChaos 通过使用 BPF 在指定内核路径上注入基于 I/O 或内存的故障。尽管 KernelChaos 的注入对象可以设置成一个或几个 Pod,但所属主机的其他 Pod 的性能也会受到一些影响,因为所有的 Pod 共享同一个内核。开启 KernelChaos 需要进行以下准备:

    • 内核故障要求 Linux 内核版本 >= 4.18
    • 启动内核配置项 CONFIG_BPF_KPROBE_OVERRIDE
    • 安装时将 bpfki.create 选项开启
  • HTTPChaos 模拟 HTTP 服务端在请求或响应过程中发生故障的场景,其底层调用 chaos-tproxy 服务基于 iptables-extension 实现请求的拦截,当前不支持 HTTPS。HTTPChaos 支持以下场景:

    • abort:中断服务端的连接
    • delay:为目标过程注入延迟
    • replace:替换请求报文或者响应报文的部分内容
    • patch:给请求报文或响应报文添加额外内容
  • JVMChaos 通过 Byteman 模拟 JVM 应用故障,主要支持以下类型的故障:

    • 抛出自定义异常
    • 触发垃圾回收
    • 增加方法延迟
    • 指定方法返回值
    • 设置 Byteman 配置文件触发故障
    • 增加 JVM 压力

2. 物理机

Chaosd 是 Chaos Mesh 提供的一款混沌工程测试工具(需要单独下载和部署),用于在物理机环境上注入故障,并提供故障恢复功能。

Chaosd 具有以下核心优势:

  • 易用性强:输入简单的 Chaosd 命令即可创建混沌实验,并对实验进行管理。
  • 故障类型丰富:在物理机的不同层次、不同类型上都提供了故障注入的功能,包括进程、网络、压力、磁盘、主机等,且更多的功能在不断扩展中。
  • 支持多种模式:Chaosd 既可作为命令行工具使用,也可以作为服务使用,满足不同场景的使用需求。

可以使用 Chaosd 模拟一下故障类型:

  • 进程:对进程进行故障注入,需要注意当使用 Systemd 管理进程时,Systemd 可能会在进程退出后自动恢复服务。
    • kill:向指定进程发送 SIGKILLSIGTERMSIGSTOP 信号
    • stop:向指定进程发送 SIGSTOP 信号
  • 网络:对物理机的网络进行故障注入,支持增加网络延迟、丢包、损坏包等操作。注入故障的场景和容器类似,但是支持指定设备等更丰富的定制。
  • 压力:对物理机的 CPU 或内存注入压力。
    • cpu
    • mem
  • 磁盘:对物理机的磁盘进行故障注入,支持增加读写磁盘负载、填充磁盘等操作。
  • 主机:对物理机本身进行故障注入,支持关机等操作。
    • shutdown:模拟主机 shutdown 关机流程
  • JVM:通过 Byteman 模拟 JVM 应用故障。
  • 时间:模拟时间偏移的场景。
  • 文件: Chaosd 模拟文件故障场景,包括新增文件、写文件、删除文件、修改文件权限、重命名文件、替换文件数据等。

1. PhysicalMachine 对象

通过 Chaoctl 用户可以通过 Chaosctl 将任意物理机注册为 Kubernetes 集群中的 PhysicalMachine 对象,无论该节点是否是 Kubernetes 集群中的节点。

用户可以在测试节点上运行 Chaosd Server 服务,Chaos Mesh 和各个节点的 Chaosd Server 服务通过 HTTP/HTTPS 通信,并且根据用户设置的 PhysicalMachineChaos 对象向指定节点注入对应类型的故障 。

官方建议 Chaos Mesh 和 Chaosd Server 之间应该基于 HTTPS 通信,用户可以使用 chaosctl 生成 Chaosd 证书:

1
2
3
4
mkdir -p /etc/chaosd/pki
kubectl get secret chaos-mesh-chaosd-client-certs -n chaos-testing -o "jsonpath={.data['ca\.crt']}" | base64 -d > /etc/chaosd/pki/ca.crt
kubectl get secret chaos-mesh-chaosd-client-certs -n chaos-testing -o "jsonpath={.data['ca\.key']}" | base64 -d>  /etc/chaosd/pki/ca.key
chaosctl pm generate --cacert=/etc/chaosd/pki/ca.crt --cakey=/etc/chaosd/pki/ca.key

以下命令启动 Chaosd Server 服务:

1
2
3
4
# 部署 HTTPS 服务
chaosd server --https-port 31768 --CA=/etc/chaosd/pki/ca.crt --cert=/etc/chaosd/pki/chaosd.crt --key=/etc/chaosd/pki/chaosd.key
# 部署 HTTP 服务
chaosd server --port 31767

创建基于 HTTP 访问的 PhysicalMachine 对象:

1
2
3
4
5
6
7
8
9
apiVersion: chaos-mesh.org/v1alpha1
kind: PhysicalMachine
metadata:
  name: dd89433a-aa8a-55d4-a8ce-6ad3176ad36f
  namespace: chaos-testing
  labels:
    arch: amd64
spec:
  address: http://172.28.112.85:31767

2. 注入物理机故障

ChaosMesh 允许通过以下三种方式注入物理机故障:

  • 通过 chaosd 命令行工具在当前物理机注入故障
  • Server 模式运行 chaosd 服务,用户通过发送 HTTP 请求注入故障
  • 通过在 Kubernetes 上定义 PhysicalMachineChaos 对象向指定节点注入故障

4. 故障编排

1. 定义故障范围

Chaos Mesh 中用户可以通过在 Chaos 对象中设置 Selectors 来限制故障发生的范围,目前支持以下几种类型的 Selector:

  • Label Selector:指定实验目标 Pod 需要带有的 Labels
  • Expression Selector:指定一组自定义的 Labels 规则来限定实验目标 Pod 。
  • Annotation Selector:同 Label Selector,但针对是 Pod 的 Annotation 属性 。
  • Field Selector:指定实验目标 Pod 的 Fields,如直接指定 Pod 的 name 或者 nodeIP。
  • PodPhase Selector:指定实验目标 Pod 的 Phase,支持的 Phase 包括 Pending、Running、Succeeded、Failed、Unknown
  • Node Selector:根据 Pod 运行节点的 Node 对象的 Label 限制故障注入范围
  • Node List Selector:指定实验目标 Pod 所属的 Node
  • Pod List Selector:指定实验目标 Pod 命名空间和 Pod 列表,即按命名空间和 Pod 名称过滤
  • Namespace Selectors:指定实验目标发生的命名空间。
  • Physical Machine List Selector:基于导入的 PhysicalMachine 名称过滤

Chaos Mesh 支持命名空间保护功能。保护功能基于"白名单"机制,用户需要在允许注入故障的 Namespace 中添加以下注解:

1
kubectl annotate ns default chaos-mesh.org/inject=enabled

当上述 Selector 筛选的 Pod 运行的 Namespace 并未被授权注入故障时,那么故障注入会失败。

命名空间保护机制默认是关闭的,通过以下配置打开:

1
helm install chaos-mesh chaos-mesh/chaos-mesh -n chaos-testing --set controllerManager.enableFilterNamespace=true

2. Chaos Mesh 任务流

混沌测试中不会只注入一种单一故障,Chaos Mesh 支持用户自定义 Workflow 对象来编排多个异常或者自定义任务。

Workflow 类型的内容比较简单,如下:

1
2
3
4
5
6
7
apiVersion: chaos-mesh.org/v1alpha1
kind: Workflow
metadata:
  name: workflow-name                # Workflow 名称
spec:
  entry: entry-name                  # 入口名称
  templates: []                      # templates 定义了一个列表用于描述,任务流的各个步骤

templates 列表的每个对象,表示任务流中的一个节点。这些节点包括以下几种类型:

  • EmbedChaos:EmbedChaos 节点,表示在指定范围注入某种故障。

  • Task:Task 节点表示自定义任务。Task 支持完整的 corev1.Container 定义,用户可以定义容器镜像、启动命令、挂载 Volume、使用探针、工作目录等内容,ChaosMesh 会根据用户定义创建一个单容器的 Pod 。Task 容器结束时,可以通过定义 ConditionalBranch 决定是否继续执行其他流程。

  • 逻辑节点:

    • Serial:串行运行 children 列表中指定的其他 template
    • Parallel:并行运行 children 列表中指定的其他 template
    • Suspend:暂停 Workflow 指定时间
    • Schedule:注入定时调度故障,定时调度故障也可以单独通过定义 Schedule 对象生成(参考
  • StatusCheck:基于 HTTP 请求的返回值,根据请求返回码,确定是否终止或者继续 Taskflow。

Task 不支持 Pod 相关定义,因此我们无法选择 Pod 运行的 Node 或者指定网络命名空间。

FAQ

  • 使用 Docker 作为 Kubernetes 的 CRI 时,chaos-daemon 使用的 Docker Client 版本为 1.40,当物理机上安装的 Docker 版本太低时会出现故障注入失败的问题。此时通过 --set chaosDaemon.env.DOCKER_API_VERSION="1.40" 在安装 helm 时进行设置 chaos-daemon 使用的 Docker API 版本。

  • 配置 controllerManager.enableFilterNamespace=true 时,需要重启 chaos-mesh 相关容器使配置生效。

参考