在Kubernetes中,Pod是最小的调度单元,它由各种各样的Controller管理,比如ReplicaSet Controller,Deployment Controller等。
Kubernetes内置了许多Controller,这些Controller能满足80%的业务需求,但是企业里也难免需要自定义Controller来适配自己的业务需求。
网上自定义Controller的文章很多,基本都差不多。俗话说:光说不练假把式,本篇文章主要是自己的一个实践归档总结,如果对你有帮助,可以一键三连!
本文主要从以下几个方面进行介绍,其中包括理论部分和具体实践部分。
Controller的实现逻辑
当我们向kube-apiserver提出创建一个Deployment需求的时候,首先是会把这个需求存储到Etcd中,如果这时候没有Controller的话,这条数据仅仅是存在Etcd中,并没有产生实际的作用。
所以就有了Deployment Controller,它实时监听kube-apiserver中的Deployment对象,如果对象有增加、删除、修改等变化,它就会做出相应的相应处理,如下
// pkg/controller/deployment/deployment_controller.go 121行
.....
dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: dc.addDeployment,
UpdateFunc: dc.updateDeployment,
// This will enter the sync loop and no-op, because the deployment has been deleted from the store.
DeleteFunc: dc.deleteDeployment,
})
......
其实现的逻辑图如下(图片来自网络):
可以看到图的上半部分都由client-go实现了,下半部分才是我们具体需要去处理的。
client-go主要包含Reflector、Informer、Indexer三个组件。
- Reflector会List&Watch kube-apiserver中的特定资源,然后会把变化的资源放入Delta FIFO队列中。
- Informer会从Delta FIFO队列中拿取对象交给相应的HandleDeltas。
- Indexer会将对象存储到缓存中。
上面部分不需要我们去开发,我们主要关注下半部分。
当把数据交给Informer的回调函数HandleDeltas后,Distribute会将资源对象分发到具体的处理函数,这些处理函数通过一系列判断过后,把满足需求的对象放入Workqueue中,然后再进行后续的处理。
code-generator介绍
上一节说到我们只需要去实现具体的业务需求,这是为什么呢?主要是因为kubernetes为我们提供了code-generator【1】这样的代码生成器工具,可以通过它自动生成客户端访问的一些代码,比如Informer、ClientSet等。
code-generator提供了以下工具为Kubernetes中的资源生成代码:
- deepcopy-gen:生成深度拷贝方法,为每个 T 类型生成 func (t* T) DeepCopy() *T 方法,API 类型都需要实现深拷贝
- client-gen:为资源生成标准的 clientset
- informer-gen:生成 informer,提供事件机制来响应资源的事件
- lister-gen:生成 Lister**,**为 get 和 list 请求提供只读缓存层(通过 indexer 获取)
如果需要自动生成,就需要在代码中加入对应格式的配置,如
其中:
- // +genclient表示需要创建client
- // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object表示在需要实现k8s.io/apimachinery/pkg/runtime.Object这个接口
除此还有更多的用法,可以参考Kubernetes Deep Dive: Code Generation for CustomResources【2】进行学习。
CRD介绍
CRD全称CustomResourceDefinition,中文简称自定义资源,上面说的Controller主要就是用来管理自定义的资源。
我们可以通过下面命令来查看当前集群中使用了哪些CRD,如下:
# kubectl get crd
NAME CREATED AT
ackalertrules.alert.alibabacloud.com 2021-06-15T02:19:59Z
alertmanagers.monitoring.coreos.com 2019-12-12T12:50:00Z
aliyunlogconfigs.log.alibabacloud.com 2019-12-02T10:15:02Z
apmservers.apm.k8s.elastic.co 2020-09-14T01:52:53Z
batchreleases.alicloud.com 2019-12-02T10:15:53Z
beats.beat.k8s.elastic.co 2020-09-14T01:52:53Z
chaosblades.chaosblade.io 2021-06-15T02:30:54Z
elasticsearches.elasticsearch.k8s.elastic.co 2020-09-14T01:52:53Z
enterprisesearches.enterprisesearch.k8s.elastic.co 2020-09-14T01:52:53Z
globaljobs.jobs.aliyun.com 2020-04-26T14:40:53Z
kibanas.kibana.k8s.elastic.co 2020-09-14T01:52:54Z
prometheuses.monitoring.coreos.com 2019-12-12T12:50:01Z
prometheusrules.monitoring.coreos.com 2019-12-12T12:50:02Z
servicemonitors.monitoring.coreos.com 2019-12-12T12:50:03Z
但是仅仅是创建一个CRD对象是不够的,因为它是静态的,创建过后仅仅是保存在Etcd中,如果需要其有意义,就需要Controller配合。
创建CRD的例子如下:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
# name 必须匹配下面的spec字段:<plural>.<group>
name: students.coolops.io
spec:
# group 名用于 REST API 中的定义:/apis/<group>/<version>
group: coolops.io
# 列出自定义资源的所有 API 版本
versions:
- name: v1 # 版本名称,比如 v1、v1beta1
served: true # 是否开启通过 REST APIs 访问 `/apis/<group>/<version>/...`
storage: true # 必须将一个且只有一个版本标记为存储版本
schema: # 定义自定义对象的声明规范
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
name:
type: string
school:
type: string
scope: Namespaced # 定义作用范围:Namespaced(命名空间级别)或者 Cluster(整个集群)
names:
plural: students # plural 名字用于 REST API 中的定义:/apis/<group>/<version>/<plural>
shortNames: # shortNames 相当于缩写形式
- stu
kind: Student # kind 是 sigular 的一个驼峰形式定义,在资源清单中会使用
singular: student # singular 名称用于 CLI 操作或显示的一个别名
具体演示
本来准备根据官方的demo【3】进行讲解,但是感觉有点敷衍,而且这类教程网上一大堆,所以就准备自己实现一个数据库管理的一个Controller。
因为是演示怎么开发Controller,所以功能不会复杂,主要的功能是:
- 创建数据库实例
- 删除数据库实例
- 更新数据库实例
开发环境说明
本次实验环境如下:
创建CRD
CRD是基础,Controller主要是为CRD服务的,所以我们要先定义好CRD资源,便于开发。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: databasemanagers.coolops.cn
spec:
group: coolops.cn
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
deploymentName:
type: strin
replicas:
type: integer
minimum: 1
maximum: 10
dbtype:
type: string
status:
type: object
properties:
availableReplicas:
type: integer
names:
kind: DatabaseManager
plural: databasemanagers
singular: databasemanager
shortNames:
- dm
scope: Namespaced
创建CRD,检验是否能创建成功。
# kube