kubebuilder和k8s.io/code-generator類似屯阀,是一個碼生成工具,用于為你的CRD生成kubernetes-style API實現(xiàn)轴术。目前個人使用Kubebuilder生成CRD和manifests yaml难衰,再使用code-generator生成informers、listers逗栽、clientsets盖袭。
下載kubebuilder
# download kubebuilder and install locally.
curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)
chmod +x kubebuilder && mv kubebuilder /usr/local/bin/
本文中使用的Kubebuilder版本為release-3,code-generator版本為v0.19.2
使用kubebuilder創(chuàng)建項目
go mod init example
// --skip-go-version-check 跳過Go版本校驗
kubebuilder init --domain lgy.com --skip-go-version-check
// 設(shè)置后生成的api上層會自動創(chuàng)建Group名文件夾
kubebuilder edit --multigroup=true
kubebuilder create api --version v1 --kind Example--group serving
效果如下:
[root@master example]# go mod init example
go: creating new go.mod: module example
[root@master example]# kubebuilder init --domain lgy.com --skip-go-version-check
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
Get controller runtime:
$ go get sigs.k8s.io/controller-runtime@v0.7.2
Update dependencies:
$ go mod tidy
Next: define a resource with:
$ kubebuilder create api
[root@master example]# kubebuilder edit --multigroup=true
[root@master example]# kubebuilder create api --version v1 --kind Example --group serving
Create Resource [y/n]
y
Create Controller [y/n]
n
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
apis/serving/v1/example_types.go
Update dependencies:
$ go mod tidy
Running make:
$ make generate
go: creating new go.mod: module tmp
Downloading sigs.k8s.io/controller-tools/cmd/controller-gen@v0.4.1
go get: installing executables with 'go get' in module mode is deprecated.
To adjust and download dependencies of the current module, use 'go get -d'.
To install using requirements of the current module, use 'go install'.
To install ignoring the current module, use 'go install' with a version,
like 'go install example.com/cmd@latest'.
For more information, see https://golang.org/doc/go-get-install-deprecation
or run 'go help get' or 'go help install'.
go get: added github.com/fatih/color v1.7.0
go get: added github.com/gobuffalo/flect v0.2.0
go get: added github.com/gogo/protobuf v1.3.1
go get: added github.com/google/gofuzz v1.1.0
go get: added github.com/inconshreveable/mousetrap v1.0.0
go get: added github.com/json-iterator/go v1.1.8
go get: added github.com/mattn/go-colorable v0.1.2
go get: added github.com/mattn/go-isatty v0.0.8
go get: added github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
go get: added github.com/modern-go/reflect2 v1.0.1
go get: added github.com/spf13/cobra v1.0.0
go get: added github.com/spf13/pflag v1.0.5
go get: added golang.org/x/mod v0.2.0
go get: added golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
go get: added golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7
go get: added golang.org/x/text v0.3.2
go get: added golang.org/x/tools v0.0.0-20200616195046-dc31b401abb5
go get: added golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
go get: added gopkg.in/inf.v0 v0.9.1
go get: added gopkg.in/yaml.v2 v2.2.8
go get: added gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966
go get: added k8s.io/api v0.18.2
go get: added k8s.io/apiextensions-apiserver v0.18.2
go get: added k8s.io/apimachinery v0.18.2
go get: added k8s.io/klog v1.0.0
go get: added k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
go get: added sigs.k8s.io/controller-tools v0.4.1
go get: added sigs.k8s.io/structured-merge-diff/v3 v3.0.0
go get: added sigs.k8s.io/yaml v1.2.0
/opt/lgy/example/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
[root@master example]#
[root@master example]#
[root@master example]# tree
.
├── apis
│ └── serving
│ └── v1
│ ├── example_types.go
│ ├── groupversion_info.go
│ └── zz_generated.deepcopy.go
├── bin
│ └── controller-gen
├── config
│ ├── crd
│ │ ├── kustomization.yaml
│ │ ├── kustomizeconfig.yaml
│ │ └── patches
│ │ ├── cainjection_in_examples.yaml
│ │ └── webhook_in_examples.yaml
│ ├── default
│ │ ├── kustomization.yaml
│ │ ├── manager_auth_proxy_patch.yaml
│ │ └── manager_config_patch.yaml
│ ├── manager
│ │ ├── controller_manager_config.yaml
│ │ ├── kustomization.yaml
│ │ └── manager.yaml
│ ├── prometheus
│ │ ├── kustomization.yaml
│ │ └── monitor.yaml
│ ├── rbac
│ │ ├── auth_proxy_client_clusterrole.yaml
│ │ ├── auth_proxy_role_binding.yaml
│ │ ├── auth_proxy_role.yaml
│ │ ├── auth_proxy_service.yaml
│ │ ├── example_editor_role.yaml
│ │ ├── example_viewer_role.yaml
│ │ ├── kustomization.yaml
│ │ ├── leader_election_role_binding.yaml
│ │ ├── leader_election_role.yaml
│ │ ├── role_binding.yaml
│ │ └── service_account.yaml
│ └── samples
│ └── serving_v1_example.yaml
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
├── main.go
├── Makefile
└── PROJECT
13 directories, 35 files
添加文件apis/serving/v1/rbac.go彼宠,這個文件用生成RBAC manifests:
注意修改kubebuilder:rbac:groups和resources為你的
// +kubebuilder:rbac:groups=serving.lgy.com,resources=examples,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=serving.lgy.com,resources=examples/status,verbs=get;update;patch
package v1
生成CRD manifests
[root@master example]# make manifests
/opt/lgy/example/bin/controller-gen "crd:trivialVersions=true,preserveUnknownFields=false" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
[root@master example]#
使用code-generator
1)準(zhǔn)備腳本
在hack目錄下添加以下文件:
[root@master hack]# tree
.
├── boilerplate.go.txt
├── tools.go
├── update-codegen.sh
└── verify-codegen.sh
0 directories, 4 files
tools.go
// +build tools
package tools
update-codegen.sh
注意:
MODULE和go.mod保持一致
API_PKG=apis鳄虱,和apis目錄保持一致
OUTPUT_PKG=generated/serving,生成Resource時指定的group一樣
GROUP_VERSION=serving:v1和生成Resource時指定的group version對應(yīng)
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
# corresponding to go mod init <module>
MODULE=example
# api package
APIS_PKG=apis
# generated output package
OUTPUT_PKG=generated/serving
# group-version such as foo:v1alpha1
GROUP_VERSION=serving: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}"
verify-codegen.sh
注意:
OUTPUT_PKG=generated/serving凭峡,生成Resource時指定的group一樣
MODULE是domain和go.mod的結(jié)合
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
OUTPUT_PKG=generated/serving
MODULE=lgy.com/example
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
修改文件權(quán)限:
[root@master hack]# chmod 755 update-codegen.sh
[root@master hack]# chmod 755 verify-codegen.sh
[root@master hack]#
2)添加注釋
修改example_types.go文件拙已,添加上tag // +genclient,這個注釋內(nèi)容要加在Example結(jié)構(gòu)體上面摧冀,
//+genclient
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// Example is the Schema for the examples API
type Example struct {
metav1.TypeMeta `json:",inline"`
新建apis/serving/v1/doc.go
// +groupName更換成自己的
// +groupName=serving.lgy.com
package v1
新建apis/serving/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()
}
3)更新依賴
新增 k8s.io/code-generator,需和 k8s.io/client-go版本一致
module example
go 1.15
require (
k8s.io/apimachinery v0.19.2
k8s.io/client-go v0.19.2
k8s.io/code-generator v0.19.2
sigs.k8s.io/controller-runtime v0.7.2
)
然后使用vend工具更新vendor索昂,注意這里不要用go mod vendor命令來更新惭适,因為k8s.io/code-generator這個依賴在項目中并沒有真正被引用過,所以使用go mod vendor是無法將這個依賴更新到vendor中楼镐,要借助第三方工具vend來實現(xiàn)癞志。https://github.com/nomad-software/vend
使用命令go get
github.com/nomad-software/vend來安裝,然后再項目根目錄下執(zhí)行vend
命令
然后給generate-groups.sh添加可執(zhí)行權(quán)限:
[root@master example]# chmod 755 vendor/k8s.io/code-generator/generate-groups.sh
[root@master example]#
執(zhí)行hack/update-codegen.sh:
[root@master example]# ./hack/update-codegen.sh
Generating clientset for serving:v1 at example/generated/serving/clientset
Generating listers for serving:v1 at example/generated/serving/listers
Generating informers for serving:v1 at example/generated/serving/informers
[root@master example]#
當(dāng)前目錄下生成example文件夾
[root@master example]# pwd
/opt/lgy/example/example
[root@master example]# tree -CL 6
.
└── generated
└── serving
├── clientset
│ └── versioned
│ ├── clientset.go
│ ├── doc.go
│ ├── fake
│ │ ├── clientset_generated.go
│ │ ├── doc.go
│ │ └── register.go
│ ├── scheme
│ │ ├── doc.go
│ │ └── register.go
│ └── typed
│ └── serving
├── informers
│ └── externalversions
│ ├── factory.go
│ ├── generic.go
│ ├── internalinterfaces
│ │ └── factory_interfaces.go
│ └── serving
│ ├── interface.go
│ └── v1
└── listers
└── serving
└── v1
├── example.go
└── expansion_generated.go
16 directories, 13 files