一、介绍

  1. 简要介绍

Kubernetes官网的介绍中operator利用定制资源管理应用及其组件,主要涉及自定义的API对象,CRD资源,以及自定义的控制器来处理业务。

  1. 官网列举了如下应用场景

场景1 :在Kubernetes集群上按需部署业务,也是最常用的场景

场景2 :获取、还原应用状态的备份,例如对于数据库的应用,通过CRD资源来触发operator控制器来备份还原

场景3 :模拟整个或部分集群中的故障以测试其稳定性

场景4:在没有内部成员选举程序的情况下,为分布式应用选择首领角色

operator主要还是通过编码和APIserver进行交互,获取相关资源的期望状态并执行自动化任务

二、架构原理

组网图及架构说明

以下为Operator的工作原理架构图:

Operator技术分析_API

上述自定义控制器的运行状态通常为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资源,当消费资源时会有两个工作

  1. 根据事件类型处理API对象并保存至Local Store,即同步并缓存API对象。
  2. 触发事先注册的Event Handler。通常有执行相应事件的处理,并把API对象的namespace/name类型的字符串作为Key写入工作队列

同时控制循环会消费工作队列中的Key,并从Local Store缓存中获取API对象,通常有以下操作

  1. 可获取对应的API对象,此时获取到的API对象为期望状态,控制循环会调用相关的API或者命令获取API对象的实际状态,两者做对比(通常对比resourceVersion字段),将API对象的实际状态置为期望状态
  2. 无法获取API对象,通常是触发了Delete事件从而从缓存中删除了API对象,此时控制循环也会将实际状态中的API对象删除

三、使用指南

使用软硬环境

硬件要求

支持硬件

类型

要求

服务器

ARM/X86

【注:有其他特殊要求的请在列表下面添加行,如内存: 不小于16G】

实验硬件

类型

实验使用

服务器

X86

【注:有其他特殊要求的请在列表下面添加行,如内存: 不小于16G】

软件要求

实验软件版本

类型

实验版本

操作系统

Ubuntu 20.04

Kubernetes

1.21.6

安装部署

  1. 克隆官方的sample-controller示例工程
$ git clone https://github.com/resouer/k8s-controller-custom-resource
$ cd k8s-controller-custom-resource
  1. 编译
$ go get github.com/tools/godep
$ godep restore
$ go build -o samplecrd-controller .
  1. 运行Controller

此处是简单的以进程方式运行,后续可以放到Pod中运行

$ ./samplecrd-controller -kubeconfig=$HOME/.kube/config -alsologtostderr=true

启动后可以在标准输出的日志看到设置了event handlers,开启了一个control loop业务循环,同时启动informer来获取并监听kubernetes相关API资源,由于目前还没有提交CRD资源,所以一直报错无法获取资源

Operator技术分析_缓存_02

  1. 执行注册用户自定义资源定义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

Operator技术分析_自定义_03

日志显示启动了一个工作线程来等待处理具体的CR

Operator技术分析_缓存_04

  1. 创建一个用户自定义资源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

Operator技术分析_缓存_05

日志显示工作线程开始工作,执行相关业务,当然由于这是个例子,仅仅是创建了该资源

Operator技术分析_自定义_06

同时在kubernetes集群中也可以看到相关CRD资源和API对象

Operator技术分析_自定义_07

  1. 修改CR资源

修改CR资源

重新执行,由于Controller持续监听该资源的增删改,故日志中也体现资源被修改

Operator技术分析_自定义_08

  1. 删除CR资源

日志同步显示CR资源被删除

Operator技术分析_API_09

四、常见问题

go get命令执行显示没有go.mod文件

Operator技术分析_自定义_10

解决方案

Operator技术分析_API_11

执行go env -w GO111MODULE=off后继续执行命令

godep命令command not found

Operator技术分析_API_12

解决方案

  1. 查看$GOPATH/bin目录下是否有godep二进制文件
  2. go env查看GOBIN的值

Operator技术分析_缓存_13

  1. 执行 export PATH=$GOPATH/bin:$PATH

五、资料出处

六、遗留问题

  1. 将Controller放到Deployment中运行
  2. 源码解析