作者 炯思(钟炯恩) 雪尧(郭耀星)
这是咱们的《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团队进行交换。
发表回复