kubebuilder 中文文档由云原生社区主导翻译。任何问题可以在这儿提issue。issue模版可以参考这个

在集成测试中使用 envtest

controller-runtime 提供 envtest (godoc),这个包可以帮助你为你在 etcd 和 Kubernetes API server 中设置并启动的 controllers 实例来写集成测试,不需要 kubelet,controller-manager 或者其他组件。

可以根据以下通用流程在集成测试中使用 envtest

import sigs.k8s.io/controller-runtime/pkg/envtest

//指定 testEnv 配置
testEnv = &envtest.Environment{
	CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
}

//启动 testEnv
cfg, err = testEnv.Start()

//编写测试逻辑

//停止 testEnv
err = testEnv.Stop()

kubebuilder 为你提供了 testEnv 的设置和清除模版,在生成的 /controllers 目录下的 ginkgo 测试套件中。

测试运行中的 Logs 以 test-env 为前缀。

配置你的测试控制面

你可以在你的集成测试中使用环境变量和/或者标记位来指定 api-serveretcd 设置。

环境变量

变量名称类型使用时机
USE_EXISTING_CLUSTERboolean可以指向一个已存在 cluster 的控制面,而不用设置一个本地的控制面。
KUBEBUILDER_ASSETS目录路径将集成测试指向一个包含所有二进制文件(api-server,etcd 和 kubectl)的目录。
TEST_ASSET_KUBE_APISERVER, TEST_ASSET_ETCD, TEST_ASSET_KUBECTL分别代表 api-server,etcd,和 kubectl 二进制文件的路径KUBEBUILDER_ASSETS 相似,但是更细一点。指示集成测试使用非默认的二进制文件。这些环境变量也可以被用来确保特定的测试是在期望版本的二进制文件下运行的。
KUBEBUILDER_CONTROLPLANE_START_TIMEOUTKUBEBUILDER_CONTROLPLANE_STOP_TIMEOUTtime.ParseDuration 支持的持续时间的格式指定不同于测试控制面(分别)启动和停止的超时时间;任何超出设置的测试都会运行失败。
KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUTboolean设置为 true 可以将控制面的标准输出和标准错误贴合到 os.Stdout 和 os.Stderr 上。这种做法在调试测试失败时是非常有用的,因为输出包含控制面的输出。

标记位

下面是一个在你的集成测试中通过修改标记位来启动 API server 的例子,和 envtest.DefaultKubeAPIServerFlags 中的默认值相对比:

var _ = BeforeSuite(func(done Done) {
	Expect(os.Setenv("TEST_ASSET_KUBE_APISERVER", "../testbin/bin/kube-apiserver")).To(Succeed())
	Expect(os.Setenv("TEST_ASSET_ETCD", "../testbin/bin/etcd")).To(Succeed())
	Expect(os.Setenv("TEST_ASSET_KUBECTL", "../testbin/bin/kubectl")).To(Succeed())

	logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
	testenv = &envtest.Environment{}

	_, err := testenv.Start()
	Expect(err).NotTo(HaveOccurred())

	close(done)
}, 60)

var _ = AfterSuite(func() {
	Expect(testenv.Stop()).To(Succeed())

	Expect(os.Unsetenv("TEST_ASSET_KUBE_APISERVER")).To(Succeed())
	Expect(os.Unsetenv("TEST_ASSET_ETCD")).To(Succeed())
	Expect(os.Unsetenv("TEST_ASSET_KUBECTL")).To(Succeed())

})
customApiServerFlags := []string{
	"--secure-port=6884",
	"--admission-control=MutatingAdmissionWebhook",
}

apiServerFlags := append([]string(nil), envtest.DefaultKubeAPIServerFlags...)
apiServerFlags = append(apiServerFlags, customApiServerFlags...)

testEnv = &envtest.Environment{
	CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
	KubeAPIServerFlags: apiServerFlags,
}

测试注意事项

除非你在使用一个已存在的 cluster,否则需要记住在测试内容中没有内置的 controllers 在运行。在某些方面,测试控制面会表现的和“真实” clusters 有点不一样,这可能会对你如何写测试有些影响。一个很常见的例子就是垃圾回收;因为没有 controllers 来监控内置的资源,对象是不会被删除的,即使设置了 OwnerReference

为了测试删除生命周期是否工作正常,要测试所有权而不是仅仅判断是否存在。比如:

expectedOwnerReference := v1.OwnerReference{
	Kind:       "MyCoolCustomResource",
	APIVersion: "my.api.example.com/v1beta1",
	UID:        "d9607e19-f88f-11e6-a518-42010a800195",
	Name:       "userSpecifiedResourceName",
}
Expect(deployment.ObjectMeta.OwnerReferences).To(ContainElement(expectedOwnerReference))