11.3. 创建基于 Helm 的 Operator

本指南概述了 Operator SDK 中的 Helm Chart 支持,借助示例引导 Operator 作者通过使用现有 Helm Chart 的 operator-sdk CLI 工具来构建和运行 Nginx Operator。

11.3.1. Operator SDK 中的 Helm Chart 支持

Operator Framework 是一个开源工具包,用于以有效、自动化且可扩展的方式管理 Kubernetes 原生应用程序,即 Operator。该框架中包含 Operator SDK,可协助开发人员利用自己的专业知识来引导和构建 Operator,而无需了解 Kubernetes API 复杂性。

通过 Operator SDK 生成 Operator 项目的其中一种方案是利用现有 Helm Chart 来部署 Kubernetes 资源作为统一应用程序,而无需编写任何 Go 代码。这种基于 Helm 的 Operator 非常适合于推出时所需逻辑极少的无状态应用程序,因为更改应该应用于作为 Chart 一部分生成的 Kubernetes 对象。这听起来似乎很有局限性,但就 Kubernetes 社区构建的 Helm Chart 的增长而言,这足以满足它们的大量用例需要。

Operator 的主要功能是从代表应用程序实例的自定义对象中读取数据,并使其所需状态与正在运行的状态相匹配。对于基于 Helm 的 Operator,对象的 spec 字段是一个配置选项列表,通常在 Helm 的 values.yaml 文件中描述。您可以不使用 Helm CLI(如 helm install -f values.yaml)来通过标志设置这些值,而是在自定义资源 (CR) 中表达这些值,因为 CR 作为原生 Kubernetes 对象能够实现应用的 RBAC 以及审核跟踪所带来的好处。

举一个名为 Tomcat 的简单 CR 示例:

apiVersion: apache.org/v1alpha1
kind: Tomcat
metadata:
  name: example-app
spec:
  replicaCount: 2

replicaCount 值(本例中为 2)会通过以下命令传播到 Chart 模板中:

{{ .Values.replicaCount }}

构建并部署完 Operator 后,您可通过新建一个 CR 实例来部署新的应用实例,或使用 oc 命令列出所有环境中运行的不同实例:

$ oc get Tomcats --all-namespaces

不要求使用 Helm CLI 或安装 Tiller;基于 Helm 的 Operator 会从 Helm 项目中导入代码。您要做的只是运行一个 Operator 实例,并使用自定义资源定义 (CRD) 注册 CR。因其遵循 RBAC,所以可以更容易防止生产环境改变。

11.3.2. 安装 Operator SDK CLI

Operator SDK 配有一个 CLI 工具,可协助开发人员创建、构建和部署新的 Operator 项目。您可在工作站上安装 SDK CLI,为编写您自己的 Operator 做准备。

注意

本指南中,minikube v0.25.0+ 用作本地 Kubernetes 集群,Quay.io 用于公共 registry。

11.3.2.1. 从 GitHub 版本安装

您可从 GitHub 上的项目下载并安装 SDK CLI 的预构建发行版文件。

先决条件

  • docker v17.03+
  • 已安装 OpenShift CLI (oc) v4.1+
  • 访问基于 Kubernetes v1.11.3+ 的集群
  • 访问容器 registry

流程

  1. 设置发行版本变量:

    RELEASE_VERSION=v0.8.0
  2. 下载发行版二进制文件。

    • Linux:

      $ curl -OJL https://github.com/operator-framework/operator-sdk/releases/download/${RELEASE_VERSION}/operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu
    • macOS:

      $ curl -OJL https://github.com/operator-framework/operator-sdk/releases/download/${RELEASE_VERSION}/operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin
  3. 验证所下载的发行版本二进制文件。

    1. 下载所提供的 ASC 文件。

      • Linux:

        $ curl -OJL https://github.com/operator-framework/operator-sdk/releases/download/${RELEASE_VERSION}/operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu.asc
      • macOS:

        $ curl -OJL https://github.com/operator-framework/operator-sdk/releases/download/${RELEASE_VERSION}/operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin.asc
    2. 将二进制文件与对应的 ASC 文件放在同一个目录中,并运行以下命令来验证该二进制文件:

      • Linux:

        $ gpg --verify operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu.asc
      • macOS:

        $ gpg --verify operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin.asc

      如果您的工作站上没有维护人员公钥,则会出现以下错误:

      $ gpg --verify operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin.asc
      $ gpg: assuming signed data in 'operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin'
      $ gpg: Signature made Fri Apr  5 20:03:22 2019 CEST
      $ gpg:                using RSA key <key_id> 1
      $ gpg: Can't check signature: No public key
      1
      RSA 密钥字符串。

      要下载密钥,请运行以下命令,用上一条命令输出的 RSA 密钥字符串来替换 <key_id>

      $ gpg [--keyserver keys.gnupg.net] --recv-key "<key_id>" 1
      1
      如果您尚未配置密钥服务器,请使用 --keyserver 选项指定一个密钥服务器。
  4. 在您的 PATH 中安装发行版本二进制文件:

    • Linux:

      $ chmod +x operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu
      $ sudo cp operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu /usr/local/bin/operator-sdk
      $ rm operator-sdk-${RELEASE_VERSION}-x86_64-linux-gnu
    • macOS:

      $ chmod +x operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin
      $ sudo cp operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin /usr/local/bin/operator-sdk
      $ rm operator-sdk-${RELEASE_VERSION}-x86_64-apple-darwin
  5. 验证是否已正确安装 CLI 工具:

    $ operator-sdk version

11.3.2.2. 通过 Homebrew 安装

可使用 Homebrew 来安装 SDK CLI。

先决条件

  • Homebrew
  • docker v17.03+
  • 已安装 OpenShift CLI (oc) v4.1+
  • 访问基于 Kubernetes v1.11.3+ 的集群
  • 访问容器 registry

流程

  1. 使用 brew 命令安装 SDK CLI:

    $ brew install operator-sdk
  2. 验证是否已正确安装 CLI 工具:

    $ operator-sdk version

11.3.2.3. 通过源代码编译并安装

可获取 Operator SDK 源代码来编译和安装 SDK CLI。

先决条件

  • dep v0.5.0+
  • Git
  • Go v1.10+
  • docker v17.03+
  • 已安装 OpenShift CLI (oc) v4.1+
  • 访问基于 Kubernetes v1.11.3+ 的集群
  • 访问容器 registry

流程

  1. 克隆 operator-sdk 存储库:

    $ mkdir -p $GOPATH/src/github.com/operator-framework
    $ cd $GOPATH/src/github.com/operator-framework
    $ git clone https://github.com/operator-framework/operator-sdk
    $ cd operator-sdk
  2. 检查所需的发行版本分支:

    $ git checkout master
  3. 编译并安装 SDK CLI:

    $ make dep
    $ make install

    该操作会在 $GOPATH/bin 中安装 CLI 二进制 operator-sdk

  4. 验证是否已正确安装 CLI 工具:

    $ operator-sdk version

11.3.3. 使用 Operator SDK 来构建基于 Helm 的 Operator

本流程介绍了使用 Operator SDK 中的工具和库来构建由 Helm Chart 提供技术支持的简单 Nginx Operator 的示例。

提示

最好为每个 Chart 新建一个 Operator。如果要在 Go 中编写一个成熟的 Operator,摆脱基于 Helm 的 Operator,这种做法支持更多具有原生行为的 Kubernetes API(如 oc get Nginx),也更灵活。

先决条件

  • 开发工作站已安装 Operator SDK CLI
  • 使用具有 cluster-admin 权限的账户访问基于 Kubernetes 的集群 v1.11.3+(如 OpenShift Container Platform 4.2)
  • 已安装 OpenShift CLI (oc) v4.1+

流程

  1. 使用 operator-sdk new 命令来创建新 Operator 项目,可以是全命名空间范围,也可以是全集群范围。选择以下任意一项:

    1. 全命名空间范围的 Operator(默认)会监视和管理单一命名空间中的资源。全命名空间范围的 Operator 因灵活性高而常被视为首选。这类 Operator 支持解耦升级、针对故障和监控隔离命名空间以及区别化 API 定义。

      要创建基于 Helm 的、全命名空间范围的新 nginx-operator 项目,请使用以下命令:

      $ operator-sdk new nginx-operator \
        --api-version=example.com/v1alpha1 \
        --kind=Nginx \
        --type=helm
      $ cd nginx-operator

      这样会创建一个 nginx-operator 项目,专门用于监视 APIVersion 为 example.com/v1apha1、Kind 为 Nginx 的 Nginx 资源。

    2. 全集群范围的 Operator 会监视并管理整个集群的资源,在某些情况下非常实用。例如,cert-manager Operator 通常会以全集群范围权限和监视功能进行部署,以便管理整个集群的证书颁发。

      要创建全集群范围的 nginx-operator 项目,请使用以下命令:

      $ operator-sdk new nginx-operator \
          --cluster-scoped \
          --api-version=example.com/v1alpha1 \
          --kind=Nginx \
          --type=helm

      使用 --cluster-scoped 标记来构建进行了以下修改的新 Operator:

      • deploy/operator.yaml:设置 WATCH_NAMESPACE="" 而不要将其设置为 Pod 的命名空间。
      • deploy/role.yaml:使用 ClusterRole 来代替 Role
      • deploy/role_binding.yaml

        • 使用 ClusterRoleBinding 来代替 rolebinding
        • 将主题命名空间设置为 REPLACE_NAMESPACE。该命名空间必须改为部署 Operator 的命名空间。
  2. 自定义 Operator 逻辑。

    在本例中,nginx-operator 会针对每个 Nginx 自定义资源 (CR) 执行以下协调逻辑:

    • 如果尚无 Nginx Deployment,请创建一个。
    • 如果尚无 Nginx Service,请创建一个。
    • 如果支持 Nginx Ingress 但尚不存在,请创建一个。
    • 确保 Deployment、Service 和可选的 Ingress 符合 Nginx CR 指定的所需配置(如副本数、镜像、服务类型)。

    默认情况下,nginx-operator 会监视 Vginx 资源事件,如 watches.yaml 文件中所示,并使用指定 Chart 执行 Helm 发行版本:

    - version: v1alpha1
      group: example.com
      kind: Nginx
      chart: /opt/helm/helm-charts/nginx
    1. 查阅 Nginx Helm Chart。

      创建 Helm Operator 项目后,Operator SDK 会创建一个 Helm Chart 示例,其中包含一组模板,用于简单的 Nginx 发行版本。

      本例中,针对 Deployment、Service 和 Ingress 资源提供了模板,另外还有 NOTES.txt 模板,Helm Chart 开发人员可利用该模板传达有关发型版本的实用信息。

      如果您对 Helm Chart 还不够熟悉,请花一点时间查阅 Helm Chart开发人员文档

    2. 了解 Nginx CR spec。

      Helm 会使用一个名为 values 的概念来自定义 Helm Chart 的默认值,具体值在 Helm Chart 的 values.yaml 文件中定义。

      通过在 CR spec 中设置所需值来覆盖这些默认值。以副本数量为例:

      1. 首先,检查 helm-charts/nginx/values.yaml 文件,会发现 Chart 有一个名为 replicaCount 的值,默认设置为 1。要在部署中使用 2 个 Nginx 实例,您的 CR spec 中必须包含 replicaCount: 2

        更新 deploy/crds/example_v1alpha1_nginx_cr.yaml 文件,如下所示:

        apiVersion: example.com/v1alpha1
        kind: Nginx
        metadata:
          name: example-nginx
        spec:
          replicaCount: 2
      2. 同样,服务端口默认设置为 80。要改用 8080,请通过添加服务端口覆盖来再次更新 deploy/crds/example_v1alpha1_nginx_cr.yaml 文件:

        apiVersion: example.com/v1alpha1
        kind: Nginx
        metadata:
          name: example-nginx
        spec:
          replicaCount: 2
          service:
            port: 8080

        Helm Operator 应用整个 spec,将其视为 values 文件内容,与 helm install -f ./overrides.yaml 命令的工作方式类似。

  3. 部署 CRD。

    在运行 Operator 之前,Kubernetes 需要了解 Operator 将会监视的新自定义资源定义 (CRD)。部署以下 CRD:

    $ oc create -f deploy/crds/example_v1alpha1_nginx_crd.yaml
  4. 构建并运行 Operator。

    有两种方式来构建和运行 Operator:

    • 作为 Kubernetes 集群内的一个 Pod。
    • 作为集群外的 Go 程序,使用 operator-sdk up 命令。

    选择以下任一方法:

    1. 作为 Kubernetes 集群内的一个 Pod 来运行。这是生产环境的首先方法。

      1. 构建 nginx-operator 镜像并将其推送至 registry:

        $ operator-sdk build quay.io/example/nginx-operator:v0.0.1
        $ docker push quay.io/example/nginx-operator:v0.0.1
      2. deploy/operator.yaml 文件中会生成 Deployment 清单。本文件中的部署镜像需要从占位符 REPLACE_IMAGE 修改为之前构建的镜像。为此,请运行:

        $ sed -i 's|REPLACE_IMAGE|quay.io/example/nginx-operator:v0.0.1|g' deploy/operator.yaml
      3. 如果使用 --cluster-scoped=true 标记来创建 Operator,请更新所生成的 ClusterRoleBinding 中的服务账户命名空间,以匹配 Operator 的部署位置:

        $ export OPERATOR_NAMESPACE=$(oc config view --minify -o jsonpath='{.contexts[0].context.namespace}')
        $ sed -i "s|REPLACE_NAMESPACE|$OPERATOR_NAMESPACE|g" deploy/role_binding.yaml

        如果要在 OSX 中执行这些步骤,请使用以下命令:

        $ sed -i "" 's|REPLACE_IMAGE|quay.io/example/nginx-operator:v0.0.1|g' deploy/operator.yaml
        $ sed -i "" "s|REPLACE_NAMESPACE|$OPERATOR_NAMESPACE|g" deploy/role_binding.yaml
      4. 部署 nginx-operator

        $ oc create -f deploy/service_account.yaml
        $ oc create -f deploy/role.yaml
        $ oc create -f deploy/role_binding.yaml
        $ oc create -f deploy/operator.yaml
      5. 验证 nginx-operator 是否正在运行:

        $ oc get deployment
        NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
        nginx-operator       1         1         1            1           1m
    2. 在集群外运行。这是开发阶段的首选方法,可加快部署和测试的速度。

      此外,还务必要确保您的计算机上存在 watches.yaml 文件中引用的 Chart 路径。watches.yaml 文件默认能够与通过 operator-sdk build 命令构建的 Operator 镜像一起使用。当使用 operator-sdk up local 命令开发和测试您的 Operator 时,SDK 会在您的本地文件系统中查找该路径。

      1. 在该位置创建符号链接,以指向您的 Helm Chart 路径:

        $ sudo mkdir -p /opt/helm/helm-charts
        $ sudo ln -s $PWD/helm-charts/nginx /opt/helm/helm-charts/nginx
      2. 要使用 $HOME/.kube/config 中的默认 Kubernetes 配置文件在本地运行 Operator:

        $ operator-sdk up local

        要使用所提供的 Kubernetes 配置文件在本地运行 Operator:

        $ operator-sdk up local --kubeconfig=<path_to_config>
  5. 部署 Nginx CR。

    应用之前修改的 Nginx CR:

    $ oc apply -f deploy/crds/example_v1alpha1_nginx_cr.yaml

    确保 nginx-operator 为 CR 创建部署:

    $ oc get deployment
    NAME                                           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    example-nginx-b9phnoz9spckcrua7ihrbkrt1        2         2         2            2           1m

    检查 Pod,确认已创建两个副本:

    $ oc get pods
    NAME                                                      READY     STATUS    RESTARTS   AGE
    example-nginx-b9phnoz9spckcrua7ihrbkrt1-f8f9c875d-fjcr9   1/1       Running   0          1m
    example-nginx-b9phnoz9spckcrua7ihrbkrt1-f8f9c875d-ljbzl   1/1       Running   0          1m

    检查 Service 端口是否已设置为 8080

    $ oc get service
    NAME                                      TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
    example-nginx-b9phnoz9spckcrua7ihrbkrt1   ClusterIP   10.96.26.3   <none>        8080/TCP   1m
  6. 更新 replicaCount 并删除端口。

    spec.replicaCount 字段从 2 改为 3,删除 spec.service 字段并应用更改:

    $ cat deploy/crds/example_v1alpha1_nginx_cr.yaml
    apiVersion: "example.com/v1alpha1"
    kind: "Nginx"
    metadata:
      name: "example-nginx"
    spec:
      replicaCount: 3
    
    $ oc apply -f deploy/crds/example_v1alpha1_nginx_cr.yaml

    确认 Operator 已更改 Deployment 大小:

    $ oc get deployment
    NAME                                           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    example-nginx-b9phnoz9spckcrua7ihrbkrt1        3         3         3            3           1m

    检查 Service 端口是否已设置为默认值 80

    $ oc get service
    NAME                                      TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)  AGE
    example-nginx-b9phnoz9spckcrua7ihrbkrt1   ClusterIP   10.96.26.3   <none>        80/TCP   1m
  7. 清理资源:

    $ oc delete -f deploy/crds/example_v1alpha1_nginx_cr.yaml
    $ oc delete -f deploy/operator.yaml
    $ oc delete -f deploy/role_binding.yaml
    $ oc delete -f deploy/role.yaml
    $ oc delete -f deploy/service_account.yaml
    $ oc delete -f deploy/crds/example_v1alpha1_nginx_crd.yaml

11.3.4. 其他资源