一、创建自定义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