作者:叶飞
ChaosBlade
随着云原生的发展,云原生应用一致性、可靠性、灵活编排的能力让大部分企业选择将应用往云上迁移,但同时云基础设施在稳定性、可观测、也接受的强大的考验。
ChaosBlade 是阿里巴巴开源的一款遵循混沌工程原理和混沌实验模型的实验注入工具,帮助企业提升分布式系统的容错能力,并且在企业上云或往云原生系统迁移过程中业务连续性保障。
ChaosBlade Operator 是 kubernetes 平台实验场景的实现,将混沌实验通过 Kubernetes 标准的 CRD 方式定义,很方便的使用 Kubernetes 资源操作的方式来创建、更新、删除实验场景,包括使用 kubectl、client-go 等方式执行,同时也可以使用 chaosblade cli 工具执行。
本文将主要介绍 ChaosBlade 在 Kubernetes 中故障注入的底层实现原理、版本优化过程以及大规模应用演练测试。
资源模型
在 Kubernetes 中部署应用,通常我们会选择将应用定义为 Pod、Deployment、Statefulset 等资源类型,这些都是 Kubernetes 已经内置的;在实际应用中,面对对复杂的应用场景,内置的资源类型是无法满足我们需求的,Operator 是一种解决复杂应用容器化的一种方案,通过自定义资源和自定义控制器来实现复杂应用容器化,chaosblade-operator 正是就是基于 Operator 实现的。
在 Kubernetes 中安装完 chaosblade-operator 后,会生成一个 deployment 资源类型的 chaosblade-operator 实例、一个 daemonset 资源类型的 chaosblade-tool 实例、一个自定义资源定义,当然还包含 RABC、SA 等等其他资源;
chaosblade 将自定义资源类型定义为 chaosblade ,简称 blade ;每次新建演练就可以通过 kubectl 或者 chaosblade cli 创建 blade 实例资源,blade 资源本身也包含了 chaosblade 混沌实验定义;
chaosblade-operator 会监听 blade 资源的生命周期,当发现有 blade 资源实例被创建时,同时就能拿到混沌实验定义,然后解析实验定义,去调用 chaosblade-tool 真正的注入故障;
chaosblade-tool 是 daemonset 资源类型,一个 Node 节点必定会部署一个 Pod,从 Linux Namespace 的维度出发,该 Pod 网络、PID 命名空间与 Node 节点处在同一命名空间,因此可以做到部分 Node 级别的演练。
生命周期
在资源模型中,简单提到了 chaosblade-operator 会监听 blade 资源的创建;chaosblade-operator 实则会监听整个 blade 资源的生命周期,blade 资源的生命周期等同演练实验生命周期;chaosblade-operator 会根据 blade 资源状态去更新实验的状态
blade 资源状态 | 实验过程 | CPU 负载案例 |
---|---|---|
apply(新建) | 新建演练 | 新建 CPU 负载演练 |
running(运行中) | 演练运行中 | CPU 负载中 |
deleted(被删除) | 恢复演练 | 恢复演练 |
故障注入
在资源模型中提到了 chaosblade-operator 发现有 blade 资源实例被创建时,同时就能拿到混沌实验定义,然后解析实验定义,去真正的注入故障;那么 chaosblade-operator 是如去真正的注入故障呢?
其实在早期的 chaosblade-operator 版本中,大部分场景是通过将 chaosblade cli 工具通过 kubenetes API 通道复制到容器内部,然后再去容器内部执行命令来实现故障注入,整体实现方案入下图;
可以看到左边的 yaml 定义就是 Chaosblade 混沌实验模型定义,也是 blade 资源实例的一部分信息,当 blade 资源通过 kubectl apply 以后,chaosblade-operator 会监听到资源的创建,同时解析到实验定义;
当解析道 scope = node 的时候,会找到 node 节点所在 chaosblade-tool pod 中执行命令,这些动作几乎对整个集群来说资源消耗也是极少的;
但是当解析道 scope = pod 或者 scope = container 的时候,大部分场景 chaosblade-operator 会把 chaosblade cli 工具本身复制到业务容器内部,然后再去业务容器执行命令,工具包的大小、实验选择的容器数量、决定了资源的消耗大小,往往兼容性、版本更新等等都得不到很好的保障;
在新版本的 chaosblade-operator 版本中,将在下面最初的问题、优化过程、实现原理等小节详细介绍。
最初的痛点
当一个云原生应用达到一定规模时,去进行演练;
- 集群环境:1000 个 node 节点
- 目标应用:deployment 有 5000 个副本数
- 演练场景:对该应用对外提供的接口返回延迟 1000 毫秒
注入慢
首先需要找到 5000 个副本,将工具复制到容器,在进入容器执行命令,假设一个复制工具耗费 100 毫秒,那么整个过程耗费时间 500000 毫秒,这对用户来说简直是不可接受的。
网络带宽占用
将工具复制到容器,至少需要调用 kubernetes api 5000次,假设一个可执文件大小 5MB , 5000 次需要占用总带宽流量 5000x5=25000MB ,对 IO 影响简直就是灾难级别的;
兼容性问题
假设我们已经通过层层考验,已经工具将工具复制进去,当工具本身依赖了依赖一些命令,比如网络(tc)、磁盘(dd)等容器中又没有这些命令,或者版本不兼容改如何处理?
只读 Pod
对于配置了只读文件系统的 Pod,文件是不可写入的,因此压根就没发将工具复制进去
侵入型
将工具留在业务容器内部,等同于将工具生命周期与容器绑定在一起;
优化过程
在最初版本的迭代过程我们做过很多优化,同步转异步、包瘦身、按需复制等等优化方案,虽然一定程度上提高了注入的效率,但是没有解决问题的本质,还是受限于主机的 IO 性能;
无论是同步转异步、包瘦身、按需复制等优化方案,本质没法解决工具复制带来的一些问题;羊毛出在羊身上,解决问题就得解决问题的本质,从 Linux 虚拟化技术的角度思考,如何不复制工具就在能容器中注入故障呢?