👻
kubebuilderで作成したCRDのclientsetをcode-generatorで生成する方法
概要
kubebuilderで作成したCRDのclientsetをcode-generatorで生成しようとしたときに、ちょっとはまったのでメモ。
環境
goとkubebuilderのバージョンは以下の通り。
$ go version
go version go1.19.2 linux/amd64
$ kubebuilder version
Version: main.version{KubeBuilderVersion:"3.7.0", KubernetesVendor:"1.24.1", GitCommit:"3bfc84ec8767fa760d1771ce7a0cb05a9a8f6286", BuildDate:"2022-09-20T17:21:57Z", GoOs:"linux", GoArch:"amd64"}
方法
プロジェクト作成
どうもcode-generatorはプロジェクトのディレクトリ構成に要件があるっぽくて、kubebuilderの方でMulti-Group対応が必要っぽい。
したがって、下記手順でプロジェクトの作成を行う必要がある。
- プロジェクトの初期化
$ kubebuilder init --domain sosomasox.com --repo github.com/sosomasox/example-controller
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
Get controller runtime:
$ go get sigs.k8s.io/controller-runtime@v0.13.0
go: downloading sigs.k8s.io/controller-runtime v0.13.0
go: downloading k8s.io/apimachinery v0.25.0
go: downloading k8s.io/client-go v0.25.0
go: downloading k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed
go: downloading k8s.io/klog/v2 v2.70.1
go: downloading sigs.k8s.io/structured-merge-diff/v4 v4.2.3
go: downloading k8s.io/component-base v0.25.0
go: downloading golang.org/x/net v0.0.0-20220722155237-a158d28d115b
go: downloading github.com/evanphx/json-patch/v5 v5.6.0
go: downloading golang.org/x/time v0.0.0-20220609170525-579cf78fd858
go: downloading k8s.io/api v0.25.0
go: downloading k8s.io/apiextensions-apiserver v0.25.0
go: downloading sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2
go: downloading golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f
go: downloading k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1
go: downloading github.com/emicklei/go-restful/v3 v3.8.0
Update dependencies:
$ go mod tidy
go: downloading github.com/go-logr/zapr v1.2.3
go: downloading go.uber.org/zap v1.21.0
go: downloading github.com/Azure/go-autorest/autorest v0.11.27
go: downloading cloud.google.com/go v0.97.0
go: downloading github.com/golang-jwt/jwt/v4 v4.2.0
go: downloading golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
go: downloading github.com/onsi/ginkgo/v2 v2.1.4
go: downloading github.com/Azure/go-autorest/autorest/mocks v0.4.2
Next: define a resource with:
$ kubebuilder create api
- Multi-Group対応
$ kubebuilder edit --multigroup=true
- APIの作成
$ kubebuilder create api --group example --version v1alpha1 --kind Hoge
Create Resource [y/n]
y
Create Controller [y/n]
y
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
apis/hoge/v1alpha1/hoge_types.go
controllers/hoge/hoge_controller.go
Update dependencies:
$ go mod tidy
Running make:
$ make generate
mkdir -p /home/taichi/Workspace/example-controller/bin
test -s /home/taichi/Workspace/example-controller/bin/controller-gen || GOBIN=/home/taichi/Workspace/example-controller/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.9.2
go: downloading sigs.k8s.io/controller-tools v0.9.2
go: downloading github.com/gobuffalo/flect v0.2.5
go: downloading k8s.io/apiextensions-apiserver v0.24.0
go: downloading golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717
go: downloading golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
/home/taichi/Workspace/example-controller/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
Next: implement your new API and generate the manifests (e.g. CRDs,CRs) with:
$ make manifests
code-generatorに必要なファイルの作成と変更
プロジェクト作成が終わったらcode-generatorに必要なファイルを作成していく。
まず、下記内容のファイルを apis/<group名>/v1alpha1/doc.go
として作成する。
groupName
は <group名>.<domain名>
にする。
$ cat apis/example/v1alpha1/doc.go
// +groupName=example.sosomasox.com
package v1alpha1
さらに、下記内容のファイルを apis/<group名>/v1alpha1/register.go
として作成する。
$ cat apis/example/v1alpha1/register.go
package v1alpha1
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()
}
次に、クライアントを作成したいカスタムリソースを定義づけているファイル内の構造体付近に //+genclient
をつける。
//+genclient
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// Hoge is the Schema for the hoges API
type Hoge struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec HogeSpec `json:"spec,omitempty"`
Status HogeStatus `json:"status,omitempty"`
}
スクリプトの作成
hack
ディレクトリ配下に下記内容のファイルを作成します。
$ cat hack/tools.go
// +build tools
package tools
import _ "k8s.io/code-generator"
code-generatorを実行するスクリプトを作成します。
$ cat hack/update-codegen.sh
#!/bin/bash -x
set -o errexit
set -o nounset
set -o pipefail
# corresponding to go mod init <module>
MODULE=github.com/sosomasox/example-controller
# api package
APIS_PKG=apis
# group-version such as foo:v1alpha1
GROUP=example
VERSION=v1alpha1
GROUP_VERSION=${GROUP}:${VERSION}
# generated output package
OUTPUT_PKG=generated/${GROUP}
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.
rm -rf generated
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}"
mv ${MODULE}/generated generated
rm -rf `echo ${MODULE} | cut -d '/' -f 1`
rm -rf generated/${GROUP}/clientset/versioned/fake
rm -rf generated/${GROUP}/clientset/versioned/typed/${GROUP}/v1alpha1/fake
exit 0
hack/update-codegen.sh
に実行権限を付与します。
$ chmod +x hack/update-codegen.sh
code-generatorのインストール
依存関係を更新します。
$ go mod tidy
go: downloading k8s.io/code-generator v0.25.0
go: downloading golang.org/x/tools v0.1.12
ベンダーを更新し、generate-groups.sh
に実行権限を付与します。
$ go mod vendor
$ chmod +x vendor/k8s.io/code-generator/generate-groups.sh
clientsetの生成
hack/update-codegen.sh
を実行し、code-generatorでclientsetを生成します。
$ ./hack/update-codegen.sh
+ set -o errexit
+ set -o nounset
+ set -o pipefail
+ MODULE=github.com/sosomasox/example-controller
+ APIS_PKG=apis
+ GROUP=example
+ VERSION=v1alpha1
+ GROUP_VERSION=example:v1alpha1
+ OUTPUT_PKG=generated/example
++ dirname ./hack/update-codegen.sh
+ SCRIPT_ROOT=./hack/..
++ cd ./hack/..
++ ls -d -1 ./vendor/k8s.io/code-generator
+ CODEGEN_PKG=./vendor/k8s.io/code-generator
+ rm -rf generated
+ bash ./vendor/k8s.io/code-generator/generate-groups.sh client,lister,informer github.com/sosomasox/example-controller/generated/example github.com/sosomasox/example-controller/apis example:v1alpha1 --go-header-file ./hack/../hack/boilerplate.go.txt --output-base ./hack/..
Generating clientset for example:v1alpha1 at github.com/sosomasox/example-controller/generated/example/clientset
Generating listers for example:v1alpha1 at github.com/sosomasox/example-controller/generated/example/listers
Generating informers for example:v1alpha1 at github.com/sosomasox/example-controller/generated/example/informers
+ mv github.com/sosomasox/example-controller/generated generated
++ echo github.com/sosomasox/example-controller
++ cut -d / -f 1
+ rm -rf github.com
+ rm -rf generated/example/clientset/versioned/fake
+ rm -rf generated/example/clientset/versioned/typed/example/v1alpha1/fake
+ exit 0
generated
ディレクトリ配下にclientsetが生成されていることが確認できます。
$ ls generated/example/
clientset informers listers
中身はこんな感じ。
参考
Discussion