共计 4699 个字符,预计需要花费 12 分钟才能阅读完成。
使用 Kubebuilder+k8s.io/code-generator 编写 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 还带有一些其他便利性设施。
Resource + Controller = Operator,因此你可以利用 Kubebuilder 编写你自己的 Operator。
如果你不想做 Operator,如果你不会直接 or 间接生成 Pod,只是想存取 CRD(把 K8S 当作数据库使用)。那你可以使用 Kubebuilder 生成 CRD 和 manifests yaml,再使用 code-generator 生成 informers、listers、clientsets。
本文讲的就是这个方法。
准备工作:安装 Kubebuilder
参考这里安装 kubebuilder。
第一步:初始化项目
MODULE=example.com/foo-controller
go mod init $MODULE
kubebuilder init --domain example.com
kubebuilder edit --multigroup=true
会生成以下文件:
.
├── Dockerfile
├── Makefile
├── PROJECT
├── bin
│ └── manager
├── config
│ ├── certmanager
│ ├── default
│ ├── manager
│ ├── prometheus
│ ├── rbac
│ └── webhook
├── hack
│ └── boilerplate.go.txt
└── main.go
第二步:生成 Resource 和 manifests
kubebuilder create api --group webapp --version v1 --kind Guestbook
Create Resource [y/n]
y
Create Controller [y/n]
n
会生成以下文件 go 代码和 manifests 文件:
.
├── apis
│ └── webapp
│ └── v1
│ ├── groupversion_info.go
│ ├── guestbook_types.go
│ └── zz_generated.deepcopy.go
└── config
├── crd
│ ├── kustomization.yaml
│ ├── kustomizeconfig.yaml
│ └── patches
│ ├── cainjection_in_guestbooks.yaml
│ └── webhook_in_guestbooks.yaml
├── rbac
│ ├── guestbook_editor_role.yaml
│ ├── guestbook_viewer_role.yaml
└── samples
└── webapp_v1_guestbook.yaml
添加文件apis/webapp/v1/rbac.go
,这个文件用生成 RBAC manifests:
// +kubebuilder:rbac:groups=webapp.example.com,resources=guestbooks,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=webapp.example.com,resources=guestbooks/status,verbs=get;update;patch
package v1
然后生成 CRD manifests:
make manifests
得到:
config
├── crd
│ └── bases
│ └── webapp.example.com_guestbooks.yaml
└── rbac
└── role.yaml
注意:
如果你修改了 guestbook_types.go
的结构,你需要执行以下命令来更新代码和 manifests:
make && make manifests
第三步:使用 code-generator
1)准备脚本
在 hack 目录下准备以下文件:
.
└── hack
├── tools.go
├── update-codegen.sh
└── verify-codegen.sh
新建 hack/tools.go
文件:
// +build tools
package tools
import _ "k8s.io/code-generator"
新建hack/update-codegen.sh
,注意修改几个变量:
-
MODULE
和go.mod
保持一致 -
API_PKG=apis
,和apis
目录保持一致 -
OUTPUT_PKG=generated/webapp
,生成 Resource 时指定的 group 一样 -
GROUP_VERSION=webapp:v1
和生成 Resource 时指定的 group version 对应
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
# corresponding to go mod init <module>
MODULE=example.com/foo-controller
# api package
APIS_PKG=apis
# generated output package
OUTPUT_PKG=generated/webapp
# group-version such as foo:v1alpha1
GROUP_VERSION=webapp:v1
SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../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}/../../.." \
新建hack/verify-codegen.sh
(文件内容请看 github 项目)。
2)下载 code-generator
先把 code-generator 下载下来,注意这里的 K8S 版本号,得和 go.mod
里的 k8s.io/client-go
的版本一致:
K8S_VERSION=v0.18.5
go get k8s.io/code-generator@$K8S_VERSION
go mod vendor
然后给 generate-groups.sh
添加可执行权限:
chmod +x vendor/k8s.io/code-generator/generate-groups.sh
3)更新依赖版本
因为 code-generator 用的是 v0.18.5,因此要把其他的 k8s 库也更新到这个版本:
K8S_VERSION=v0.18.5
go get k8s.io/client-go@$K8S_VERSION
go get k8s.io/apimachinery@$K8S_VERSION
go get sigs.k8s.io/controller-runtime@v0.6.0
go mod vendor
4)生成代码
你需要修改 guestbook_types.go
文件,添加上 tag // +genclient
:
// +genclient
// +kubebuilder:object:root=true
// Guestbook is the Schema for the guestbooks API
type Guestbook struct {
新建apis/webapp/v1/doc.go
,注意// +groupName=webapp.example.com
:
// +groupName=webapp.example.com
package v1
新建apis/webapp/v1/register.go
,code generator 生成的代码需要用到它:
package v1
import ("k8s.io/apimachinery/pkg/runtime/schema")
// SchemeGroupVersion is group version used to register these objects.
var SchemeGroupVersion = GroupVersion
func Resource(resource string) schema.GroupResource {return SchemeGroupVersion.WithResource(resource).GroupResource()}
执行hack/update-codegen.sh
:
./hack/update-codegen.sh
会得到 example.com/foo-controller
目录:
example.com
└── foo-controller
└── generated
└── webapp
├── clientset
├── informers
└── listers
移动文件:
-
example.com/foo-controller/generated
直接移出来,放到项目根下面generated
例子程序
先 apply manifests yaml:
kubectl apply -f config/crd/bases/webapp.example.com_guestbooks.yaml
kubectl apply -f config/samples/webapp_v1_guestbook.yaml
然后执行项目的 main.go。
参考资料
- code-generator client-gen tag references
- kubebuilder tag references
- Kubernetes Deep Dive: Code Generation for CustomResources
- kubebuilder sample project