共计 5653 个字符,预计需要花费 15 分钟才能阅读完成。
作者:Patrick Ohly(英特尔)
越来越多过去是 Kubernetes 组件的一部分,现在搬到在 Kubernetes 之外开发。例如,存储驱动程序曾经被编译成 Kubernetes 二进制文件,然后被转移到主机上的独立 Flexvolume 二进制文件中,现在作为容器存储接口(Container Storage Interface,CSI)驱动程序提供,这些驱动程序部署在 Kubernetes 集群内部的 pod 中。
这对于处理此类组件的开发者来说是一个挑战:如何在这样的外部组件上对 Kubernetes 集群进行端到端(E2E)测试?用于测试 Kubernetes 本身的 E2E 框架具有所有必要的功能。但是,尝试在 Kubernetes 之外使用它很困难,只有通过仔细选择大量依赖项的正确版本才能实现。在 Kubernetes 1.13 中,E2E 测试变得更加简单。
这篇博客文章总结了 Kubernetes 1.13 的变化。对于 CSI 驱动程序开发者,它将涵盖使存储测试可用于测试第三方 CSI 驱动程序。如何使用它们将基于两个 Intel CSI 驱动程序显示:
开放式基础架构经理(Open Infrastructure Manager,OIM)
PMEM-CSI
测试这些驱动程序是大多数这些增强功能的主要动机。
E2E 概述
E2E 测试包括几个阶段:
实现测试套件。这是本篇博文的主要焦点。Kubernetes E2E 框架是用 Go 编写的。它依赖于 Ginkgo 来管理测试,而断言(assertion)则依赖于 Gomega。这些工具支持“行为驱动开发”,它描述了“规范”中的预期行为。在这篇博客文章中,“test”用于引用个别 Ginkgo.It 规范。测试使用 client-go 与 Kubernetes 集群进行交互。
启动测试集群。像 kubetest 这样的工具可以帮忙。
针对该群集运行 E2E 测试套件。Ginkgo 测试套件可以使用 ginkgo 工具运行,也可以使用 go test 进行正常的 Go 测试。没有任何参数,Kubernetes E2E 测试套件将基于环境变量(如 KUBECONFIG)连接到默认集群,与 kubectl 完全相同。Kubetest 还知道如何运行 Kubernetes E2E 套件。
Kubernetes 1.13 中的 E2E 框架增强功能
所有以下增强都遵循相同的基本模式:它们使 E2E 框架在 Kubernetes 之外更有用和更容易使用,而不会改变原始 Kubernetes e2e.test 二进制文件的行为。
拆分供应商支持
使用 Kubernetes <= 1.12 的 E2E 框架很困难的主要原因是依赖于特定于提供者的 SDK,这些 SDK 使用了大量的软件包。只是编译它已经不简单。
许多这些软件包仅在某些测试中需要。例如,测试预配置卷的安装必须首先通过一些非 Kubernetes API,直接与特定存储后端通信,以管理员相同的方式配置这样的卷。
现在有尝试从核心 Kubernetes 中删除特定于云供应商的测试。在 PR#68483 中采用的方法可以看作是朝着这个目标迈出的一步:不是立即剥离代码并打破所有依赖它的测试,所有特定于云供应商的代码都被移动到 test/e2e/framework/providers 下的可选包中。然后,E2E 框架通过每个供应商包单独实现的接口访问它。
E2E 测试套件的作者决定将哪些软件包导入测试套件。然后通过 –provider 命令行标志激活供应商支持。1.13 和 1.14 中的 Kubernetes e2e.test 二进制文件仍然支持与 1.12 中相同的供应商程序。也可以不包含任何包,这意味着只有通用供应上程序可用:
“skeleton”:通过 Kubernetes API 访问集群,没有别的
“local”:跟“skeleton”差不多,但是另外 kubernetes/kubernetes/cluster 中的脚本可以在运行测试套件后通过 ssh 检索日志
外部文件
测试可能必须在运行时读取其他文件,例如.yaml 清单。但是 Kubernetes e2e.test 二进制文件应该是可用的并且完全独立,因为这简化了发布和运行它。Kubernetes 构建系统中的解决方案是使用 go-bindata 将 test/e2e/testing-manifests 下的所有文件链接到二进制文件中。E2E 框架过去对 go-bindata 的输出有很强的依赖性,现在 bindata 支持是可选的。通过 testfiles 包访问文件时,将从不同的源检索文件:
相对于使用 –repo-root 参数指定的目录
零个或多个 bindata 块
测试参数
e2e.test 二进制文件采用控制测试执行的附加参数。2016 年,开始尝试用 Viper 配置文件替换所有 E2E 命令行参数。但是这种努力停滞不前,这使得开发者没有明确指导他们应该如何处理特定于测试的参数。
v1.12 中的方法是将所有标志添加到中央 test/e2e/framework/test_context.go,这对于独立于框架开发的测试不行。自 PR#69105 以来,建议使用普通标志包在其自己的源代码中定义其参数。标记名称必须是分层的,点分隔不同的级别,例如 my.test.parameter,并且必须是唯一的。标志包强制执行唯一性,第二次注册标志时会发生混乱。新的配置包简化了多个选项的定义,这些选项存储在单个结构中。
总而言之,这就是现在如何处理参数:
测试包中的 init 代码定义了测试和参数。实际参数值尚不可用,因此测试定义不能使用它们。
测试套件的 init 代码解析参数和配置文件(可选)。
测试运行并可以使用参数值。
但是,最近有人指出,比较可取且有可能不将测试设置公开为命令行标志,只能通过配置文件设置它们。关于这个有一个开放的 bug 和一个待定的 PR。
Viper 支持得到了增强。与供应商支持一样,它是完全可选的。它通过导入 viperconfig 包被拉入 e2e.test 二进制文件,并在解析正常的命令行标志后调用它。这已经实现,以便当标志出现在 Viper 配置文件中时,也可以设置所有可以通过命令行标志设置的变量。例如,Kubernetes v1.13 e2e.test 二进制文件接受 –viper-config=/tmp/my-config.yaml,该文件将 my.test.parameter 设置为具有此内容的值:my: test: parameter: value
在较旧的 Kubernetes 版本中,该选项只能从当前目录加载文件,后缀必须省略,实际上只能通过这种方式设置几个参数。请注意 Viper 的一个限制仍然存在:它通过匹配已知标志的配置文件条目,而不会发出有关未知配置文件条目的警告,从而不会检测到错别字。Kubernetes 的更好的配置文件解析器仍在开发中。
从.yaml 创建项目清单
在 Kubernetes 1.12 中,有一些支持从.yaml 文件加载单个项目,但是然后创建该项目必须通过手写代码完成。现在,框架提供新方法加载具有多个项目的.yaml 文件、修补这些项目(例如,设置为当前测试创建的命名空间)以及创建它们。这目前用于为每个测试重新部署 CSI 驱动程序,这些驱动程序来自完全相同的.yaml 文件,这些文件也用于通过 kubectl 进行部署。如果 CSI 驱动程序支持以不同的名称运行,则测试完全独立并且可以并行运行。
但是,重新部署驱动程序会降低测试执行速度,并且不会涵盖针对驱动程序的并发操作。更现实的测试场景是在启动测试集群时部署驱动程序一次,然后针对该部署运行所有测试。最终,Kubernetes E2E 测试将转移到该模型,一旦更清楚如何扩展测试集群的启动,包括安装 CSI 驱动程序等其他实体。
Kubernetes 1.14 推出的增强功能
重用存储测试
能够使用 Kubernetes 之外的框架可以构建自定义测试套件。但是没有测试的测试套件仍然没用。一些现有的测试,特别是用于存储的测试,可以应用于树外组件。感谢 Masaki Kimura 所做的工作,Kubernetes 1.13 中的存储测试被定义为可以针对不同的驱动程序多次实例化它们。
但历史有重复的习惯。与供应商程序一样,定义这些测试的程序包也提取了所有树内存储后端的驱动程序定义,这反过来又拉取了比所需更多的附加程序包。这在 Kubernetes 1.14 进行了修复。
跳过不支持的测试
某些存储测试依赖于群集的功能(如在支持 XFS 的主机上运行)或驱动程序(如支持块卷)。在测试运行时检查这些条件,导致在不满意时跳过测试。好的是这记录解释了为什么测试没有运行。
开始测试很慢,特别是当它必须首先部署 CSI 驱动程序时,在其他情况下也差不多。在快速集群上测量为测试创建命名空间的时间为 5 秒,并且会产生大量噪声测试输出。本来可以解决这个问题,通过跳过不支持的测试的定义,然后报告为什么测试甚至不是测试套件的一部分变得棘手。这种方法已不被考虑,而是采用重新组织存储测试套件的方式,以便在进行更昂贵的测试设置步骤之前首先检查条件。
更易读的测试定义
同样的 PR 还将测试重写,接近传统的 Ginkgo 测试,测试用例及其局部变量在一个函数中。
测试外部驱动程序
构建自定义 E2E 测试套件仍然是相当多的工作。将在 Kubernetes 1.14 测试档案中分发的 e2e.test 二进制文件将能够测试已安装的存储驱动程序,而无需重建测试套件。有关详细说明,请参阅本自述文件。
E2E 测试套件 HOWTO
测试套件初始化
第一步是设置定义测试套件的必要样板代码。在 Kubernetes E2E 中,这是在 e2e.go 和 e2e_test.go 文件中完成的。它也可以在 e2e_test.go 文件中完成。Kubernetes 在 e2e_test.go 中导入所有各种供应商程序、树内测试、Viper 配置支持和 bindata 文件。e2e.go 控制实际执行,包括一些集群准备和指标收集。
一个更简单的起点是来自 PMEM-CSI 的 e2e_[test].go 文件。它不使用任何供应商程序,没有 Viper,没有 bindata,只导入存储测试。
与 PMEM-CSI 一样,OIM 会丢弃所有额外功能,但有点复杂,因为它将自定义集群启动直接集成到测试套件中,在这种情况下非常有用,因为一些额外的组件必须在主机端运行。通过直接在 E2E 二进制文件中运行它们,使用 dlv 进行交互式调试变得更加容易。
这两个 CSI 驱动程序都遵循 Kubernetes 示例,并使用 test/e2e 目录作为其测试套件,但也可以使用任何其他目录和其他文件名。
添加 E2E 存储测试
测试由导入测试套件的包定义。E2E 测试唯一特有的是,它们使用 framework.NewDefaultFramework 实例化一个 framework.Framework 指针(通常称为 f)。此变量在每个测试的 BeforeEach 中重新初始化,并在 AfterEach 中释放。它在运行时有一个 f.ClientSet 和 f.Namespace(并且只在运行时!),可以由测试使用。
PMEM-CSI 存储测试导 Kubernetes 存储测试套件,并为必须已安装在测试集群中的 PMEM-CSI 驱动程序设置一个供应测试实例。存储测试套件更改存储类以使用不同的文件系统类型运行测试。由于此要求,存储类是从.yaml 文件创建的。
解释框架中可用的所有各种实用方法超出了本博文的范围。阅读现有测试和框架的源代码是一个很好的入门方法。
提供代码
即使消除了许多不必要的依赖关系,提供 Kubernetes 代码仍然不是一件容易的事。k8s.io/kubernetes 并不意味着包含在其他项目中,也没有以 dep 等工具理解的方式定义其依赖关系。其他 k8s.io 包应包含在内,但不遵循语义版本控制或不标记任何版本(k8s.io/kube-openapi,k8s.io/utils)。
PMEM-CSI 使用 dep。它的 Gopkg.toml 文件是一个很好的起点。它启用了修剪(默认情况下未在 dep 中启用)并将某些项目锁定到与所使用的 Kubernetes 版本兼容的版本上。当 dep 没有选择兼容的版本时,检查 Kubernetes 的 Godeps.json 有助于确定哪个版本可能是正确的版本。
编译并运行测试套件
go test ./test/e2e -args -help 是测试测试套件编译的最快方法。
一旦编译完成并且已经设置了集群,go test -timeout=0 -v ./test/e2e -ginkgo.v 命令将运行所有测试。要并行运行测试,请使用 ginkgo -p ./test/e2e 命令。
如何参与
Kubernetes E2E 框架由测试 SIG 的 testing-commons 子项目所有。请参阅该页面以获取联系信息。
有各种任务,包括但不限于:
将 test/e2e/framework 移动到 staging 仓库并重组它以使其更加模块化(#74352)。
通过将更多代码移入 test/e2e/framework(#74353)来简化 e2e.go。
从 Kubernetes E2E 测试套件中删除特定于供应商程序的代码(#70194)。
鸣谢
特别感谢本文的审阅者:
Olev Kartau(https://github.com/okartau)
Mary Camp(https://github.com/MCamp859)
KubeCon + CloudNativeCon + Open Source Summit 大会日期:
会议日程通告日期:2019 年 4 月 10 日
会议活动举办日期:2019 年 6 月 24 至 26 日
KubeCon + CloudNativeCon + Open Source Summit 赞助方案 KubeCon + CloudNativeCon + Open Source Summit 多元化奖学金现正接受申请 KubeCon + CloudNativeCon 和 Open Source Summit 即将首次合体落地中国 KubeCon + CloudNativeCon + Open Source Summit 购票窗口,立即购票!CNCF 邀请你加入最终用户社区