<aside> 🤡 本文主要介绍如何为 CRD 资源编写自定义的控制器
</aside>
上节课我们已经学习了如何使用 code-generator 来进行代码自动生成,通过代码自动生成可以帮我们自动生成 CRD 资源对象客户端访问的 ClientSet、Informer、Lister 等工具包,接下来我们就来了解下如何编写一个自定义的控制器。
这里我们来针对前面课程中介绍的 CronTab 自定义资源对象编写一个自定义的控制器,对应的资源清单文件如下所示:
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
我们需要针对上面的规范来定义资源结构,首先初始化项目:
$ 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
然后初始化 CRD 资源类型,建立好自己的 CRD 结构体,然后使用code-generator 生成客户端代码:
$ mkdir -p pkg/apis/stable/v1beta1
在该文件夹中新建 doc.go
文件,内容如下所示:
// +k8s:deepcopy-gen=package
// +groupName=stable.example.com
package v1beta1
根据 CRD 的规范定义,这里我们定义的 group 为 stable.example.com
,版本为 v1beta1
,在顶部添加了一个代码自动生成的 deepcopy-gen
的 tag,为整个包中的类型生成深拷贝方法。
然后就是非常重要的资源对象的结构体定义,新建 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"`
}
然后可以参考系统内置的资源对象,还需要提供 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
}
最终的项目结构如下所示:
$ tree .
.
├── go.mod
├── go.sum
└── pkg
└── apis
└── stable
└── v1beta1
├── doc.go
├── register.go
└── types.go
4 directories, 5 files