目录

    1. 缘起

    最初,有两名 CoreOS 的员工,为了更方便部署 etcd 集群,在 etcdCluster 对象的增、删、改事件上绑定了相应的逻辑操作,借助 Kubernetes 来自动化管理 etcd 集群。

    在几个月之后的 KubeCon 大会上,他们分享了这种称之为 Operator 的方案,得到社区的强烈回响。随后,大量项目宣布支持以 Operator 的方式进行运行和管理。

    但来自 Google 的 Kubernetes 核心开发者并不认同 Operator。理由是,Operator 破坏了 Kubernetes 原有的设计,游离于 Controller Manager 之外,不受控制。

    就在核心开发者准备放弃 Operator 之际,CoreOS 的 CTO 在社区发起征集令,收集使用这种方式的项目。由于使用的项目太多,Kubernetes 最终接纳了 Operator。

    2. 原理

    Operator 就是 CRD + Controller。CRD 定义用户的资源;Controller 监听 CRD 对象实例的增、删、改事件,然后执行相应的业务逻辑。

    Kubernetes 中的每个资源都是一个 API 对象的集合。除了内置的资源类型,用户还可以自定义资源类型对 Kubernetes API 进行扩展。自定义资源,也可以直接使用 API 或 kubectl 进行操作。

    Operator 仅依赖于 Kubernetes 申明式 API 和 Controller 的能力,实现了用户资源与具体操作的定制化关联。

    2.1 CRD

    Kubernetes 中的基础资源类型有 Pod、Service、Job、Deployment 等,表达能力有限。Kubernetes 提供了内建的类型 CRD(CustomResourceDefinition),用于自定义资源。 下面是一个定义资源和创建对象的例子:

    1,创建新的资源类型

    resourcedefinition.yaml:

    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      # name must match the spec fields below, and be in the form: <plural>.<group>
      name: crontabs.stable.example.com
    spec:
      # group name to use for REST API: /apis/<group>/<version>
      group: stable.example.com
      # version name to use for REST API: /apis/<group>/<version>
      version: v1
      # either Namespaced or Cluster
      scope: Namespaced
      names:
        # plural name to be used in the URL: /apis/<group>/<version>/<plural>
        plural: crontabs
        # singular name to be used as an alias on the CLI and for display
        singular: crontab
        # kind is normally the CamelCased singular type. Your resource manifests use this.
        kind: CronTab
        # shortNames allow shorter string to match your resource on the CLI
        shortNames:
        - ct
    

    执行命令:

    kubectl apply -f resourcedefinition.yaml
    

    Kubernetes 会在 /apis/stable.example.com/v1/namespaces/*/crontabs/... 端点,新建 RESTful API。

    1. 创建自定义对象:

    my-crontab.yaml

    apiVersion: "stable.example.com/v1"
    kind: CronTab
    metadata:
      name: my-new-cron-object
    spec:
      cronSpec: "* * * * */5"
      image: my-awesome-cron-image
    

    执行命令:

    kubectl apply -f my-crontab.yaml
    
    1. 查看对象:
    kubectl get crontab
    

    2.2 Controller

    下面是 Controller 的实现逻辑:

    一个 Controller 有一个或多个 Informer 来跟踪某一个资源。Informer 与 apiserver 保持通讯,一旦发现资源发生变化,立即调用 Callbacks,将对象数据放入 Workqueue 中。

    Workqueue 作为 Worker 的任务队列。Worker 首先会比较 Workerqueue 中资源对象的状态与预期状态的差别,然后通过 client-go 向 apiserver 发送执行请求,直到达成预期状态。

    3. 用途

    Operator 项目的初衷是,开发者将运维能力固化在代码中,让运维更容易。核心在于对领域能力的实现和封装。

    对于无状态应用的部署和管理,Kubernetes 得心应手。而有状态应用往往存在拓扑关系,对某些外部资源有着绑定性的依赖。虽然 Kubernetes 内置了 StatefulSet 有状态对象,但要求开发者在启动命令中添加大量领域逻辑,增加了使用难度。

    Operator 的出现,为应用的动态描述提出了一套行之有效的实现规范。

    Operator 将分布式应用的使用门槛降到了最低。无论一个分布式应用多么复杂,只要它为用户提供了 Operator ,那么只需要两条命令即可搞定,以 kafka 为例:

    kubectl apply -f kafka-operator.yaml
    kubectl apply -f kafka-cluster.yaml
    

    Operator 的用途是管理有状态分布式应用,例如数据库、缓存、监控等。

    4. 如何开发 Operator

    4.1 KubeBuilder

    使用 client-go 作为 Kubernetes 的客户端,用 KubeBuilder 来生成骨架代码。

    KubeBuilder 封装和抽象了 controller-runtime 和 controller-tools ,用于快速构建 Operator。通过 KubeBuilder 生成 Operator 的脚手架,开发者不必关注 apiserver 通信、请求队列化等细节,只需要专注于业务逻辑的实现。

    KubeBuilder 的工作流程如下:

    1. 创建一个新的工程目录
    2. 创建一个或多个资源 API CRD ,然后将字段添加到资源
    3. 在控制器中实现协调循环(reconcile loop),watch 额外的资源
    4. 在集群中运行测试(自动安装 CRD 并自动启动控制器)
    5. 更新引导集成测试测试新字段和业务逻辑
    6. 使用用户提供的 Dockerfile 构建和发布容器

    4.2 Operator Framework

    Operator Framework 是 CoreOS 提供的 Operator 开发框架。主要包含两个部分:

    • Operator SDK ,用于开发 Operator
    • Operator Lifecycle Manager OLM ,安装、更新和管理 Operator

    Operator SDK 提供以下工作流开发 Operator:

    1. 使用 SDK 创建一个新的 Operator 项目
    2. 通过添加自定义资源(CRD)定义新的资源 API
    3. 指定使用 SDK API 来 watch 的资源
    4. 定义 Operator 的协调(reconcile)逻辑
    5. 使用 Operator SDK 构建并生成 Operator 部署清单文件

    5. 参考