k8s编程-crd operator-使用code generator创建代码

1,236 阅读2分钟

对于自定义资源,需要编写对应的 custom controller( 亦即 operator)来进行对应的资源控制。本文主要记录我的操作过程

详细的教程也可以参考官方教程: github.com/kubernetes/…

1. 下载code-generatorrepo

下载code-generatorrepo, 切换到对应的分支,分支选择建议与你的k8s版本匹配,我的版本是1.23.4,对应的code-generator版本为0.23.3

git clone https://github.com/kubernetes/code-generator
git checkout v0.23.3
或者
git checkout kubernetes-1.23.4

2. 编译项目, 生成对应的gen文件

报错:

go install code-generator/cmd/{client-gen,lister-gen,informer-gen,deepcopy-gen}

package code-generator/cmd/client-gen is not in GOROOT (/usr/local/Cellar/go/1.18.2/libexec/src/code-generator/cmd/client-gen)
package code-generator/cmd/lister-gen is not in GOROOT (/usr/local/Cellar/go/1.18.2/libexec/src/code-generator/cmd/lister-gen)
package code-generator/cmd/informer-gen is not in GOROOT (/usr/local/Cellar/go/1.18.2/libexec/src/code-generator/cmd/informer-gen)
package code-generator/cmd/deepcopy-gen is not in GOROOT (/usr/local/Cellar/go/1.18.2/libexec/src/code-generator/cmd/deepcopy-gen)

这一步也可以不执行,在后续调用generate-group.sh时自动安装

由于我的repo不在gopath下,替换为使用绝对路径

go install ./cmd/{client-gen,lister-gen,informer-gen,deepcopy-gen}

生成结束后,可以在$(go env GOPATH)/bin/目录下看到刚刚的编译成果物,例如我刚刚就编译生成了:

➜  bin ls -alht
total 711792
drwxr-xr-x  29 admin  staff   928B  5 14 17:23 .
-rwxr-xr-x   1 admin  staff   8.7M  5 14 17:23 client-gen
-rwxr-xr-x   1 admin  staff   8.5M  5 14 17:23 informer-gen
-rwxr-xr-x   1 admin  staff   8.4M  5 14 17:23 lister-gen
-rwxr-xr-x   1 admin  staff   8.1M  5 14 17:23 deepcopy-gen

上一个步骤中生成的bin文件一般不会直接调用,而是通过code-generator中的脚本generate-groups进行调用。 这个脚本的作用是用于生成crd所需的项目代码

3. 编写初始化文件

可以参考官方给的sample进行改写, kubernetes/sample-controller: Repository for sample controller. Complements sample-apiserver (github.com)

或者直接在Kubernetes仓库的如下目录中:vendor/k8s.io/sample-controllerstaging/src/k8s.io/sample-apiserver

4. 初始化步骤


├── pkg
│   └── apis
│       └── crd.example.com  // group
│           └── v1    // version
│               ├── doc.go
│               ├── register.go
│               └── types.go

目录层级为pkg/{group}/{version}/, 需要自己创建的文件为doc.go/redister.go/types.go 下载依赖: go get -d k8s.io/sample-controller

5. 改写文件

具体文件目录: sample-controller/pkg/apis/samplecontroller/v1alpha1 at master · kubernetes/sample-controller (github.com)

  • doc.go:
//+k8s:deepcopy-gen=package
//+groupName=crd.example.com
  • types.go: 直接copy

  • register: 拷贝后进行修改

    • 修正:SchemeGroupVersion 的Group和Version
 varSchemeGroupVersion=schema.GroupVersion{Group:"crd.example.com",Version:"v1"}
- addKnownTypes: Foo和FooList因为没有zz_generated.deepcopy.go文件,所以会存在告警,后续生成后就好了

6.生成deepcopy及其他文件

使用脚本生成文件

➜  code-generator git:(fb849a7) ✗ /Users/admin/work/k8s/demo/CRD/code-generator/code-generator/generate-groups.sh all  github.com/jijunhua/k8s-demo/operator-crd/pkg/generated  github.com/jijunhua/k8s-demo/operator-crd/pkg/apis crd.example.com:v1 --go-header-file=/Users/admin/work/k8s/demo/CRD/code-generator/code-generator/hack/boilerplate.go.txt

Generating deepcopy funcs
Generating clientset for crd.example.com:v1 at github.com/jijunhua/k8s-demo/operator-crd/generated/clientset
Generating listers for crd.example.com:v1 at github.com/jijunhua/k8s-demo/operator-crd/generated/listers
Generating informers for crd.example.com:v1 at github.com/jijunhua/k8s-demo/operator-crd/generated/informers

这个时候代码生成在 ${GOPATH}/github.com/jijunhua/k8s-demo/operator-crd/generated下

如果需要生成到指定目录,使用--output-base指定到你的src层级目录

生成完成后, 刚刚的Foo报错就没了

7. 写一个operator demo

package main

import (
	"context"
	"log"

	clientset "github.com/jijunhua/k8s-demo/operator-crd/pkg/generated/clientset/versioned"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/tools/clientcmd"
)

func main() {
	config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
	if err != nil {
		klog.Fatalln(err)
		return
	}
	client, err := clientset.NewForConfig(config)
	if err != nil {
		klog.Fatalln(err)
		return
	}
	list, err := client.CrdV1().Foos("default").List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		klog.Fatalln(err)
		return
	}
        
        for _, foo := range list.Items {
		klog.Infof("%+v", foo.Name)
	}
}

8. 注册foo crd + 运行

如果尚未注册过foo这个crd,会报错:

2022/05/15 14:53:21 the server could not find the requested resource (get foos.crd.example.com)

有关foo这个crd的定义,可以在sample-controller项目中找到。复制并修改对应的group 及version后,应用一下

# create a CustomResourceDefinition
kubectl create -f artifacts/examples/crd-status-subresource.yaml

# create a custom resource of type Foo
kubectl create -f artifacts/examples/example-foo.yaml

运行结果

I0515 16:44:48.170289   21692 main.go:34] example-foo

其他:

后续应该还有controller的编写,这里不详细描述。 controller及新项目的构建可以完成参考:github.com/kubernetes/… 进行修改实现。

code-generator中提供了一个更详细的参考实例,Kubernetes Deep Dive: Code Generation for CustomResources (redhat.com)