Kubernetes Operator
Operator 是 Kubernetes 的扩展软件, 它利用定制资源管理应用及其组件。 Operator 遵循 Kubernetes 的理念,特别是在控制器方面。
通俗点理解Operator就是为了解决我们对资源的自动化控制、管理,例如我们可以定义一个crd,来实现当我们创建了一个deploy的时候自动为我们创建svc和ingress;也可以定义个crd,来实现拉起一套中间件。
名词解释
GVK/GVR
GVK 就是 group、verison、kind
golang中,资源数据的存储都是以结构体存储(称为 Go type)。由于多版本version的存在(alpha1,beta1,v1等),不同版本中存储结构体的存在着差异,但是我们都会给其相同的 Kind 名字(比如 Deployment)。
因此,我们编码中只用 Kind 名(如 Deployment),并不能准确获取到其使用哪个版本结构体。所以, GVK 的三个信息(group/verion/kind) 确定一个 Go type(结构体)
GVR 就是 group、version、resource
我们通过yaml来创建资源,会包括 apiversion 和 kind,其实就是 GVK。kubectl 与 apiserver 通信是将请求发送到一个url的,这个 http path 其实就是 GVR,例如:/apis/batch/v1/namespaces/default/job。其实 GVR 是由 GVK 转化而来,通过REST映射的RESTMappers实现。
GVR/GVK的含义
kubernetes API的分组可以分为无组名资源
(/apis/v1/pods
)和有组名资源
(/apis/apps/v1/deployments
),无组名资源
也被称为核心资源组
,core group,相当于/apis/core/v1/pods
。在后面的client-go中可以看到,无组名资源都在core下面。
- G(Group组):资源组,包含一组资源操作的集合,比如apps等。
- V(Version版本):资源版本,用于区分不同API的稳定程度和兼容性,比如v1、v1alpha1等。
- R(Resources资源):资源信息,用于区别不同的资源API,k8s中有很多资源,比如pod、deployment、ingress等。
- K(Kind类别):资源对象的类型,每个资源对象都需要Kind来区分它自身代表的资源类型。
Custom Resource 定制资源
定制资源(Custom Resource) 是对 Kubernetes API 的扩展,就像Pod
资源一样,例如我定义个了一个serverinfo的资源,那么我就可以使用kubectl get serverinfo
来获取它。
Custom Controller 定制控制器
就定制资源本身而言,它只能用来存取结构化的数据。 当你将定制资源与定制控制器(Custom Controller) 结合时, 定制资源就能够提供真正的声明式 API(Declarative API)。
Custom Resource Definitions 定制资源定义
Kubernetes 1.7之后,提供了CRD(CustomResourceDefinitions)自定义资源的二次开发能力来扩展kubernetes API,通过此扩展可以向kubernetes API中增加新的资源类型,会比修改kubernetes apiserver的源代码或创建自定义的apiserver来的更加的简洁和容。通过kubectl get crd
可以查看。
k8s扩展资源类型的方式:
- 第一种是CRD,crd是k8s内置的资源类型,通过crd资源可以将用户自定义资源类型转换为k8s上资源类型;
- 第二种是自定义apiserver,这种方式是复用 Kubernetes 的一些特性的同时,自由度最高的方式。可以自定义存储等,同时保有一定程度的公共特性。Cloud TiDB 的实现就是通过自定义 API server 进行的;
- 第三种方式就是修改现有k8s apiserver的源码,让其支持对应用户自定义资源类型;
进行自定义资源类型,只能把对应资源类型的定义信息写入到etcd中,不能让对应自定义类型资源实例化为一个自定义资源对象,它不能真正的跑起来,我们还需要一个自定义控制器controller,将对应资源实例化为k8s上的资源对象,通过API Server提供的接口实时的对指定的resource进行监听和执行的动作(watch,diff,action)。
定义一个crd
以下 RESTful API 端点(gvk)会被创建在/apis/example.com/v1/namespaces/*/demos/...
yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
# 名字必需与下面的 spec 字段匹配,并且格式为 '<名称的复数形式>.<组名>'
name: demos.example.com
spec:
# 组名称,用于 REST API: /apis/<组>/<版本>
group: example.com
names:
# 名称的复数形式,用于 URL:/apis/<组>/<版本>/<名称的复数形式>
plural: demos
# 名称的单数形式,作为命令行使用时和显示时的别名
singular: demo
# kind 通常是单数形式的帕斯卡编码(PascalCased)形式。你的资源清单会使用这一形式。
kind: Demo
# shortNames 允许你在命令行使用较短的字符串来匹配资源
shortNames:
- dm
categories:
- all
# 可以是 Namespaced 或 Cluster
scope: Namespaced
# 列举此 CustomResourceDefinition 所支持的版本
versions:
- name: v1
# 每个版本都可以通过 served 标志来独立启用或禁止
served: true
# 其中一个且只有一个版本必需被标记为存储版本
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
name:
type: string
pattern: '^test' # test开头
additionalPrinterColumns:
- name: CR-Name # crd的列名
type: string
jsonPath: .spec.name # 通过哪个字段获取值
bash
$ kubectl apply -f crd.yaml
$ kubectl get crd demos.example.com
NAME CREATED AT
demos.example.com 2023-03-10T14:16:58Z
根据crd创建资源
yaml
apiVersion: "example.com/v1"
kind: Demo
metadata:
name: crd-demo
spec: # jsonPath定义了.spec.name
name: test # properties 中的定义名称的规则
创建资源后,可以根据plural、singular或者shortNames来获取crd资源,且不区分大小写
bash
$ kubectl get dm # dm、demo、demos都可以
NAME CR-NAME # additionalPrinterColumns
crd-demo test
crd-demo11 test11
Operator
Operator
是一种包装、运行和管理k8s应用的一种方式。它涵盖了 CRD (CustomResourceDeftination) + AdmissionWebhook + Controller ,并以 Deployment 的形式部署到K8S中。
CRD Operator = kubernetes CRD + AdmissionWebhook + custom controller
- CRD 用来定义声明式API(yaml),程序会通过该定义一直让最小调度单元(POD)趋向该状态;
- AdmissionWebhook 用来拦截请求做 mutate(修改)提交的声明(yaml)和 validate(校验)声明式的字段;
- Controller 主要的控制器,监视资源的 创建 / 更新 / 删除 事件,并触发
Reconcile
函数作为响应。整个调整过程被称作Reconcile Loop
(协调一致的循环),其实就是让 POD 趋向CRD定义所需的状态;
用户创建一个资源,实际上是把k8s抽象的资源根据资源清单(yaml文件)做实例化。具体过程如下:
- 用户的资源请求发送给apiserver,通过apiserver的认证、授权、准入控制以后,通过apiserver把对应的资源定义信息存放在etcd中;
- 对应资源类型的控制器一般被称为 controller或operator,controller通过watch机制监听apiserver上的资源变动,通过对应资源变动事件触发对应类型资源的控制器从etcd中读取对应资源的定义,并将对应资源创建出来,并通过控制器内部的和解循环(control loop)监控着对应资源状态是否和用户定义的期望状态一样;如果发现不一样,内部和解循环就会被触发,对应的控制器会向apiserver发起创建资源的请求,将对应资源重建,让对应资源的状态始终满足用户期望的状态。
最基础的oprator
go
package main
func main() {
// config
// client
// informer
// add envent handler
// informer.start
}