在 K8S 1.7 开始支持 Custom Resource Define, CRD 自定义资源,这样可以动态注册到集群中,就与其它资源类似可以通过 kubectl 来管理该资源了。注意,此时的 CRD 仅仅是资源的定义而已,需要一个 Controller 去监听 CRD 的各种事件来添加自定义的业务逻辑。
示例
这里以 Cron 表达式为例,简单介绍使用方法,首先是一个仅操作数据的示例 cron.yaml
配置文件。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: crons.example.com
spec:
group: example.com
versions: # 所有支持的版本
- name: v1beta1 # 版本名称,比如 v1、v2beta1 等等
served: true # 是否开启通过 REST APIs 访问
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 # 定义作用范围,可以是命名空间或者整个集群(cluster)
names:
kind: Cron # 驼峰形式定义,会在资源清单中的Kind参数使用
plural: crons # 复数形式用于RestAPI路径
singular: cron # 单数,用于Client操作或显示的别名
shortNames: # 缩写形式
- ct
其中的 metadata.name
必须要以 复数.组
的方式命名,以上述的示例为例,那么 RestAPI 就是 /apis/example.com/v1/crons
。
另外,在 schema
中参数会通过 OpenAPI v3 Schema 方式进行简单的参数校验,如果需要更复杂的校验则可以参考 CRD Validation 中的介绍。
创建资源
通过如下方式创建 crons.example.com
资源。
----- 创建资源并查看
# kubectl apply -f cron.yaml
customresourcedefinition.apiextensions.k8s.io/crons.example.com created
# kubectl get crd
NAME CREATED AT
crons.example.com 2022-08-18T15:40:20Z
然后就可以据此定义 Cron
资源对象,如下是 cron-demo.yaml
文件。
apiVersion: "example.com/v1beta1"
kind: Cron
metadata:
name: cron-demo
spec:
cronSpec: "* * * * */5"
image: your-image-here
接着可以创建、查看该对象。
----- 创建上述的对象
# kubectl apply -f cron-demo.yaml
kubectl apply -f cron-demo.yaml
----- 查看时可以简写为ct或者是复数crons
# kubectl get cron
NAME AGE
cron-demo 41s
----- 或者查看原始的yaml文件,包含了关键的cronSpec和image参数
# kubectl get cron -o yaml
apiVersion: v1
items:
- apiVersion: example.com/v1beta1
kind: Cron
metadata:
... ...
spec:
cronSpec: '* * * * */5'
image: your-image-here
kind: List
metadata:
resourceVersion: ""
Controller
上述只是将自定义的资源创建了,也就是将资源清单数据保存到了 etcd 中,除此之外并没有其它的用处,接着需要定义一个 Controller 来处理,可以查看 Sample Controller 示例代码。
其实现最终会基于 client-go 这个库,基本原理架构可以参考 Under the Hood 中的介绍。
示例
这是官方提供的 Sample Controller 实例,可以参考 GitHub,可以通过如下方式简单试用。
----- 下载相关依赖包并编译二进制文件
# go mod vendor
# go build -o sample-controller .
----- 更新生成代码,会更新deepcopy和pkg/generated
# bash hack/update-codegen.sh
----- 创建自定义的CRD资源
# kubectl create -f artifacts/examples/crd-status-subresource.yaml
customresourcedefinition.apiextensions.k8s.io/foos.samplecontroller.k8s.io created
----- 在本地运行
# ./sample-controller -kubeconfig=$HOME/.kube/config
----- 创建自定义的资源对象并检查,也可以删除
# kubectl create -f artifacts/examples/example-foo.yaml
foo.samplecontroller.k8s.io/example-foo created
# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
example-foo 0/1 1 0 45s
# kubectl delete deployment example-foo
deployment.apps "example-foo" deleted
这实际上是从 K8S 源码中提取出来的,所以有些生成代码的更新脚本需要进行修改才可以。
代码生成
通过 code-generator 提供了以下工具生成代码:
deepcopy-gen
生成深度拷贝方法,为每个 T 类型创建一个func (t *T) DeepCopy()
方法。client-gen
为自定义资源生成标准的操作方法,例如 get list create 等,也就是 Kerbernetes 的客户端。informer-gen
为自定义资源生成 informer 模块,这是一种基于事件的接口,用来及时反馈数据库中自定义资源的变化。lister-gen
为自定义资源的 get 和 list 方法提供只读缓存层。
通过这四种生成器可以打造和 Kerbernetes 上游一样的控制器能力,除此之外,还有其它的代码生成工具。
可以直接下载代码后在源码所在目录下执行如下命令 go install k8s.io/code-generator/cmd/deepcopy-gen
进行安装。另外,还提供了 generate-groups.sh
和 generate-internal-groups.sh
两个脚本方便调用。
----- 安装代码,由于cmd的命令不在根目录下,实际上只会下载代码
# go install k8s.io/code-generator@latest
----- 切换到源码目录下安装
# cd $GOPATH/pkg/mod/k8s.io/code-generator
在 code-generator
源码中已经提供了一些常用的脚本文件:
generate-groups.sh
通过命令行直接调用,可以用来调用不同的脚本,不过已经不建议使用了。kube_codegen.sh
真正功能的实现函数,通常用于自定义脚本的编写,一般会通过hack/update-codegen.sh
脚本更新以及hack/verify-codegen.sh
检查是否最新。
详细的使用可以直接参考源码中的 help 信息,这里以上述的 Sample Controller 为例生成相应代码,可以通过 kube_codegen.sh
配置自己的脚本,不过对目录是有一定要求的。
注意,在使用时有个隐形的约束,假设包为 ROOT_PKG=k8s.io/sample-controller
,那么对应的 Controller 源码应该保存在 $GOPATH/src/$ROOT_PKG
目录下。实际上,这也是没有 module 之前的约定,不过自从有了 module 之后对目录不再有要求了。
对于 sample-controller 来说已经提供了脚本,可以通过如下步骤测试。
$ mkdir -p $GOPATH/src/k8s.io/sample-controller && cd $GOPATH/src/k8s.io/sample-controller
$ git clone https://github.com/kubernetes/sample-controller.git .
$ bash hack/update-codegen.sh