本文记录用kubebuilder和code-generator开发k8s的crd控制器。
概览
和k8s.io/code-generator类似,是一个码生成工具,用于为你的CRD生成kubernetes-style API实现。区别在于:
Kubebuilder不会生成informers、listers、clientsets,而code-generator会。
Kubebuilder会生成Controller、Admission Webhooks,而code-generator不会。
Kubebuilder会生成manifests yaml,而code-generator不会。
Kubebuilder还带有一些其他便利性设施。
安装kubebuilder
https://github.com/kubernetes-sigs/kubebuilder/releases/tag/v3.13.0
在这里下载kubebuilder对应芯片版本:
本身作为一个二进制可执行文件,放入到/usr/local/bin目录下即可。
使用go mod
mkdir example
go mod init gateway
kubebuilder init --domain example.com
kubebuilder edit --multigroup=true
创建API
kubebuilder create api --group app --version v1 --kind Gateway
Create Resource [y/n]
y
Create Controller [y/n]
n
在example目录下创建了,api目录,制定了group和版本以及资源类型。
会自动生成apis/app/v1目录,里面有{crd}_types.go和zz_generated.deepcopy.go文件,如果需要配置和修改crd字段,可以修改{crd}_types.go中的crd spec结构体,见下图:
修改{crd}_types.go之后,需用重新执行make manifests重新生成crd,此时zz_generated.deepcopy.go也会同步更新。
生成RBAC manifests
在api/app/v1/目录创建rbac.go文件,加入以下内容:
// +kubebuilder:rbac:groups=app.example.com,resources=gateways,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=app.example.com,resources=gateways/status,verbs=get;update;patch
package v1
生成crd manifests
make manifests
这一步会生成config/crd/bases目录,以及该目录下的crd yaml
使用code-generator
先下载code-generator
go get -u -v k8s.io/code-generator/...
这里要下下载很多依赖包
在后面的编译过程中,需要手动下载一些依赖包到$GOPATH下
同时需要升级go到1.21版本,已解决如下问题:
准备脚本
在hack目录下新增update-codegen.sh和verify-codegen.sh
其中update-codegen.sh如下
其中:
MODULE=gateway,这里和go.mod保持一致(go mod init gateway)
API_PKG=api,目前工程的api目录,有的可能是api
OUTPUT_PKG=generated/app:输出结果的目录(generated/{group},group是之前kubebuilder create api是指定的group参数)
GROUP_VERSION=app:v1,也是跟kubebuilder create api是的group和version保持一致
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
# corresponding to go mod init <module>
MODULE=gateway
# api package
APIS_PKG=api
# generated output package
OUTPUT_PKG=generated/app
# group-version such as foo:v1alpha1
GROUP_VERSION=app:v1
SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
CODEGEN_PKG=${
CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 /Users/luoyi/go/src/k8s.io/code-generator 2>/dev/null || echo /Users/luoyi/go/src/k8s.io/code-generator)}
# generate the code with:
# --output-base because this script should also be able to run inside the vendor dir of
# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir
# instead of the $GOPATH directly. For normal projects this can be dropped.
bash "${CODEGEN_PKG}"/generate-groups.sh "client,lister,informer" \
${
MODULE}/${
OUTPUT_PKG} ${
MODULE}/${
APIS_PKG} \
${
GROUP_VERSION} \
--go-header-file "${SCRIPT_ROOT}"/hack/boilerplate.go.txt \
--output-base "${SCRIPT_ROOT}"
# --output-base "${SCRIPT_ROOT}/../../.." \
这个脚本主要就是制定了一些模块名和运行脚本的参数。本质上与进入到$GOPATH/src/k8s.io,执行如下命令一样:
./generate-groups.sh all /Users/luoyi/k8s/example/generated/app /Users/luoyi/k8s/example/api app:v1
其中,/Users/luoyi/k8s/example/generated/app指定了生成代码的路径,/Users/luoyi/k8s/example/api指定了作用路径,最后一个参数指定了group和版本。all表示client、informer和listener都生成。
在生成代码前还需要做些配置:
在{crd}_type.go上配置tag // +genclient,用于生成clienset
// +genclient
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// Gateway is the Schema for the gateways API
type Gateway struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec GatewaySpec `json:"spec,omitempty"`
在apis/app/v1下新建doc.go,其中groupName要根据kubebuilder init和kubebuilder create api参数对应修改