侧边栏壁纸
博主头像
问道

问道的小花园,总能给你带来惊喜

  • 累计撰写 70 篇文章
  • 累计创建 37 个标签
  • 累计收到 6 条评论

kubernetes二次开发系列(4):CRD和operator

问道
2023-02-04 / 0 评论 / 0 点赞 / 1,705 阅读 / 5,788 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2023-02-04,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

定制资源 和 定制控制器

  • 资源(Resource) 是 Kubernetes API 中的一个端点, 其中存储的是某个类别的 API 对象的一个集合。例如内置的 Pod 资源包含一组 Pod 对象。
  • 定制资源(Custom Resource) 是对 Kubernetes API 的扩展, 定制资源所代表的是对特定 Kubernetes 安装的一种定制。不过,很多 Kubernetes 核心功能现在都用定制资源来实现,这使得 Kubernetes 更加模块化。
  • 定制资源可以通过动态注册的方式在运行中的集群内或出现或消失,集群管理员可以独立于集群更新定制资源。
  • 一旦某定制资源被安装,用户可以使用 kubectl 来创建和访问其中的对象, 就像他们为 Pod 这种内置资源所做的一样。

定制控制器

  • 定制资源本身而言,它只能用来存取结构化的数据。当你将定制资源与定制控制器(Custom Controller) 结合时, 定制资源就能够提供真正的声明式 API(Declarative API)
  • Operator 模式就是将定制资源定制控制器相结合的。

什么是CRD

如果 K8S 中的自带资源类型不足以满足业务需求,需要定制开发资源怎么办?自定义资源(Custom Resource)由此产生。那么,如何让Kubernetes认识这些自定义的资源呢?CRD(Custom Resource Definition)就承担了一个说明书的角色,让Kubernetes 来认识这个自定义资源CR。

从 Kubernetes 的用户角度来看,所有东西都叫资源 Resource,就是 Yaml 里的字段 Kind 的内容,例如 Service、Deployment 等。

除了常见内置资源之外,Kubernetes 允许用户自定义资源 Custom Resource,而 CRD 表示自定义资源的定义。

当你创建新的 CustomResourceDefinition(CRD)时,Kubernetes API 服务器会为你所指定的每个版本生成一个新的 RESTful 资源路径

基于 CRD 对象所创建的自定义资源可以是名字空间作用域的,也可以是集群作用域的, 取决于 CRD 对象 spec.scope 字段的设置。

那么CRD是怎么来的呢?最早是谷歌提出Third Party Resource的概念,希望开发者以插件化形式扩展 K8s API 对象模型,以增强整个k8s的生态。基于Third Party Resource这一概念,Kubernetes 社区在 1.7 版本中提出了CRD 的概念。

随便打开一个CRD的YAML可以看到,其主体部分是使用 OpenAPI v3 schema 来描述CR的字段结构,类似编程语言中的强类型声明。

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: lights.light.sreworks.io
spec:
group: light.sreworks.io
names:
kind: Light
plural: lights
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
description: ...
type: object
properties:
spec:
type: object
properties:
company:
type: string
...

有了CRD之后,我们可以自由地增加各种内置资源平级的资源。原本很多之前只维护在软件内部的元数据,也可以被写入到k8s集群中。这极大地拓宽了我们的想象力,比如作业、路由、账号等各种关联的资源都一股脑地放进集群里面去。

在各种自定义资源被放进去之后,就会有人问,这放进去是挺方便的,但是放进去就会生效吗?是的,资源的生效就是Operator的功劳。

什么事kubernetes Operator

让我们来看一下OperatorFramework官网上对于Operator的解释

WHAT IS AN OPERATOR AFTER ALL? An Operator represents human operational knowledge in software, to reliably manage an application. They are methods of packaging, deploying, and managing a Kubernetes application.

从这个定义中,我们可以看到,这个operator是指由人发出的,对k8s应用(Kubernetes application)展开的操作。一般围绕应用的操作有哪些?部署、升级、扩缩容、卸载等等。我们可以先这样理解,operator应该就是个类似控制器的东西,里面含有一些运维操作(后面会继续展开,其实不仅仅是这些)。

Operator 其实并不是一个工具,而是为了解决一个问题而存在的一个思路,将特定于应用程序的操作知识编码到软件中,利用功能强大的Kubernetes抽象来正确地运行和管理应用程序。

Operator 本质上是针对特定的场景去做有状态服务,或者说针对拥有复杂应用的应用场景去简化其运维管理的工具,Operator与特定应用是一对一的关系。

我们把自己的家也用一个自定义资源对象来描述,用来承载一些家中的全局设置。

apiVersion: v1
kind: Home
metadata:
  name: jiongsi-home
spec: 
  nobody: false
  stayOpen: []

当我们家中所有人都出门的时候,家中就没有人了,于是将nobody设为true。然后Home的operator会遍历家中所有的开关、电器、灯等设备,全部都给关上(在YAML上设置power=off)。同时也会根据常亮的策略(stayOpen),保持某些电器不关闭,比如冰箱。

从上面的例子可以看出,每个控制器只负责自己的那部分,但从顶层往下看,已经实现了级联控制,能够实现牵一发而动全身的效果。这个就是上面所提到的operator的更深一层的机制:能够像运算符一样,让几种资源产生某种互动关系,一起协作完成复杂的工程行为。

operator开发框架:kuberbuilder和operator sdk

用于operator开发的的框架有kuberbuilder和operator sdk。

operator sdk和kubebuilder都是为了用户方便创建和管理operator而生的脚手架项目。对于用基于Golang开发的operator项目而言,operator sdk在底层使用了kubebuilder,例如operator sdk的命令行工具底层实际是调用kubebuilder的命令行工具。所以无论由operator sdk还是kubebuilder创建的operator项目都是调用的controller-runtime接口,而有相同的项目布局。

kuberbuilder是kubernetes官方提供的二次开发的框架。

  • 提供脚手架工具初始化 CRDs 工程,自动生成 boilerplate 代码和配置;
  • 提供代码库封装底层的 K8s go-client;

operator sdk则是由 CoreOS 开源,它是用于构建 Kubernetes 原生应用的 SDK,它提供更高级别的 API、抽象和项目脚手架。

kuberbuilder和operator sdk两者之间大同小异,kuberbuilder也在借鉴一些operator sdk好的地方。

两者并不是竞争关系,sdk相当于kubebuilder+; sdk的文档质量更高,感觉sdk更像是商业版的kubebuilder,而实际上它们是开源的;

Operator Framework

Operator Lifecycle Manager: 负责管理具体应用Operator的生命周期

应用业务Operator: 由开发者针对特定应用业务开发的Operator本身

Operator Registry: 存储 CSV (ClusterServiceVersion ) 和自定义资源定义 (CRD) 等构成的应用配置

ClusterServiceVersion (CSV): 由Operator 元数据创建的 YAML 清单,可OLM在集群中运行 Operator

Subscription: 通过跟踪安装包中的channel保证CSV的版本更新

InstallPlan: 计算自动安装或升级 CSV 过程中需创建的资源集合

operator sdk与kubebuilder的区别

operator sdk和kubebuilder都是为了用户方便创建和管理operator而生的脚手架项目。对于用基于Golang开发的operator项目而言,operator sdk在底层使用了kubebuilder,例如operator sdk的命令行工具底层实际是调用kubebuilder的命令行工具。所以无论由operator sdk还是kubebuilder创建的operator项目都是调用的controller-runtime接口,而有相同的项目布局。

除此以外,operator sdk还增加了一些特性。默认情况下,使用operator-sdk init生成的项目集成如下功能:

Operator Lifecycle Manager,安装和管理operator的系统 OperatorHub,发布operator的社区中心 operator sdk scorecard,一个有用的工具,用于确保operator具有最佳实践和开发过程中集群测试 另外,operator sdk除了支持golang以外,还支持Ansible和Helm。

总结:

两者并不是竞争关系,sdk相当于kubebuilder+; sdk的文档质量更高,感觉sdk更像是商业版的kubebuilder,而实际上它们是开源的;

operator的组成

CRD (Custom Resource Definition): 允许用户自定义 Kubernetes 资源,是一个类型;

CR (Custom Resourse): CRD 的一个具体实例;

webhook: 它本质上是一种 HTTP 回调,会注册到 apiserver 上。在 apiserver 特定事件发生时,会查询已注册的 webhook,并把相应的消息转发过去。

按照处理类型的不同,一般可以将其分为两类:一类可能会修改传入对象,称为 mutating webhook;一类则会只读传入对象,称为 validating webhook。

工作队列: controller 的核心组件。它会监控集群内的资源变化,并把相关的对象,包括它的动作与 key,例如 Pod 的一个 Create 动作,作为一个事件存储于该队列中;

**controller **:它会循环地处理上述工作队列,按照各自的逻辑把集群状态向预期状态推动。不同的 controller 处理的类型不同,比如 replicaset controller 关注的是副本数,会处理一些 Pod 相关的事件;

operator:operator 是描述、部署和管理 kubernetes 应用的一套机制,从实现上来说,可以将其理解为 CRD 配合可选的 webhook 与 controller 来实现用户业务逻辑,即 operator = CRD + webhook + controller。

常见的operator工作模式

工作流程:

用户创建一个自定义资源 (CRD); apiserver 根据自己注册的一个 pass 列表,把该 CRD 的请求转发给 webhook; webhook 一般会完成该 CRD 的缺省值设定和参数检验。webhook 处理完之后,相应的 CR 会被写入数据库,返回给用户; 与此同时,controller 会在后台监测该自定义资源,按照业务逻辑,处理与该自定义资源相关联的特殊操作; 上述处理一般会引起集群内的状态变化,controller 会监测这些关联的变化,把这些变化记录到 CRD 的状态中。

如何实现kubernetes Operator

operator虽好,但开发门槛却不低。开发门槛至少体现在如下几个方面:

  • 对operator概念的理解是基于对k8s的理解的基础之上的,而k8s自从2014年开源以来,变的日益复杂,理解起来需要一定时间投入;
  • 从头手撸operator很verbose,几乎无人这么做,大多数开发者都会去学习相应的开发框架与工具,比如:kubebuilder[8]、operator framework sdk[9]等;
  • operator的能力也有高低之分,operator framework就提出了一个包含五个等级的operator能力模型(CAPABILITY MODEL),见下图。使用Go开发高能力等级的operator需要对client-go[10]这个kubernetes官方go client库中的API有深入的了解。

不管是原生 YAML / Helm 还是 Kustomize,都是通过配置来搞定各类事情。然而 CRD + Operator 就不一样了,它们让你直接接入 apiserver,作为 K8S 的一部分监听所有你关心的对象,并通过代码进行状态维持及管理。因为 CRD 的开发是非常复杂的,除了业务逻辑之外,还需要做很多基础的工作,非常不便,所以有了 Operator 的开发框架(常见的有 KubeBuilder 和 Operator-SDK),让开发人员专注于 CRD 的业务代码开发。


我们可以来看一下operator的架构实现,这个有助于我们理解operator的工作原理:

如图可知,Operator内部有个控制器来监听CR的变化,同时由于每个变化对应的函数执行需要一定的耗时,所以引入一个队列来依次执行这些函数。由于整个逻辑的执行链路不同于普通的web服务,所以也需要一个框架来承载请求的流转。

市面上的KubeBuilder 或 Operator-SDK 开发框架可以降低Operator的难度,但 Operator 的开发在当前所有的几类组件托管方案当中仍然是最为复杂的。前前后后需要 CRD 设计及安装,编译 Operator 及部署到集群,最后再下发 CR,外围为了配套这些内容可能还需要上面 Helm 或 Kustomize 的协助,配合对应的 CICD 流程及工具。

0

评论区