一篇帶你kubebuilder 進(jìn)階: 測(cè)試
Operator 的測(cè)試是一個(gè)比較頭疼的問題,在 kubernetes 資源是在不斷變化的,并且想要在測(cè)試的時(shí)候跑一整套的 kubernetes 環(huán)境也不是一件容易的事情,今天我們大概看一下單元測(cè)試和集成測(cè)試怎么做。
單元測(cè)試
單元測(cè)試和 golang 的單元測(cè)試沒有什么太大的區(qū)別,一般可以通過單元測(cè)試搞定的首先使用單元測(cè)試,因?yàn)閱卧獪y(cè)試寫起來最容易,例如下面這一段對(duì)節(jié)點(diǎn)標(biāo)簽更新邏輯進(jìn)行測(cè)試
- func TestNodePoolSpec_ApplyNode(t *testing.T) {
 - type fields struct {
 - Taints []corev1.Taint
 - Labels map[string]string
 - Handler string
 - }
 - type args struct {
 - node v1.Node
 - }
 - tests := []struct {
 - name string
 - fields fields
 - args args
 - want *corev1.Node
 - }{
 - {
 - name: "label",
 - fields: fields{
 - Labels: map[string]string{
 - "node-pool.lailin.xyz/test": "",
 - },
 - },
 - args: args{
 - node: v1.Node{
 - ObjectMeta: metav1.ObjectMeta{
 - Name: "worker",
 - Labels: map[string]string{
 - "kubernetes.io/arch": "amd64",
 - "a": "b",
 - },
 - },
 - },
 - },
 - want: &v1.Node{
 - ObjectMeta: metav1.ObjectMeta{
 - Name: "worker",
 - Labels: map[string]string{
 - "kubernetes.io/arch": "amd64",
 - "node-pool.lailin.xyz/test": "",
 - },
 - },
 - },
 - },
 - }
 - for _, tt := range tests {
 - t.Run(tt.name, func(t *testing.T) {
 - s := &NodePoolSpec{
 - Taints: tt.fields.Taints,
 - Labels: tt.fields.Labels,
 - Handler: tt.fields.Handler,
 - }
 - assert.Equal(t, tt.want, s.ApplyNode(tt.args.node))
 - })
 - }
 - }
 
集成測(cè)試
controller-runtime 提供 envtest ,這個(gè)包可以幫助你為你在 etcd 和 Kubernetes API server 中設(shè)置并啟動(dòng)的 controllers 實(shí)例來寫集成測(cè)試,不需要 kubelet,controller-manager 或者其他組件。
envtest
一個(gè) envtest 的簡(jiǎn)單例子如下
- import sigs.k8s.io/controller-runtime/pkg/envtest
 - //指定 testEnv 配置
 - testEnv = &envtest.Environment{
 - CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
 - }
 - //啟動(dòng) testEnv
 - cfg, err = testEnv.Start()
 - //編寫測(cè)試邏輯
 - //停止 testEnv
 - err = testEnv.Stop()
 
envtest 在啟動(dòng)的時(shí)候需要設(shè)置一些環(huán)境變量來說明我們使用什么控制平面來進(jìn)行測(cè)試
- USE_EXISTING_CLUSTER表示使用一個(gè)已經(jīng)存在的控制平面
 - KUBEBUILDER_ASSETS 本地控制平面二進(jìn)制文件的文件夾路徑,里面包含了 kubectl apiserver和 etcd
 - KUBEBUILDER_CONTROLPLANE_START_TIMEOUT控制平面啟動(dòng)的超時(shí)時(shí)間
 - KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT控制平面停止的超時(shí)時(shí)間
 
編寫測(cè)試
kubebuilder 在生成代碼的時(shí)候已經(jīng)幫我們生成好了相關(guān)的腳手架,已經(jīng)環(huán)境配置,我們只需要寫具體的測(cè)試邏輯就行了
下面我們就以創(chuàng)建一個(gè) NodePool 為例子看看集成測(cè)試怎么寫
- controllers/suite_test.go
 
- var _ = Describe("node labels", func() {
 - pool := &nodesv1.NodePool{
 - ObjectMeta: metav1.ObjectMeta{
 - Name: "test",
 - },
 - Spec: nodesv1.NodePoolSpec{
 - Labels: map[string]string{
 - "node-pool.lailin.xyz/xxx": "",
 - },
 - Handler: "",
 - },
 - }
 - It("create pool", func() {
 - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 - defer cancel()
 - err := k8sClient.Create(ctx, pool)
 - Expect(err).NotTo(HaveOccurred())
 - })
 - })
 
使用 make test 執(zhí)行測(cè)試
- Using cached envtest tools from blog-code/k8s-operator/07-node-pool-operator/testbin
 - setting up env vars
 - ? github.com/mohuishou/blog-code/k8s-operator/node-pool-operator [no test files]
 - ok github.com/mohuishou/blog-code/k8s-operator/node-pool-operator/api/v1 9.403s coverage: 24.5% of statements
 - ok github.com/mohuishou/blog-code/k8s-operator/node-pool-operator/controllers 10.390s coverage: 0.0% of statements
 
總結(jié)
今天這篇文章主要還是希望起一個(gè)拋磚引玉的作用,沒有過多的去深入具體改如何寫單元測(cè)試和集成測(cè)試,只是給了兩個(gè)例子,關(guān)于集成測(cè)試如果感興趣可以看看 https://onsi.github.io/ginkgo 和 envtest 的相關(guān)文檔。
對(duì)于 Operator 來說建議能寫單元測(cè)試的還是寫單元測(cè)試,能夠本地寫集成測(cè)試的就寫集成測(cè)試這樣我們?cè)趯?shí)際上線的時(shí)候就會(huì)減少 bug 的概率,因?yàn)橄鄬?duì)于業(yè)務(wù)代碼來說 Operator 的測(cè)試實(shí)在是比較麻煩,對(duì)于測(cè)試同學(xué)的要求也比較高,一不小心就有可能遺漏一些問題。
















 
 
 






 
 
 
 