写点什么

Kubernetes Operator 测试面面观

  • 2020-03-02
  • 本文字数:3549 字

    阅读完需:约 12 分钟

Kubernetes Operator 测试面面观

软件测试是一门工程技术,更是一门艺术。维护良好、质量过硬的测试用例不仅能大幅提高开发者的工作幸福感,也是企业对外提供优质软件服务的重要基础。在这篇文章中,才云工程师 gaocegege 将分享团队在 Kubernetes Operator 测试方案上的一些心得。


本文将介绍一些比较成熟的 Kubernetes Operator 测试方案与方法,分析目前对 Kubernetes Operator 进行测试的最佳实践。

单元测试

首先,让我们把镜头对准单元测试。单元测试又称模块测试,它是针对程序模块(软件设计的最小单位)进行正确性检验的测试工作,也被视为是软件质量的第一道保障。


Kubernetes 的做法


在 tf-operator 中,我们采取了跟 Kubernetes 内置的 controller 类似的测试方案(例子可见 job_controller_test.go)。


如下面的代码所示,我们通过 Fake KubeConfig 创建了 Fake Clienset 和 Informer。之后,我们利用 Indexer,将测试的数据注入到 Informer 的 Cache 中,同时把 Informer 的 Sync 状态置为 AlwaysReady。最后,我们用到了 Fake PodControl 和 ServiceControl,这一操作使得我们不会真正在 Kubernetes 中创建对象,而是只进行一个记录。



随后,我们将状态更新的函数也 Fake 掉,将其赋值到内存的一个对象中,以便在后续的测试中进行状态比对。通过手动调用 SyncTFJob,我们可以利用之前自己手动构造的 Cache 进行状态的 Sync。


最后,就是根据构造对象和实际更新后对象的比对,来判断 Operator 在 Sync 的过程中是否达到了期望状态。



这一方法利用了 Kubernetes 的一些机制,绕过了对 Kubernetes API Server 和其他组件的依赖,直接利用 Informer 针对 Operator 的代码逻辑进行测试,可以测试单次 Sync 过程中,Operator 的工作是否符合预期。


etcd-operator 的做法


etcd-operator 是问世最久的 Operator 之一,Operator 这一模式也是由 CoreOS 提出的,了解 etcd-operator 有助于我们以史为镜。


目前 etcd-operator 在实现中仍没有像主流的 Operator 一样,采用 Work Queue 的方式来避免阻塞问题,而是在 Informer 中直接进行处理,而它的处理逻辑则被统一写成了:



因此,在做单元测试时,这种方法相对容易些,可以直接构造 Event 对象来进行测试。


Kubebuilder-generated Operator 的做法


严格意义上,Kubebuilder 的测试有别于传统单元测试,它背后依赖的是 “sigs.k8s.io/controller-runtime/pkg/envtest”.Environment。


在运行时,它会启动一个真正的 API Server 和 etcd,随后把 CRD 注册到 Scheme 中并把 Operator 运行起来。但值得注意的是,它不会启动 Controller Manager,这也意味着来自 API Server 的关于 Kubernetes 资源的事件不会真正被处理。


相比其他测试方法,它有许多比较明显的不同。首先,它需要运行一个真正的 API Server 和 etcd 来做对象存储。这就意味着在测试时可以使用真正的 Clientset 对 API Server 进行各种请求。



其次,它会运行一个真正的 Operator,而不只是通过手动调用 Sync 过程的方式进行测试。如下方代码所示,inner 这一对象就是真正的 Operator 的逻辑,而这一函数对其进行了再次封装,利用一个没有缓冲的 Channel 对其进行了执行的控制。



根据 Golang 的内存模型,不带缓冲的 Channel 的接收操作 happens-before 相应 Channel 的发送操作完成。利用这一特性,在同一个测试用例中,测试的对象可以被多次 Sync,每次 Sync 的状态都可以被检查。如果需要检查其中的 reconcile.Result 的值,如 Requeue 等,也可以改动这部分的逻辑来扩展。


这样做的优势是可以在单个测试中多次 Sync,并且依赖真实的 API Server,直接简单地利用 Clientset 进行操作。而它的劣势也在于依赖真实的 API Server,由于有些 CI 系统对多进程支持不好,真正在持续集成环境下运行时会有各种各样的问题。

端到端测试

端到端测试是利用真实的外部组件,将系统当做黑盒,站在终端用户的角度进行的测试。这里的“真实的组件”指的是 Kubernetes 还有一些外部依赖。相比单元测试,端到端测试需要依赖一个真实的 Kubernetes 集群,同时由于其黑盒属性,我们就有了更多不同选型。


Kubernetes 的做法


首先介绍下 Kubernetes 自身 Controller 的 e2e 测试是如何做的。


Kubernetes 的端到端测试依赖一个关键的抽象,也就是 Framework。Framework 负责把需要的 Client 创建好,同时,它也会为测试创建一个 Namespace。


当前的测试用例会在这个 Namespace 下运行,因此它从设计上就避免了并行测试可能引起的冲突,是一个非常有价值的特性。这也使得 Kubernetes 的测试用例可以并行地运行。


其实 Kubernetes 的端到端测试有许多值得学习的地方,包括其整体的原则、哲学、设计和实现。限于篇幅原因,这里不过多介绍。


Operator-SDK generated Operator 的做法


Operator-SDK 的做法和 etcd-operator 的做法类似,和 Kubernetes 的做法也有异曲同工之妙,相当于是基于 Kubernetes 社区的实现做了一个新的抽象和改写。


首先它需要设置 Main Entry:



这一函数会根据传入的 Kubeconfig、ProjectRoot 等参数,创建出 CRD 和 Operator。Operator 可以运行在集群外,也可以以 Pod 的方式运行在集群内。


随后,集群就可以进行测试了。我们可以完全把它当做黑盒,把 Clientset 当做 kubectl,将端到端的黑盒测试自动化。不过这里值得一提的是,这一方式不能通过 go test 直接进行测试。因为在 MainEntry 中,它会依赖一些参数,而这些参数会涉及一些预处理的逻辑。


举个例子,Operator-SDK 会把 Operator 所有的 YAML 文件合并成一个 YAML,然后再把这一临时的 YAML 文件的路径作为参数传递给后续的命令。


因此 Operator-SDK 是利用 operator-sdk test local 这一命令先进行预处理,然后再把处理好的参数传递给 go test 命令的。这一方式对用户并不是那么友好,必须依赖 operator-sdk 才能发起测试。但它默认支持一个用例一个 Namespace,与 Kubernetes 测试时的行为类似。


Kubebuilder-generated Operator 的做法


由于 Kubebuilder 生成的测试原本就依赖一个真实的 API Server 和 etcd,所以我们只要再创建出其他 Kubernetes 的组件就可以了。


但是,如果已经有正在运行的 Kubernetes 集群,那么我们就可以利用 UseExistingCluster,通过运行的集群进行测试。


相比前几种方式,这种方法可以真正检查所有资源的状态。而之前的方法只有 API Server 的运行中,是做不到对状态的检查的,因为事件不会被 Kubernetes Controller Manager 处理,因此状态更新无法进行。


tf-operator 的做法


因为端到端测试是黑盒测试,只要能够利用 Kubernetes 的 API 进行请求就可以完成,因此 tf-operator 的端到端测试是用 Python 实现的。


其实不只是端到端测试,tf-operator 的构建也不是用 Make 或者 Bazel 做的,而是用 Python 实现的,它们其实都是历史遗留问题。


不过这也证明了,只要能够解决集群部署、CRD 以及 Operator 的安装,用什么语言都可以做 Operator 的端到端测试。

总结

除了以上内容,Operator 的单元测试还存在多种不同的实现方案,本文只是基于才云内部实践,列举了几种较为主流且高效的方法。


对于单元测试,Kubernetes 和 tf-operator 的做法能够细粒度地构造测试用例,同时检查 Sync 的过程可否满足期望。


etcd-operator 的做法为单元测试提供了一种新思路,通过对 Operator 进行更高层次的抽象,针对高层次的抽象进行单元测试,我们可以避免手动利用 Indexer 构造测试场景。


kubebuilder 生成 Operator 实现的测试并不是传统意义上的单元测试。它利用了真实的 API Server,在测试时可以利用 Client 获取真实的资源。但由于没有 Controller 的支持,所以对于不少需要依赖一些 Kubernetes 自身资源状态来更新自己状态的 CRD 而言,没办法进行状态的检查。这一问题在前面的方法中不存在。


而对于端到端测试,我列举的所有方案基本都是利用 Client 来对已经创建好的集群进行端到端的黑盒测试,它们的区别主要在于运行集群的方式。


Kubernetes 和 Operator-SDK 的做法利用 Framework 这一抽象来部署集群环境。


而 Operator-SDK 由于需要部署 CRD 和 Operator,因此基于 Kubernetes 原本的理念做了一些修改,支持从本地或者利用 Deployment 的方式部署 Operator 以便测试。


kubebuilder 采用了类似单元测试的方法,利用 controller-runtime 提供的抽象和能力,在运行时注册 CRD,在测试代码中运行 Operator 的逻辑,依赖已经部署好的标准的 Kubernetes 集群进行端到端测试。但它在默认情况下,没有每个测试使用一个 Namespace 的支持,需要用户自行实现这样的逻辑。


不同的测试选型适合于不同的 Operator,在测试时,大家可以根据 Operator 的特点来确定具体的测试方案。目前来看,社区并没有一个 One for all 的方案。


本文转载自才云 Caicloud 公众号。


原文链接:https://mp.weixin.qq.com/s/_vCZucfzlsKIzElxKnCDcQ


2020-03-02 17:471121

评论

发布
暂无评论
发现更多内容

北冥多样性计算融合架构系列解读之 一文读懂华为昇思科学计算

Geek_32c4d0

华云大咖说 | 安超ArSDN云安全场景方案

华云数据

信创 华云数据 安超

深入剖析 Spring WebFlux

vivo互联网技术

spring WebFlux java

👊 【Spring技术实战】@Async机制的使用技巧以及异步注解源码解析

码界西柚

Java spring API 10月月更

北冥多样性计算融合架构系列解读之 一文读懂华为MindStudio统一工具链 多样性计算系统下的开发挑战

Geek_32c4d0

算力 多样性计算 北冥

CSS架构之Base层

Augus

CSS 10月月更

信息流推荐系统智能交付解决方案探索

百度Geek说

后端

一个神器,让写东西快得飞起

锋享前端

小工具

linux之vi,vim命令

入门小站

Linux

css3中的3D转换效果有哪些,浏览器私有前缀兼容写法

你好bk

html5 css3 大前端 html/css

当物联网遇上云原生:K8s向边缘计算渗透中

华为云开发者联盟

Kubernetes 云原生 物联网 边缘计算 kubeedge

政企融合商城,运营商打开B端市场利器

鲸品堂

运营商

Cobar提出的一种在分库场景下对Order By / Limit 的优化

捉虫大师

算法 cobar

StreamNative 宣布 2300 万美元 A 轮融资,Prosperity7 Ventures 与华泰创新联合领投

Apache Pulsar

融资 Apache Pulsar StreamNative

在线图片转base64工具

入门小站

工具

【Flutter 专题】31 图解 TextPainter 与 TextSpan 小尝试

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 10月月更

1688 商家基于 HarmonyOS 的多屏协同直播技术方案

阿里巴巴终端技术

ios android 客户端开发 HarmonyOS 直播技术

【Vuex 源码学习】第十一篇 - Vuex 插件的开发

Brave

源码 vuex 10月月更

看动画学算法之:栈stack

程序那些事

数据结构 算法 看动画学算法 程序那些事 stack

北冥多样性计算融合架构系列解读之 一文读懂华为多瑙统一调度器

Geek_32c4d0

uni-app技术分享| 用uni-app实现拖动的诀窍

anyRTC开发者

uni-app 音视频 WebRTC 移动开发 视频通话

5G NR 网络类型移动开发小记

阿里巴巴终端技术

ios android 5G 移动开发 移动网络

[ Golang 中的 DDD 实践] 仓储

baiyutang

golang 领域驱动设计 DDD 10月月更

[初恋系列]一个让初恋爱不释手的购物平台(电商系统微服务拆分)

人工智能~~~

微服务 电商平台 拆分 电商系统

【LeetCode】搜索旋转排序数组Java题解

Albert

算法 LeetCode 10月月更

新人融入团队的必备python技巧,python 编码规范,滚雪球学Python第4季12篇

梦想橡皮擦

10月月更

从一盏路灯,看亿万级物联网联接的智能之路

华为云开发者联盟

物联网 IoT 华为云 LiteOS NB- IoT

Vue进阶(幺叁贰):ES实现数组合并

No Silver Bullet

Vue 数组合并 10月月更

如何基于Jupyter notebook搭建Spark集群开发环境

华为云开发者联盟

spark Jupyter Notebook 集群 Spark集群 Sparkmagic

北冥多样性计算融合架构系列解读之 一文读懂北冥基础使能:毕昇C++编译器及北冥融合加速库

Geek_32c4d0

解决外卖配送最后一公里:外卖柜存在哪些问题

石头IT视角

Kubernetes Operator 测试面面观_文化 & 方法_才云科技_InfoQ精选文章