一、介绍
- 简要介绍
Kubernetes官网的介绍中operator利用定制资源管理应用及其组件,主要涉及自定义的API对象,CRD资源,以及自定义的控制器来处理业务。
- 官网列举了如下应用场景
场景1 :在Kubernetes集群上按需部署业务,也是最常用的场景
场景2 :获取、还原应用状态的备份,例如对于数据库的应用,通过CRD资源来触发operator控制器来备份还原
场景3 :模拟整个或部分集群中的故障以测试其稳定性
场景4:在没有内部成员选举程序的情况下,为分布式应用选择首领角色
operator主要还是通过编码和APIserver进行交互,获取相关资源的期望状态并执行自动化任务
二、架构原理
组网图及架构说明
以下为Operator的工作原理架构图:
上述自定义控制器的运行状态通常为Kubernetes集群中的Deployment,当然根据业务不同也可以使用Daemonset或者Statefulset,甚至是集群外的本地二进制守护进程或者一个Docker容器应用。
Informer:主要作用是本地同步API对象(一个CRD资源的实例化)及其状态,触发不同的事件Handler
Reflactor:Informer模块中用来连接Apiserver并获取API对象的组件
Delta FIFO Queue:增量先进先出队列,在Informer模块中用于保存Delta增量(即API对象和事件类型的组合)
Local Store:用于本地缓存API对象
Work Queue:自定义工作队列,用于缓存Key这一对象(通常为namespace/name类型的字符串,指向具体的API对象),主要是用于解耦informer和控制循环,防止控制循环作为消费者运行过于缓慢拖死Informer
Control Loop:控制循环,自定义控制器中具体执行逻辑的实现,调用其他API或者命令来实现业务
架构原理分析
当自定义控制器启动后,会运行informer模块,以及控制循环和一个工作队列。
当informer运行时,会由Reflactor来连接Apiserver,并通过listandwatch机制,list接口获取API对象,watch接口监听API对象的变化。Reflactor获取API对象及其事件后,会组合为一个叫做增量 Delta 的资源存入Delta FIFO Queue。常见的事件类型有Add、Update、Delete。
informer同时还会消费队列中的Delta资源,当消费资源时会有两个工作
- 根据事件类型处理API对象并保存至Local Store,即同步并缓存API对象。
- 触发事先注册的Event Handler。通常有执行相应事件的处理,并把API对象的namespace/name类型的字符串作为Key写入工作队列
同时控制循环会消费工作队列中的Key,并从Local Store缓存中获取API对象,通常有以下操作
- 可获取对应的API对象,此时获取到的API对象为期望状态,控制循环会调用相关的API或者命令获取API对象的实际状态,两者做对比(通常对比resourceVersion字段),将API对象的实际状态置为期望状态
- 无法获取API对象,通常是触发了Delete事件从而从缓存中删除了API对象,此时控制循环也会将实际状态中的API对象删除
三、使用指南
使用软硬环境
硬件要求
支持硬件
类型 | 要求 |
服务器 | ARM/X86 |
【注:有其他特殊要求的请在列表下面添加行,如内存: 不小于16G】
实验硬件
类型 | 实验使用 |
服务器 | X86 |
【注:有其他特殊要求的请在列表下面添加行,如内存: 不小于16G】
软件要求
实验软件版本
类型 | 实验版本 |
操作系统 | Ubuntu 20.04 |
Kubernetes | 1.21.6 |
安装部署
- 克隆官方的sample-controller示例工程
$ git clone https://github.com/resouer/k8s-controller-custom-resource
$ cd k8s-controller-custom-resource
- 编译
$ go get github.com/tools/godep
$ godep restore
$ go build -o samplecrd-controller .
- 运行Controller
此处是简单的以进程方式运行,后续可以放到Pod中运行
$ ./samplecrd-controller -kubeconfig=$HOME/.kube/config -alsologtostderr=true
启动后可以在标准输出的日志看到设置了event handlers,开启了一个control loop业务循环,同时启动informer来获取并监听kubernetes相关API资源,由于目前还没有提交CRD资源,所以一直报错无法获取资源
- 执行注册用户自定义资源定义CRD
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: networks.samplecrd.k8s.io
spec:
group: samplecrd.k8s.io
version: v1
names:
kind: Network
plural: networks
scope: Namespaced
kubectl apply -f crd/network.yaml
日志显示启动了一个工作线程来等待处理具体的CR
- 创建一个用户自定义资源CR
apiVersion: samplecrd.k8s.io/v1
kind: Network
metadata:
name: example-network
spec:
cidr: "192.168.0.0/16"
gateway: "192.168.0.1"
kubectl apply -f example/example-network.yaml
日志显示工作线程开始工作,执行相关业务,当然由于这是个例子,仅仅是创建了该资源
同时在kubernetes集群中也可以看到相关CRD资源和API对象
- 修改CR资源
修改CR资源
重新执行,由于Controller持续监听该资源的增删改,故日志中也体现资源被修改
- 删除CR资源
日志同步显示CR资源被删除
四、常见问题
go get命令执行显示没有go.mod文件
解决方案
执行go env -w GO111MODULE=off
后继续执行命令
godep命令command not found
解决方案
- 查看$GOPATH/bin目录下是否有godep二进制文件
go env
查看GOBIN的值
- 执行
export PATH=$GOPATH/bin:$PATH
五、资料出处
六、遗留问题
- 将Controller放到Deployment中运行
- 源码解析