混合kubebuilder與code generator編寫CRD


概覽

kubebuilder和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 init 命令,初始化一個新項目。示例如下。

mkdir $GOPATH/src/foo-controller
cd $GOPATH/src/foo-controller
# 我們將使用zsy.com域,
# 所以所有的 API 組將是<group>.zsy.com.
kubebuilder init --domain zsy.com 
kubebuilder edit --multigroup=true

注意:1、確保你已經安裝 Kubebuilder,如果你的項目目錄不在 $GOPATH 中,你需要運行 go mod init <modulename> 來告訴 kubebuilder 和 Go module 的基本導入路徑。
         2、執行kubebuilder edit --multigroup=true命令,之后通過Kubebuilder創建API生成的Resource將放到項目apis路徑下,不執行此條命令默認放到api路徑下。

控制台輸出類似以下內容:

apple@appledeMacBook-Pro foo-controller$ kubebuilder init --domain zsy.com
Writing scaffold for you to edit...
Get controller runtime:
$ go get sigs.k8s.io/controller-runtime@v0.5.0
Update go.mod:
$ go mod tidy
Running make:
$ make
/usr/local/go/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
go fmt ./...
go vet ./...
go build -o bin/manager main.go
Next: define a resource with:
$ kubebuilder create api

會生成以下文件:

.
├── 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

新建hack/update-codegen.sh,注意修改幾個變量:

  • MODULEgo.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=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

#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

OUTPUT_PKG=generated/webapp
MODULE=zsy.com/foo-controller

SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..

DIFFROOT="${SCRIPT_ROOT}/${OUTPUT_PKG}"
TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/${OUTPUT_PKG}"
_tmp="${SCRIPT_ROOT}/_tmp"

cleanup() {
  rm -rf "${_tmp}"
}
trap "cleanup" EXIT SIGINT

cleanup

mkdir -p "${TMP_DIFFROOT}"
cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"

"${SCRIPT_ROOT}/hack/update-codegen.sh"
echo "copying generated ${SCRIPT_ROOT}/${MODULE}/${OUTPUT_PKG} to ${DIFFROOT}"
cp -r "${SCRIPT_ROOT}/${MODULE}/${OUTPUT_PKG}"/* "${DIFFROOT}"

echo "diffing ${DIFFROOT} against freshly generated codegen"
ret=0
diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}"
if [[ $ret -eq 0 ]]
then
  echo "${DIFFROOT} up to date."
else
  echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh"
  exit 1
fi

2)下載code-generator

先把code-generator下載下來,注意這里的K8S版本號,得和go.mod里的k8s.io/client-go的版本一致:

K8S_VERSION=v0.18.6
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.6,因此要把其他的k8s庫也更新到這個版本,修改項目go.mod文件:

module foo-controller

go 1.13

require (
	github.com/go-logr/logr v0.1.0
	github.com/onsi/ginkgo v1.11.0
	github.com/onsi/gomega v1.8.1
	k8s.io/apimachinery v0.18.6
	k8s.io/client-go v0.18.6
	k8s.io/code-generator v0.18.6
	sigs.k8s.io/controller-runtime v0.6.0
)

執行下面命令更新vendor目錄

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.zsy.com

// +groupName=webapp.zsy.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

會得到zsy.com/foo-controller目錄:

foo-controller
└── generated
    └── webapp
        ├── clientset
        ├── informers
        └── listers

移動文件:

  • 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

參考:https://segmentfault.com/a/1190000023097945

         https://github.com/chanjarster/kubebuilder-mix-codegen-how-to

         https://chanjarster.github.io/post/k8s/use-code-generator/

         https://cloudnative.to/kubebuilder/cronjob-tutorial/cronjob-tutorial.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM