AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

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:471154

评论

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

字节面试官:你没有高并发、性能调优经验,为什么录取你?

Java 高并发 性能调优

挑战 30 天学完 Python:Day9 条件语句

MegaQi

Python 挑战30天学完Python 三周年连更

热榜!Alibaba最新发布「10亿级并发系统设计文档」Git狂揽9000星

Java你猿哥

数据库 架构 分布式 架构设计 并发系统

清单推荐:常见的研发效能度量指标(科学管理版)

LigaAI

研发管理 技术管理 效能度量 研发效能度量 企业号 4 月 PK 榜

全量通过,华为云GaussDB首批完成信通院全密态数据库评测

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 4 月 PK 榜

华为云新一代iPaaS全域融合集成平台全新升级

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 4 月 PK 榜

火山引擎 DataLeap下Notebook系列文章一:技术选型之路

字节跳动数据平台

notebook 数据研发 企业号 4 月 PK 榜

女朋友要我讲解@Controller注解的原理,真是难为我了

Java你猿哥

Java spring Spring 配置解析

阅读完synchronized和ReentrantLock的源码后,竟发现其完全相似

Java你猿哥

并发编程 并发 synchronized SSM框架 ReentrantLock

带你一同认识和使用JPA框架进行开发你的应用服务

Java你猿哥

Java SSM框架 jpa Java工程师

火山引擎DataTester:让企业“无代码”也能用起来的A/B实验平台

字节跳动数据平台

AB testing实战 无代码 A/B 测试 企业号 4 月 PK 榜 企业增长

Scrum敏捷研发和项目管理

顿顿顿

Scrum 敏捷开发 敏捷开发流程 leangoo 敏捷开发管理工具

火山引擎云原生数据仓库ByteHouse技术白皮书V1.0 (Ⅲ)

字节跳动数据平台

数据仓库 云原生 白皮书 数据仓库服务 企业号 4 月 PK 榜

Java中线程的6种状态详解(NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED)

共饮一杯无

Java 线程 线程状态 三周年连更

面试了个985毕业的大佬,回答“性能调优”题时表情令我毕生难忘

Java 性能优化 性能调优

GitHub上线重量级分布式架构原理设计笔记,开源的东西看着就是爽

Java你猿哥

架构 分布式 分布式架构

【堡垒机小知识】堡垒机能记录操作时间、操作数据等等吗?

行云管家

网络安全 堡垒机

接口设计文档的12个注意点

Java 后端开发 接口设计

阅读完synchronized和ReentrantLock的源码后,我竟发现其完全相似

Java 源码 synchronized ReentrantLock

安装Zookeeper和Kafka集群

Java你猿哥

Java kafka zookeeper SSM框架 Java工程师

【架构与设计】常见微服务分层架构的区别和落地实践

京东科技开发者

架构 微服务 DDD 分层架构 企业号 4 月 PK 榜

Apifox 更新 | WebSocket 接口调试功能上线!

Apifox

程序员 开发工具 Apifox API 接口工具

从源码角度深入解析Callable接口

华为云开发者联盟

后端 开发 华为云 华为云开发者联盟 企业号 4 月 PK 榜

如何用scrum敏捷工具做迭代规划及迭代执行。

顿顿顿

Scrum Sprint 敏捷开发管理工具 敏捷工具 迭代规划

Kurator v0.3.0版本发布!助力企业实现多云异构管理

华为云开发者联盟

开源 后端 华为云 华为云开发者联盟 企业号 4 月 PK 榜

Gradio:快速构建你的webApp

AIWeker

Python 三周年连更 Gradio

4 月 22 日丨【云数据库技术沙龙】技术进化,让数据更智能

NineData

MySQL 数据库 程序员 开发者 Clickhouse

“淄”味当道,工赋十足

Openlab_cosmoplat

开源社区 双碳

Kubernetes集群调度增强之超容量扩容

京东科技开发者

Kubernetes k8s 集群 企业号 4 月 PK 榜 超容量扩容

从零学习SDK(7)如何打包SDK

MobTech袤博科技

Linux:管道命令与文本处理三剑客(grep、sed、awk)

会踢球的程序源

Java Linux

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