关于运维:Kubernetes资源编排系列之四-CRDOperator篇

作者 炯思(钟炯恩) 雪尧(郭耀星)

这是咱们的《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团队进行交换。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理