一、创建自定义CRD
apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: crontabs.stable.example.com spec: group: stable.example.com versions: - name: v1beta1 served: true storage: true schema: openAPIV3Schema: description: Define CronTab YAML Spec type: object properties: spec: type: object properties: cronSpec: type: string image: type: string replicas: type: integer scope: Namespaced names: kind: CronTab plural: crontabs singular: crontab shortNames: - ct
二、初始化项目并且导入包
1、初始化项目
$ mkdir -p github.com/cnych/controller-demo && cd github.com/cnych/controller-demo # 初始化项目 $ go mod init github.com/cnych/controller-demo go: creating new go.mod: module github.com/cnych/controller-demo # 获取依赖 $ go get k8s.io/apimachinery@v0.17.9 $ go get -d k8s.io/code-generator@v0.17.9 $ go get k8s.io/client-go@v0.17.9
2、在当前项目目录建立好自己的 CRD 结构体,然后使用code-generator 生成客户端代码:
mkdir -p pkg/apis/stable/v1beta1
3、在该文件夹中新建 doc.go
文件,内容如下所示:
// +k8s:deepcopy-gen=package // +groupName=stable.example.com package v1beta1
4、新建 type.go
文件
package v1beta1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // +genclient // +genclient:noStatus // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // 根据 CRD 定义 CronTab 结构体 type CronTab struct { metav1.TypeMeta `json:",inline"` // +optional metav1.ObjectMeta `json:"metadata,omitempty"` Spec CronTabSpec `json:"spec"` } // +k8s:deepcopy-gen=false type CronTabSpec struct { CronSpec string `json:"cronSpec"` Image string `json:"image"` Replicas int `json:"replicas"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // CronTab 资源列表 type CronTabList struct { metav1.TypeMeta `json:",inline"` // 标准的 list metadata // +optional metav1.ListMeta `json:"metadata,omitempty"` Items []CronTab `json:"items"` }
5、还需要提供 AddToScheme 与 Resource 两个变量供 client 注册,新建 register.go
文件,内容如下所示
package v1beta1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" ) // GroupName is the group name use in this package const GroupName = "stable.example.com" // 注册自己的自定义资源 var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"} // Resource takes an unqualified resource and returns a Group qualified GroupResource func Resource(resource string) schema.GroupResource { return SchemeGroupVersion.WithResource(resource).GroupResource() } var ( // SchemeBuilder initializes a scheme builder SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) // AddToScheme is a global function that registers this API group & version to a scheme AddToScheme = SchemeBuilder.AddToScheme ) // Adds the list of known types to Scheme. func addKnownTypes(scheme *runtime.Scheme) error { // 添加 CronTab 与 CronTabList 这两个资源到 scheme scheme.AddKnownTypes(SchemeGroupVersion, &CronTab{}, &CronTabList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil }
6、最终的项目结构如图
$ tree . . ├── go.mod ├── go.sum └── pkg └── apis └── stable └── v1beta1 ├── doc.go ├── register.go └── types.go 4 directories, 5 files
三、生成代码
1、项目目录下创建目录
mkdir hack && cd hack
2、创建tools.go文件
// +build tools // 建立 tools.go 来依赖 code-generator // 因为在没有代码使用 code-generator 时,go module 默认不会为我们依赖此包. package tools import _ "k8s.io/code-generator"
3、创建update-codegen.sh
脚本
#!/usr/bin/env bash set -o errexit set -o nounset set -o pipefail 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)} bash "${CODEGEN_PKG}"/generate-groups.sh "deepcopy,client,informer,lister" github.com/cnych/controller-demo/pkg/client github.com/cnych/controller-demo/pkg/apis stable:v1beta1 --output-base "${SCRIPT_ROOT}"/../../.. --go-header-file "${SCRIPT_ROOT}"/hack/boilerplate.go.txt # To use your own boilerplate text append: # --go-header-file "${SCRIPT_ROOT}"/hack/custom-boilerplate.go.txt
4、创建verify-codegen.sh
脚本
#!/usr/bin/env bash set -o errexit set -o nounset set -o pipefail SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. DIFFROOT="${SCRIPT_ROOT}/pkg" TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/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 "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
5、为生成的代码文件添加头部内容的 boilerplate.go.txt
文件,内容如下所示
/* Copyright The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */
6、接下来就是生成代码了,首先将依赖包放置到 vendor 目录中去
go mod vendor
7、然后执行脚本生成代码
$ chmod +x ./hack/update-codegen.sh $ ./hack/update-codegen.sh Generating deepcopy funcs Generating clientset for stable:v1beta1 at github.com/cnych/controller-demo/pkg/client/clientset Generating listers for stable:v1beta1 at github.com/cnych/controller-demo/pkg/client/listers Generating informers for stable:v1beta1 at github.com/cnych/controller-demo/pkg/client/informers
8、代码生成后,整个项目的 pkg 包变成了下面的样子:
$ tree pkg pkg ├── apis │ └── stable │ └── v1beta1 │ ├── doc.go │ ├── register.go │ ├── types.go │ └── zz_generated.deepcopy.go └── client ├── clientset │ └── versioned │ ├── clientset.go │ ├── doc.go │ ├── fake │ │ ├── clientset_generated.go │ │ ├── doc.go │ │ └── register.go │ ├── scheme │ │ ├── doc.go │ │ └── register.go │ └── typed │ └── stable │ └── v1beta1 │ ├── crontab.go │ ├── doc.go │ ├── fake │ │ ├── doc.go │ │ ├── fake_crontab.go │ │ └── fake_stable_client.go │ ├── generated_expansion.go │ └── stable_client.go ├── informers │ └── externalversions │ ├── factory.go │ ├── generic.go │ ├── internalinterfaces │ │ └── factory_interfaces.go │ └── stable │ ├── interface.go │ └── v1beta1 │ ├── crontab.go │ └── interface.go └── listers └── stable └── v1beta1 ├── crontab.go └── expansion_generated.go 20 directories, 26 files