为每一个人提供Kubernetes端到端测试

做者:Patrick Ohly(英特尔)linux

愈来愈多过去是Kubernetes组件的一部分,如今搬到在Kubernetes以外开发。例如,存储驱动程序曾经被编译成Kubernetes二进制文件,而后被转移到主机上的独立Flexvolume二进制文件中,如今做为容器存储接口(Container Storage Interface,CSI)驱动程序提供,这些驱动程序部署在Kubernetes集群内部的pod中。git

这对于处理此类组件的开发者来讲是一个挑战:如何在这样的外部组件上对Kubernetes集群进行端到端(E2E)测试?用于测试Kubernetes自己的E2E框架具备全部必要的功能。可是,尝试在Kubernetes以外使用它很困难,只有经过仔细选择大量依赖项的正确版本才能实现。在Kubernetes 1.13中,E2E测试变得更加简单。github

这篇博客文章总结了Kubernetes 1.13的变化。对于CSI驱动程序开发者,它将涵盖使存储测试可用于测试第三方CSI驱动程序。如何使用它们将基于两个Intel CSI驱动程序显示:json

测试这些驱动程序是大多数这些加强功能的主要动机。后端

E2E概述

E2E测试包括几个阶段:api

  • 实现测试套件。这是本篇博文的主要焦点。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框架经过每一个供应商包单独实现的接口访问它。ssh

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)。

鸣谢

特别感谢本文的审阅者:


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邀请你加入最终用户社区

相关文章
相关标签/搜索