在前面的文章中,常常会提到 CRD 和 K8s operator,但并没有对此进行深入的探讨。作为k8s中的一大亮点,在本篇文章中,我们会详细展开讲讲。
1、什么是CRD
如果 K8S 中的自带资源类型不足以满足业务需求,需要定制开发资源怎么办?自定义资源(Custom Resource)由此产生。那么,如何让 Kubernetes 认识这些自定义的资源呢?CRD(Custom Resource Definition)就承担了一个说明书的角色,让 Kubernetes 来认识这个自定义资源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
...
2、什么是Operator
首先随便翻看一本词典看一下 operator 这个词的定义:操作员/运算符,是个名词。那么,operator 描述的应该是一个围绕”操作、控制”概念的东西。为了让大家有个更直观的认识,我们来举一个例子,比如 1 + 2 = 3,这个 “+” 就是一个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.
apiVersion: v1
kind: Light
metadata:
name: bedroom
spec:
power: on
brightness: 70
colorTemperature: 5000k
从名字可以看出这盏灯被放在卧室(bedroom),当power=on的时候电灯打开,power=off的时候电灯关闭,修改亮度(brightness)和色温(colorTemperature)能操纵这盏灯在打开状态下的视觉效果。
通过上面这段灯的YAML我们可以发现,在CRD+operator的场景下,我们可以只关注对象终态,而不去关注其中的控制过程。比如当前家中网络不太稳定,要花1-2秒,重试3次operator才能成功下发指令打开灯,这些重试我们是不感知的。我们只知道只要将power设置为on,灯就会亮。类比到k8s的日常实践,也是这样:一个Pod被放到集群后,控制器会想方设法去克服困难: 从仓库拉取镜像,启动工作负载,如果crash掉了就立即重试,直到稳定运行为止。我们只关心这个Pod是否最终拉起可用。
所以,operator其实是一种架构理念,它区别于常见的shell等运维脚本方案:operator希望应用能够自管理,而不是由运维人员写脚本从外围来控制他们。不过,如果仅仅是这样,可能operator也只能叫controller了,只是一些自控制的逻辑而已。从最前面提到的operator的概念可以看出,operator能够让两种以上的资源产生一些互动关系,那么这是如何实现的呢? 我们继续用上面的灯的例子再加个YAML让大家感受一下:
我们把自己的家也用一个自定义资源对象来描述,用来承载一些家中的全局设置。apiVersion: v1
kind: Home
metadata:
name: jiongsi-home
spec:
nobody: false
stayOpen: []
当我们家中所有人都出门的时候,家中就没有人了,于是将nobody设为true。然后Home的operator会遍历家中所有的开关、电器、灯等设备,全部都给关上(在YAML上设置power=off)。同时也会根据常亮的策略(stayOpen),保持某些电器不关闭,比如冰箱。
从上面的例子可以看出,每个控制器只负责自己的那部分,但从顶层往下看,已经实现了级联控制,能够实现牵一发而动全身的效果。这个就是上面所提到的operator的更深一层的机制:能够像运算符一样,让几种资源产生某种互动关系,一起协作完成复杂的工程行为。 3、如何实现K8S Operator
不管是原生 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 流程及工具。 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这层概念: 所有的工作负载都有对应的资源定义(CRD),他们都有能力和k8s apiserver交互。 对于承载 SREWorks 中的应用 (Application) 这个概念而言,Operator 是不合适的,无他,太复杂了。一般来说,Operator 只要管好自己这个独立功能在 K8S 中的生命周期就已经足够了。从目前的社区方向来看,Operator 不会作为一整个业务场景应用解决方案去裸提供,而是与 Helm/Kustomize/KubeVela/AppManager(SREWorks中OAM实现)等集成并作为一个整体(组件 or 应用)对外发布。
来源:阿里智能运维,点击查看原文。
2022年10月,GOPS 全球运维大会 2022 · 上海站,字节、小红书、ebay、中通等互联网一线运维经验,扫码解锁更多精彩~
<< 滑动查看下一张图片 >>
近期好文: 因违反数据保护条例,Meta接4亿天价罚单;贵州核酸检测系统崩溃:云上贵州回应;GitHub将关闭Trending|一周IT资讯
“高效运维”公众号诚邀广大技术人员投稿
投稿邮箱:[email protected],或添加联系人微信:greatops1118。 点个“在看”,一年不宕机 原文始发于微信公众号(高效运维):自定义你的 Kubernetes 资源:一文细说 CRD+Operator
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论