Operator 基础原理和概念
什么是operator
定义
operator是coreos 公司工程师在2016年提出,就是可以根据应用独有的领域逻辑编写的自定义控制器,
如何理解operator?
k8s的资源类型实现都要满足俩个条件:
- 对资源类型的模型抽象,比如创建deployment 的yaml中的定义
- 实际去处理这个资源类型抽象的控制器,例如namespace控制器,deployment控制器。并通过restful api 对外提供能力。
上面这种资源设计方式叫做“声明式API”
operator就是采用上面的模式实现,主要组成有:模型抽象-CRD、具体业务逻辑动作的处理-controller。
对于使用者来说,提交了定义好的CRD对象来描述期望的状态之后,无需关注处理过程,关注结果即可,过程由controller处理。
相关概念
CRD(costom resource definition): 自定义资源
controller:控制器
group/version: api组 api版本
Kind/resouce: api类型 kind的实例
GVK: 定义一种资源的方式,通过GVK的信息(group/version/kind)确定一个具体资源类型,体现在restful api 交互上
GVR: 实例化GVK定义的资源类型
GVK和GVR的转换:GVR通过rest mapper映射到对应的GVK
api资源路径格式:/api/apps/v1/namespace/$namespace/job
-
“api/apps” : 组
-
“v1”: 版本
-
“job”: 资源
什么是controller
简单来说,就是控制器,控制k8s的资源实体。
client-go原理
kubernetes官方在2016年八月把k8s资源操作相关核心源码抽离出来,组成了一个新的项目,client-go。
client-go是k8s集群资源操作的编程式交互客户端库,通过与api server进行交互完成资源操作。
client-go主要用于内置、自定义资源的增删查改操作,通过client-go提供的能力,就可以实现controller的能力,所以学习client-go,对我们理解controller很重要。
目录结构
.
├── CHANGELOG.md
├── CONTRIBUTING.md
├── INSTALL.md
├── LICENSE
├── OWNERS
├── README.md
├── SECURITY_CONTACTS
├── applyconfigurations
├── code-of-conduct.md
├── discovery # 包含discovery客户端,用于发现api server 支持的资源信息
├── doc.go
├── dynamic # 包含dynamic 客户端,用户对自定义k8s资源执行通过操作
├── examples #client-go使用示例
├── go.mod
├── go.sum
├── informers # 包含各种资源的informer实现
├── kubernetes #包含k8s内置资源的clientset
├── kubernetes_test
├── listers #提供监听服务
├── metadata
├── openapi
├── pkg
├── plugin
├── rest
├── restmapper
├── scale
├── testing
├── third_party
├── tools #与util一起提供常用工具,便于编写controller
├── transport #提供安全连接功能
└── util
主体结构
client共支持4中与api server交互的客户端逻辑。如下
- restclient:对http请求以及相关操作进行封装
- clientset:k8s内置资源的客户端集合,仅能操作内置资源
- discovery client:发现api server支持的资源组、资源版本和资源信息。(kubectl api-version 主要使用discovery client)
- dynamic client:对任意k8s资源执行操作。
架构
client-go主要用于k8s控制其中,包括内置控制器(kube-controller-manager)和CRD控制器。client提供了编写自定义controller所使用的各种机制,如下
-
list-watch机制
- 功能:把k8s中的对象资源存储到本地并实时更新,拥有很高的实时性、可靠性和顺序性。
- list:调用list restful api,短链接实现,获取资源信息
- watch:调用watch restful api,长链接实现,获取事件类型和最新的资源信息
-
reflector:使用list-watch 方法监听指定类型的资源对象,通过list获取所有实例的resouceversion,并监听在这个版本后面所有的变化,并把收到的event用反射机制处理为监控的实体对象,即把GVK转为go type
-
deltafifo:上面得到的event及它对应的实体对象组合成为增量delt。
-
localStore:通过event类型,创建和更新本地缓存,并建立索引提供快速查找的能力indexer,可以减少api server压力。
-
workqueue:deltafifo同步完localstore后,会把这个event pop到内部的controller的回调函数resourehandler,进行简单的过滤工作,最后吧变更的对象放入workqueue中,供worker控制循环处理。
-
Worker:控制循环,work执行真正的业务逻辑,通过对比状态进行动作处理
kububuilder原理
什么是kubebuilder
kubebuilder是一个用go语言构建kubernetes apis的框架,通过这一套编程框架,可以便捷的使用crd构建api、controller和admission webhook,实现对k8s自定义资源的扩展。
架构
-
Kubebuilder Scaffolds是实现这个脚手架最核心的逻辑,它借助 API Scaffolder对象模块,实现了 CRD的 Template和 Controller的核心代码块。
-
用户主要关注Userdefined 模块,需要根据实际场景,设计 CRD的结构定义,当然这里的 CRD的数量可以有多个。
-
用户还需要实现 Reconcile的逻辑。这里,首先了解 Reconcile的含义,用户自定义了CRD结构,而在 Kubernetes集群中,想要实现这样的 CRD 结构定义,Reconcile 需要协调逻辑。举例来说,假设用户定义了 MysqlCluster{Name:demo,Num:3} 这样的结构体,而希望在系统中创建MySQL的集群,而构造 MySQL 集群的构造过程,就是 Reconcile过程做的工作。
-
运行环境,用户自定义的部分能工作的前提是要有一个 Kubernetes集群,即架构中最下面的部分,它负责安装 CRD及运行 Controller。
-
controller runtime负责运行controller,包含了schema、manager、client、cache等核心模块。
- schema。在Controller Runtime模块中,Kubebuilder构建出来的 CRD会注册到 Scheme模块,schema模块提供了Kinds与对应的 GoType的映射,即给定了GoType,就能够知道它的GKV(GroupKindVerision),这也是Kubernetes所有资源的注册模式。举例来说,我们给定了一个Scheme,“demo1.example.org/v1”.Demo{},这个GoType映射到demo1.example.org/v1的 DemoGVK。
{ "apiVersion":"demo1.example.org/v1","kind":"Demo", "metadata":{ ... }
通过这个 GoType,能够正确地获取 GVR的信息,从而提供给 Controller, 获取期望的状态,即协调的逻辑。
-
manager,controller总控,负责初始化一些公共模块以及controller运行管理。
在Controller Runtime中Controller最依赖的除了Scheme之外,还包括 Manager 的初始化、安装和启动工作。Manager 的初始化依赖 Controller Runtime库初始化 Manager对象,包括 Client、Cache 等模块的生成工作。然后调用Client就可以实现对CRD的“增、删、改、查”,而查询的逻辑是通过本地的Cache 模块实现的。这里的Cache 负责监听CRD 的变化,它是通过监听Scheme,从而收集所有与 Controller有关的GVR 资源,并创建对应的监听器,从而实现当监听到Kubernetes集群中的CRD发生变化触发 Controller的协调进程Reconcile工作。
-
Kuberbuilder工具生成的内容还包括 Finalizer,它用于处理 Kubernetes资源的预删除逻辑,保障资源被删除后能够从 Cache中读取到,清理相关的其他资源;
-
OwnerReference用于清理资源时, 对于任何一个对象, 若它的 OwnerReference字段值为待删除对象,则这个对象也会被清理,支持对象的变更,也会触发 Owner对象的Controller 的协调过程。
-
Index 用于提供资源的缓存,提升客户端资源的查询效率。
目录结构
.
├── api ## 这里定义了 sample 的结构体 GVK,以及所需的 deepcopy 实现
│ └── v1
│ ├── groupversion_info.go
│ ├── sample_types.go
│ └── zz_generated.deepcopy.go
├── bin
│ └── manager ## controller 编译后的 二进制文件
├── config ## 包含了我们在使用 crd 是可能需要的 yml 文件,包括rbac、controller的deployment 等
│ ├── certmanager
│ ├── crd
│ ├── default
│ ├── manager
│ ├── prometheus
│ ├── rbac
│ ├── samples #crd资源类型的部署yaml
│ └── webhook
├── controllers ## 我们的controller 逻辑就放在这里
│ ├── sample_controller.go
│ └── suite_test.go
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│ └── boilerplate.go.txt
├── main.go
├── Makefile #编译打包工具
└── PROJECT
代码流程讲解
-
CRD创建
- crd go type定义
- reconcile 协调逻辑
-
manager 初始化
- ctrl.NewManager -> controller runtime manager.new -> 初始化cache schema client等模块
-
controller 初始化
- SetupWithManager 安装crd到manager。-> controller runtime builder方法初始化controllerManager对象 -> 进一步关联crd gotype -> complate方法完成controllermanager 对象的构建,包括do controller(传递reconcile) ,do watch,实现了基于schema和controllerManager对象的CRD的注册和监听流程。
- do controller 完成controller的创建并注册到mgr,关联reconcile
- do watch doWatch会可以watch多种资源类型,controller的Watch函数启动监控对象,其根据eventhandler(监控资源对象入队Controller.Queue前需要被EventHandler处理)、监控资源source生成watchDescription结构并添加到controller的watches数组中, 实现监控资源与Controller的绑定,等待controllerManager的启动
-
client初始化
- NewManager -> New -> setoptionsdefault 初始化默认的client -> 初始化读client ->初始化写client
- 传递给controller, 初始化client -> 传给每个crd controller -> SetupWithManager 完成controller初始化
-
manager启动
- 启动controller生产端,启动cache -> 启动所有watch -> 启动controller,controlle.start -> 启动source,完成informer的创建、并将事件回调与informer关联起来。
- 启动controller消费端 -> processNextWorkItem -> Do.Reconcile(req)
-
Finalizers,是每种资源在声明周期结束时都会使用到的字段,属于k8s GC垃圾回收器,是一种删除拦截机制,可以执行一些预删除处理,需要在reconcile中实现。
-
运行逻辑:Finalizers字段不为空时,delete -> update,更新deletetimestamp 字段,之后,如果再次检测发现finalizers为空,k8s GC可以删除该资源。
-
**使用姿势:**创建对象时定义好finalizer字段,任意string,删除资源的时候,update deletiontimestamp字段,执行所有的pre-hook操作,然后将finalizes字段值为空
-
核心模块介绍
-
controller runtime
-
manager
-
controller
-
client
-
cache
-
webhook
参考文献
《云原生应用开发 Operator原理与实践》