共计 5155 个字符,预计需要花费 13 分钟才能阅读完成。
作者 炯思(钟炯恩) 雪尧(郭耀星)
这是咱们的《Kubernetes 资源编排系列》的第四篇——CRD+Operator 篇。在后面的文章中,经常会提到 CRD 和 k8s operator,但并没有对此进行深刻的探讨。作为 k8s 中的一大亮点,在本篇文章中,咱们会具体开展讲讲。
1. 什么是 CRD
如果 K8S 中的自带资源类型不足以满足业务需要,须要定制开发资源怎么办?自定义资源 (Custom Resource) 由此产生。那么,如何让 Kubernetes 意识这些自定义的资源呢?CRD(Custom Resource Definition)就承当了一个说明书的角色,让 Kubernetes 来意识这个自定义资源 CR。
那么 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: humans.human.sreworks.io
spec:
group: human.sreworks.io
names:
kind: Human
plural: humans
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
description: ...
type: object
properties:
spec:
type: object
properties:
company:
type: string
...
有了 CRD 之后,咱们能够自在地减少各种与 Pod 平级的资源,很多之前须要落在 CMDB 中的数据,也能够被放在 k8s 集群中。这极大地拓宽了咱们的想象力,什么交换机、作业、路由等各种关联的资源都一股脑地放进集群外面去。
在各种自定义资源被放进去之后,就会有人问,这放进去是挺不便的,然而放进去就会失效吗?是的,资源的失效就是 Operator 的功绩。上面咱们就开始介绍 Operator。
2. 什么是 Operator
首先轻易翻看一本词典看一下 operator 这个词的定义:操作员 / 运算符,是个名词。那么,operator 形容的应该是一个围绕 ” 操作、管制 ” 概念的货色。为了让大家有个更直观的意识,咱们来举一个例子,比方 1 + 2 = 3,这个 “+” 就是一个 operator(运算符),这个 “+” 让两个数字产生了一些互动(相加)。
有了词典里的概念铺垫后,咱们持续往下剖析,既然是一种操作或运算,那么在 k8s 中,是谁来操作?而被操作的对象又是什么呢?让咱们来看一下 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 应该就是一个相似控制器的货色,外面含有一些运维操作(前面会持续开展,其实不仅仅是这些)。
较真一点的读者可能会问,既然这样,这货色叫 controller 是不是会更贴切一点呢?事实上,问出这个问题的读者,和假相很靠近了,每个 operator 根本都会有个控制器,但又不仅仅只有一个控制器,还会有后面提到过的资源定义: CRD (CustomResourceDefinition)。每种自定义资源背地都会有一个或多个控制器,让这些资源看起来像活的一样,如上面的 YAML 样例:
这个叫 Bob 的人,生日和性别是不可变属性,无奈批改;而地位是能够批改的,能够从家改到公司,然而改完之后会有一段时间处于不 Ready 的状态,因为他正在去下班的路上。去哪个公司下班呢,他在 helloworld 公司工作,所以他是去这家公司下班。
apiVersion: v1
kind: Human
metadata:
name: Bob
spec:
birth: 648489237
sex: male
location: home
company: helloworld
status:
- lastProbeTime: null
lastTransitionTime: "2022-07-20T08:41:04Z"
status: "True"
type: Ready
通过下面这段 YAML 咱们能够发现,当咱们关注于对象终态的时候,咱们就不太关注这个管制过程,这个 Bob 怎么去下班的,是开车还是地铁去的,其实咱们并不关怀。如果类比到一般的日常实际,也是这样:做一个利用的存储地位迁徙,咱们只须要设置这个利用新的存储地位,至于怎么迁徙过来,是用网络命令传输过来的还是物理上用硬盘拷贝过来咱们不关怀,迁徙过程中数据一致性咱们也不关怀,只晓得会有 operator 把这些都给搞定。
所以,operator 其实是一种架构理念,它区别于常见的 shell 等运维脚本计划:operator 心愿利用可能本人治理本人,而不是由运维人员写一堆脚本从外围来管制他们。不过,如果仅仅是这样,可能 operator 也只能叫 controller 了,只是一些自管制的逻辑而已。从最后面提到的 operator 的概念能够看出,operator 可能让两种以上的资源产生一些互动关系,那么这是如何实现的呢?
咱们持续用下面 Human 的例子再加个 YAML:
这个 helloworld 公司也能够用一个资源对象来形容。如果咱们把这个公司的 isOpen 改成 true,这个 company 会有个控制器来遍历所有的 Human 资源,把 spec.company=”helloworld” 的人 (比方 Bob) 的 location 全改成公司,这样就会让每个公司的人都动起来,想各种方法来公司下班。
apiVersion: v1
kind: Company
metadata:
name: helloworld
spec:
startTime: 932488234
isOpen: false
从下面的例子能够看出,每个控制器只负责本人的那局部,但从顶层往下看,曾经实现了级联管制,可能实现牵一发而动全身的成果。这个就是下面所提到的 operator 的更深一层的机制:可能像运算符一样,让几种资源产生某种互动关系,一起合作实现一些简单的工程动作。
3. 如何实现 K8S Operator
不论是原生 YAML / Helm 还是 Kustomize,都是通过配置来搞定各类事件。然而 CRD + Operator 就不一样了,它们让你间接接入 apiserver,作为 K8S 的一部分监听所有你关怀的对象,并通过代码进行状态维持及治理。因为 CRD 的开发是非常复杂的,除了业务逻辑之外,还须要做很多根底的工作,十分不便,所以有了 Operator 的开发框架(常见的有 KubeBuilder 和 Operator-SDK),让开发人员专一于 CRD 的业务代码开发。
咱们能够来看一下 operator 的架构实现,这个有助于咱们了解 operator 的工作原理:
尽管有了 KubeBuilder 或 Operator-SDK 开发框架,但 Operator 的开发在以后所有的几类组件托管计划当中依然是最为简单的。前前后后须要 CRD 设计及装置,编译 Operator 及部署到集群,最初再下发 CR,外围为了配套这些内容可能还须要下面 Helm 或 Kustomize 的帮助,配合对应的 CICD 流程及工具。
Spark Operator
Spark Operator 是大数据分布式系统在 k8s 场景一次经典的实际。本来 Spark 的作业提交是须要通过 spark-submit 命令,但有了 Spark Operator 之后,咱们能够间接向 k8s 提交作业 YAML,而后 Spark Operator 监听 CR,将这一作业提交给控制器。实现了咱们前文提到的,将作业资源放在 k8s 集群进行治理这一指标。
4. 大数据通用 Operator 设计与实际
上文讲述了 operator 实现的复杂性。不过,咱们发现,越是这样简单的利用,越是会有一些共通性:因为这些简单利用根本都是分布式应用,只是在某些状态或部署程序上的有些非凡需要。于是,咱们针对这个现状,开发了一款通用的大数据 Operator。
这个通用 Operator 的架构设计如下:
与市面上常见的 golang 编写的 operator 不同的是,咱们激励用户不编写代码,而是间接用 yaml 来形容管制逻辑,依照 感知 / 决策 / 执行 三大环节来进行控制器的逻辑合成和编排设计。同时,因为有这几个环节形象的辅助,用户在设计 operator 的时候可能更有目的性,对于简单场景,不引入过多的简单逻辑流,尽量用无状态的形式解决问题。
同时,咱们还借鉴了前端框架 React 中的 VirtualDOM 的设计,在云原生场景下,引入了 VirtualResource 这样的一个概念。VirtualResource 可能将云原生对象资源映射进行 Operator 的内存数据库中,让控制器可能用 SQL 语法疾速查问和操作这些资源对象,简化 Reconcile(和谐)场景的逻辑复杂性。对照 React 框架中生命周期的概念,VirtualResource 也存在生命周期的概念,用户可能管制在资源变动的不同阶段,追加一些自定义的运维形容动作。
咱们在大量应用 helm 的状况下,发现 golang template 语法在进行模板渲染的时候,还是不够灵便。于是咱们把整体架构栈切换到 Python,采纳 jinja2 进行控制器的语法渲染,同时咱们也保留 helm 在渲染框架中,用户可能无缝切换两种渲染引擎。
这个通用 Operator 的控制器将本来须要 golang 编写的管制层逻辑,简化成应用 cmd(指令) + yaml(资源) 的形式进行形容。控制器的形容示例如下:通过 helm 将 vvp 这个利用的所有 yaml 下发,监听 service 的状态变动,同步更新 ingress 资源的状态。
default:
def: crd.yaml
deploy:
- cmd: helm
chart: vvp/vvp
values: vvp/values.yaml
maintain:
- watch:
category: ResourceDidChange
kind: Service
apiVersion: v1
action:
- cmd: kube-patch
file: ingressUpdate.yaml
5. 总结
对于承载 组件 (Component) 这个概念而言,CRD+Operator 能够说是最为简单的,然而又是最万能 的,如果 Helm 或者 Kustomize 无奈满足需要,Operator 基本上是惟一的抉择。另一方面来说,CRD+Operator 个别又会和 Helm / Kustomize 相辅相成一起呈现,最难搞的事件通过 Operator 与 apiserver 交互解决,剩下的胶水粘合,各种 YAML 拼接之类的交给 Helm / Kustomize 搞定。
同时,咱们也能够看出,CRD+Operator 是云原生演进期间的计划,特地适宜本来非 k8s 的软件架构上 k8s。那些本来就在 k8s 架构下呈现的软件计划,会逐步淡化 Operator 这个概念: 所有的工作负载都有能力和 k8s apiserver 交互。
对于承载 SREWorks 中的利用 (Application) 这个概念而言,Operator 是不适合的,无他,太简单了。一般来说,Operator 只有管好本人这个独立性能在 K8S 中的生命周期就曾经足够了。从目前的社区方向来看,Operator 不会作为一整个业务场景利用解决方案去裸提供,而是与 Helm / Kustomize / KubeVela / AppManager 等集成并作为一个整体 (组件 or 利用) 对外公布。
后续文章咱们会分享更多的 Kubernetes 组件和利用管理工具,均会公布在咱们的公众号“阿里智能运维 ”上,请大家继续关注~也欢送大家在公众号后盾留言想理解的内容和感兴趣的相干话题,与SREWorks 团队进行交换。