5.6. 基于 Helm 的 Operator

5.6.1. 开始使用基于 Helm 的 Operator 的 Operator SDK

Operator SDK 包括生成一个 Operator 项目的选项,它利用现有 Helm chart 将 Kubernetes 资源部署为统一应用程序,而无需编写任何 Go 代码。

如需演示使用 Operator SDK 提供的工具和库来设置并运行基于 Helm 的 Operator 的基本知识,Operator 开发人员可以为 Nginx 构建一个基于 Helm 的 Operator 示例,并将它部署到集群中。

5.6.1.1. 先决条件

5.6.1.2. 创建并部署基于 Helm 的 Operator

您可以使用 Operator SDK 为 Nginx 构建和部署简单基于 Helm 的 Operator。

流程

  1. 创建一个项目。

    1. 创建您的项目目录:

      $ mkdir nginx-operator
    2. 切换到项目所在的目录:

      $ cd nginx-operator
    3. 使用 helm 插件运行 operator-sdk init 命令以初始化项目:

      $ operator-sdk init \
          --plugins=helm
  2. 创建 API。

    创建简单的 Nginx API:

    $ operator-sdk create api \
        --group demo \
        --version v1 \
        --kind Nginx

    此 API 使用 helm create 命令的内置 Helm Chart 网卡。

  3. 构建并推送 Operator 镜像。

    使用默认的 Makefile 目标来构建和推送 Operator。使用镜像的 pull spec 设置 IMG,该 spec 使用您可推送到的 registry:

    $ make docker-build docker-push IMG=<registry>/<user>/<image_name>:<tag>
  4. 运行 Operator。

    1. 安装 CRD:

      $ make install
    2. 将项目部署到集群中。将 IMG 设置为您推送的镜像:

      $ make deploy IMG=<registry>/<user>/<image_name>:<tag>
  5. 添加安全性上下文约束(SCC)。

    Nginx 服务帐户需要特权访问权限才能在 OpenShift Container Platform 中运行。将以下 SCC 添加到 nginx-sample pod 的服务帐户中:

    $ oc adm policy add-scc-to-user \
        anyuid system:serviceaccount:nginx-operator-system:nginx-sample
  6. 创建示例自定义资源(CR)。

    1. 创建一个示例 CR:

      $ oc apply -f config/samples/demo_v1_nginx.yaml \
          -n nginx-operator-system
    2. 查看 CR 协调 Operator:

      $ oc logs deployment.apps/nginx-operator-controller-manager \
          -c manager \
          -n nginx-operator-system
  7. 删除 CR

    运行以下命令来删除 CR:

    $ oc delete -f config/samples/demo_v1_nginx -n nginx-operator-system
  8. 清理。

    运行以下命令清理在此流程中创建的资源:

    $ make undeploy

5.6.1.3. 后续步骤

5.6.2. 基于 Helm 的 Operator 的 operator SDK 指南

Operator 开发人员可以利用 Operator SDK 中的 Helm 支持来为 Nginx 构建基于 Helm 的 Operator 示例,并管理其生命周期。本教程介绍了以下过程:

  • 创建 Nginx 部署
  • 确保部署大小与 Nginx 自定义资源(CR)spec 指定的大小相同
  • 使用 status writer 带有 nginx Pod 的名称来更新 Nginx CR 状态

通过以下两个 Operator Framework 核心组件来完成此过程:

Operator SDK
operator-sdk CLI 工具和 controller-runtime 库 API
Operator Lifecycle Manager (OLM)
集群中 Operator 的安装、升级和基于角色的访问控制(RBAC)
注意

本教程的内容比基于 Helm 的 Operator 开始使用 Operator SDK的内容更详细。

5.6.2.1. 先决条件

5.6.2.2. 创建一个项目

使用 Operator SDK CLI 创建名为 nginx-operator 的项目。

流程

  1. 为项目创建一个目录:

    $ mkdir -p $HOME/projects/nginx-operator
  2. 进入该目录:

    $ cd $HOME/projects/nginx-operator
  3. 使用 helm 插件运行 operator-sdk init 命令以初始化项目:

    $ operator-sdk init \
        --plugins=helm \
        --domain=example.com \
        --group=demo \
        --version=v1 \
        --kind=Nginx
    注意

    默认情况下,helm 插件使用样板 Helm Chart 初始化项目。您可以使用其他标记(如 --helm-chart 标志)使用现有 Helm chart 初始化项目。

    init 命令创建 nginx-operator 项目,专门用于监视 API 版本为 example.com/v1 和 kind Nginx 的资源。

  4. 对于基于 Helm 的项目,init 命令根据 chart 的默认清单部署的资源,在 config/rbac/role.yaml 文件中生成 RBAC 规则。验证此文件生成的规则是否满足 Operator 的权限要求。
5.6.2.2.1. 现有 Helm chart

您可以使用以下标记,而不是使用样板 Helm Chart 创建项目,而是使用现有 chart(可以从本地文件系统或远程 Chart 仓库中)使用现有 chart:

  • --helm-chart
  • --helm-chart-repo
  • --helm-chart-version

如果指定了 --helm-chart 标志,--group--version--kind 标志将变为可选。如果保留未设置,则使用以下默认值:

标记

--domain

my.domain

--group

charts

--version

v1

--kind

从指定的 chart 中分离

如果 --helm-chart 标志指定本地 chart 归档,如 example-chart-1.2.0.tgz 或目录,则 chart 被验证并解包或复制到项目中。否则,Operator SDK 会尝试从远程存储库中获取 chart。

如果没有通过 --helm-chart-repo 标志指定自定义存储库 URL,则支持以下 chart 引用格式:

格式描述

<repo_name>/<chart_name>

从名为 <repo_name> 的 helm chart 中获取名为 <chart_name> 的 Helm chart,如 $HELM_HOME/repositories/repositories.yaml 文件指定。使用 helm repo add 命令来配置此文件。

<url>

通过指定的 URL 获取 Helm Chart 归档。

如果自定义仓库 URL 由 --helm-chart-repo 指定,则支持以下 chart 引用格式:

格式描述

<chart_name>

在由 --helm-chart-repo URL 值指定的 Helm Chart 仓库中获取名为 <chart_name> 的 Helm Chart。

如果 --helm-chart-version 标志未设置,Operator SDK 会获取最新可用的 Helm Chart 版本。否则,它会获取指定的版本。当使用 --helm-chart 标记指定一个特定版本(例如一个本地路径或 URL)的 chart 时,--helm-chart-version 标志不会被使用。

如需更多详细信息和示例,请运行:

$ operator-sdk init --plugins helm --help
5.6.2.2.2. PROJECT 文件

operator-sdk init 命令生成的文件中是一个 Kubebuilder PROJECT 文件。从项目 root 运行的后续 operator-sdk 命令以及 help 输出可读取该文件,并注意项目类型是 Helm。例如:

domain: example.com
layout:
- helm.sdk.operatorframework.io/v1
plugins:
  manifests.sdk.operatorframework.io/v2: {}
  scorecard.sdk.operatorframework.io/v2: {}
  sdk.x-openshift.io/v1: {}
projectName: nginx-operator
resources:
- api:
    crdVersion: v1
    namespaced: true
  domain: example.com
  group: demo
  kind: Nginx
  version: v1
version: "3"

5.6.2.3. 了解 Operator 逻辑

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

  • 如果尚无 Nginx 部署,请创建一个。
  • 如果尚无 Nginx 服务,请创建一个。
  • 如果被启用且不存在,请创建一个 Nginx ingress。
  • 确保部署、服务和可选入口与 Nginx CR 指定的配置匹配,如副本数、镜像和服务类型。

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

# Use the 'create api' subcommand to add watches to this file.
- group: demo
  version: v1
  kind: Nginx
  chart: helm-charts/nginx
# +kubebuilder:scaffold:watch
5.6.2.3.1. Helm chart 示例

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

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

如果您对 Helm chart 有一定的了解,请参阅 Helm 开发人员文档

5.6.2.3.2. 修改自定义资源规格

Helm 使用名为 values 的概念来自定义 Helm Chart 的默认配置,该 chart 在 values.yaml 文件中定义。

您可以通过在自定义资源(CR)spec 中设置所需的值来覆盖这些默认值。以副本数量为例。

流程

  1. 在默认情况下,helm-charts/nginx/values.yaml 文件有一个设置为 1 的名为 replicaCount 的值。要在部署中有两个 Nginx 实例,您的 CR spec 必须包含 replicaCount: 2

    编辑 config/samples/demo_v1_nginx.yaml 文件以设置 replicaCount: 2

    apiVersion: demo.example.com/v1
    kind: Nginx
    metadata:
      name: nginx-sample
    ...
    spec:
    ...
      replicaCount: 2
  2. 同样,服务端口默认设置为 80。要使用 8080,编辑 config/samples/demo_v1_nginx.yaml 文件来设置 spec.port: 8080,它会添加服务端口覆盖:

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

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

5.6.2.4. 启用代理支持

Operator 作者可开发支持网络代理的 Operator。集群管理员配置对 Operator Lifecycle Manager (OLM) 处理的环境变量的代理支持。要支持代理集群,Operator 必须检查以下标准代理变量的环境,并将值传递给 Operands:

  • HTTP_PROXY
  • HTTPS_PROXY
  • NO_PROXY
注意

本教程使用 HTTP_PROXY 作为示例环境变量。

先决条件

  • 启用了集群范围的出口代理的集群。

流程

  1. 通过添加 overrideValues 字段来编辑 watches.yaml 文件,使其包含基于环境变量的覆盖:

    ...
    - group: demo.example.com
      version: v1alpha1
      kind: Nginx
      chart: helm-charts/nginx
      overrideValues:
        proxy.http: $HTTP_PROXY
    ...
  2. helm-charts/nginx/values.yaml 文件中添加 proxy.http 值:

    ...
    proxy:
      http: ""
      https: ""
      no_proxy: ""
  3. 要确保 Chart 模板支持使用变量,请编辑 helm-charts/nginx/templates/deployment.yaml 文件中的 chart 模板,使其包含以下内容:

    containers:
      - name: {{ .Chart.Name }}
        securityContext:
          - toYaml {{ .Values.securityContext | nindent 12 }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        env:
          - name: http_proxy
            value: "{{ .Values.proxy.http }}"
  4. 通过在 config/manager/manager.yaml 文件中添加以下内容来设置 Operator 部署上的环境变量:

    containers:
     - args:
       - --leader-elect
       - --leader-election-id=ansible-proxy-demo
       image: controller:latest
       name: manager
       env:
         - name: "HTTP_PROXY"
           value: "http_proxy_test"

5.6.2.5. 运行 Operator

您可以使用 Operator SDK CLI 构建和运行 Operator:

  • 作为 Go 程序在集群外本地运行。
  • 作为集群的部署运行。
  • 捆绑 Operator,并使用 Operator Lifecycle Manager(OLM)在集群中部署。
5.6.2.5.1. 在集群外本地运行

您可以作为集群外的 Go 程序运行您的 Operator 项目。这可以加快部署和测试的速度,对于开发非常有用。

流程

  • 运行以下命令,以在 ~/.kube/config 文件中配置的集群中安装自定义资源定义(CRD),并在本地运行 Operator:

    $ make install run

    输出示例

    ...
    {"level":"info","ts":1612652419.9289865,"logger":"controller-runtime.metrics","msg":"metrics server is starting to listen","addr":":8080"}
    {"level":"info","ts":1612652419.9296563,"logger":"helm.controller","msg":"Watching resource","apiVersion":"demo.example.com/v1","kind":"Nginx","namespace":"","reconcilePeriod":"1m0s"}
    {"level":"info","ts":1612652419.929983,"logger":"controller-runtime.manager","msg":"starting metrics server","path":"/metrics"}
    {"level":"info","ts":1612652419.930015,"logger":"controller-runtime.manager.controller.nginx-controller","msg":"Starting EventSource","source":"kind source: demo.example.com/v1, Kind=Nginx"}
    {"level":"info","ts":1612652420.2307851,"logger":"controller-runtime.manager.controller.nginx-controller","msg":"Starting Controller"}
    {"level":"info","ts":1612652420.2309358,"logger":"controller-runtime.manager.controller.nginx-controller","msg":"Starting workers","worker count":8}

5.6.2.5.2. 作为集群的部署运行

您可以作为一个部署在集群中运行 Operator 项目。

流程

  1. 运行以下 make 命令来构建和推送 Operator 镜像。在以下步骤中修改 IMG 参数来引用您可访问的库。您可以获取在存储库站点(如 Quay.io)存储容器的帐户。

    1. 构建镜像:

      $ make docker-build IMG=<registry>/<user>/<image_name>:<tag>
      注意

      由 SDK 为 Operator 生成的 Dockerfile 需要为 go build 明确引用 GOARCH=amd64。这可以在非 AMD64 构架中使用 GOARCH=$TARGETARCH。Docker 自动将环境变量设置为 -platform 指定的值。对于 Buildah,需要使用 -build-arg 来实现这一目的。如需更多信息,请参阅多个架构

    2. 将镜像推送到存储库:

      $ make docker-push IMG=<registry>/<user>/<image_name>:<tag>
      注意

      镜像的名称和标签,如 IMG=<registry> /<user> /<image_name>:<tag>,在两个命令中都可在您的 Makefile 中设置。修改 IMG ?= controller:latest 值来设置您的默认镜像名称。

  2. 运行以下命令来部署 Operator:

    $ make deploy IMG=<registry>/<user>/<image_name>:<tag>

    默认情况下,这个命令会创建一个带有 Operator 项目名称的命名空间,格式为 <project_name>-system,用于部署。此命令还从 config/rbac 安装 RBAC 清单。

  3. 验证 Operator 是否正在运行:

    $ oc get deployment -n <project_name>-system

    输出示例

    NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
    <project_name>-controller-manager       1/1     1            1           8m

5.6.2.5.3. 捆绑 Operator 并使用 Operator Lifecycle Manager 进行部署
5.6.2.5.3.1. 捆绑 Operator

Operator 捆绑包格式是 Operator SDK 和 Operator Lifecycle Manager(OLM)的默认打包方法。您可以使用 Operator SDK 来构建和推送 Operator 项目作为捆绑包镜像,使 Operator 可供 OLM 使用。

先决条件

  • 在开发工作站上安装 operator SDK CLI
  • 已安装 OpenShift CLI(oc)v4.10+
  • 使用 Operator SDK 初始化 operator 项目

流程

  1. 在 Operator 项目目录中运行以下 make 命令来构建和推送 Operator 镜像。在以下步骤中修改 IMG 参数来引用您可访问的库。您可以获取在存储库站点(如 Quay.io)存储容器的帐户。

    1. 构建镜像:

      $ make docker-build IMG=<registry>/<user>/<operator_image_name>:<tag>
      注意

      由 SDK 为 Operator 生成的 Dockerfile 需要为 go build 明确引用 GOARCH=amd64。这可以在非 AMD64 构架中使用 GOARCH=$TARGETARCH。Docker 自动将环境变量设置为 -platform 指定的值。对于 Buildah,需要使用 -build-arg 来实现这一目的。如需更多信息,请参阅多个架构

    2. 将镜像推送到存储库:

      $ make docker-push IMG=<registry>/<user>/<operator_image_name>:<tag>
  2. 运行 make bundle 命令创建 Operator 捆绑包清单,该命令调用多个命令,其中包括 Operator SDK generate bundlebundle validate 子命令:

    $ make bundle IMG=<registry>/<user>/<operator_image_name>:<tag>

    Operator 的捆绑包清单描述了如何显示、创建和管理应用程序。make bundle 命令在 Operator 项目中创建以下文件和目录:

    • 包含 ClusterServiceVersion 对象的捆绑包清单目录,名为 bundle/manifests
    • 名为 bundle/metadata 的捆绑包元数据目录
    • config/crd 目录中的所有自定义资源定义(CRD)
    • 一个 Dockerfile bundle.Dockerfile

    然后,使用 operator-sdk bundle validate 自动验证这些文件,以确保磁盘上的捆绑包的格式是正确的。

  3. 运行以下命令来构建和推送捆绑包镜像。OLM 使用索引镜像来消耗 Operator 捆绑包,该镜像引用一个或多个捆绑包镜像。

    1. 构建捆绑包镜像。使用您要推送镜像的 registry、用户命名空间和镜像标签的详情,设置 BUNDLE_IMG

      $ make bundle-build BUNDLE_IMG=<registry>/<user>/<bundle_image_name>:<tag>
    2. 推送捆绑包镜像:

      $ docker push <registry>/<user>/<bundle_image_name>:<tag>
5.6.2.5.3.2. 使用 Operator Lifecycle Manager 部署 Operator

Operator Lifecycle Manager(OLM)可帮助您在 Kubernetes 集群中安装、更新和管理 Operator 及其相关服务的生命周期。OLM 在 OpenShift Container Platform 上默认安装,并作为 Kubernetes 扩展运行,以便您可以在没有任何额外工具的情况下将 Web 控制台和 OpenShift CLI(oc)用于所有 Operator 生命周期管理功能。

Operator Bundle Format 是 Operator SDK 和 OLM 的默认打包方法。您可以使用 Operator SDK 在 OLM 上快速运行捆绑包镜像,以确保它正确运行。

先决条件

  • 在开发工作站上安装 operator SDK CLI
  • 构建并推送到 registry 的 Operator 捆绑包镜像
  • OLM安装在一个基于 Kubernetes 的集群上(如果使用 apiextensions.k8s.io/v1 CRD,则为 v1.16.0 或更新版本,如 OpenShift Container Platform 4.10)
  • 使用具有 cluster-admin 权限的账户使用 oc 登录到集群

流程

  1. 输入以下命令在集群中运行 Operator:

    $ operator-sdk run bundle \
        [-n <namespace>] \1
        <registry>/<user>/<bundle_image_name>:<tag>
    1
    默认情况下,命令会在 ~/.kube/config 文件中当前活跃的项目中安装 Operator。您可以添加 -n 标志来为安装设置不同的命名空间范围。

    这个命令执行以下操作:

    • 创建引用捆绑包镜像的索引镜像。索引镜像不透明且具有临时性,但准确反映了如何将捆绑包添加到生产中的目录中。
    • 创建指向新索引镜像的目录源,以便 OperatorHub 能够发现 Operator。
    • 通过创建一个 OperatorGroupSubscriptionInstallPlan 和所有其他必要的对象(包括 RBAC),将 Operator 部署到集群中。

5.6.2.6. 创建自定义资源

安装 Operator 后,您可以通过创建一个由 Operator 在集群中提供的自定义资源(CR)来测试它。

先决条件

  • Nginx Operator 示例,它提供了 Nginx CR,在集群中安装

流程

  1. 切换到安装 Operator 的命名空间。例如,如果使用 make deploy 命令部署 Operator:

    $ oc project nginx-operator-system
  2. 编辑 config/samples/demo_v1_nginx.yaml 中的 Nginx CR 清单示例,使其包含以下规格:

    apiVersion: demo.example.com/v1
    kind: Nginx
    metadata:
      name: nginx-sample
    ...
    spec:
    ...
      replicaCount: 3
  3. Nginx 服务帐户需要特权访问权限才能在 OpenShift Container Platform 中运行。将以下安全性上下文约束 (SCC) 添加到 nginx-sample pod 的服务帐户中:

    $ oc adm policy add-scc-to-user \
        anyuid system:serviceaccount:nginx-operator-system:nginx-sample
  4. 创建 CR:

    $ oc apply -f config/samples/demo_v1_nginx.yaml
  5. 确保 Nginx Operator 为示例 CR 创建部署,其大小正确:

    $ oc get deployments

    输出示例

    NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-operator-controller-manager       1/1     1            1           8m
    nginx-sample                            3/3     3            3           1m

  6. 检查 pod 和 CR 状态,以确认其状态是否使用 Nginx pod 名称更新。

    1. 检查 pod:

      $ oc get pods

      输出示例

      NAME                                  READY     STATUS    RESTARTS   AGE
      nginx-sample-6fd7c98d8-7dqdr          1/1       Running   0          1m
      nginx-sample-6fd7c98d8-g5k7v          1/1       Running   0          1m
      nginx-sample-6fd7c98d8-m7vn7          1/1       Running   0          1m

    2. 检查 CR 状态:

      $ oc get nginx/nginx-sample -o yaml

      输出示例

      apiVersion: demo.example.com/v1
      kind: Nginx
      metadata:
      ...
        name: nginx-sample
      ...
      spec:
        replicaCount: 3
      status:
        nodes:
        - nginx-sample-6fd7c98d8-7dqdr
        - nginx-sample-6fd7c98d8-g5k7v
        - nginx-sample-6fd7c98d8-m7vn7

  7. 更新部署大小。

    1. 更新 config/samples/demo_v1_nginx.yaml 文件,将 Nginx CR 中的 spec.size 字段从 3 改为 5

      $ oc patch nginx nginx-sample \
          -p '{"spec":{"replicaCount": 5}}' \
          --type=merge
    2. 确认 Operator 已更改部署大小:

      $ oc get deployments

      输出示例

      NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
      nginx-operator-controller-manager       1/1     1            1           10m
      nginx-sample                            5/5     5            5           3m

  8. 运行以下命令来删除 CR:

    $ oc delete -f config/samples/demo_v1_nginx.yaml
  9. 清理本教程中创建的资源。

    • 如果使用 make deploy 命令来测试 Operator,请运行以下命令:

      $ make undeploy
    • 如果使用 operator-sdk run bundle 命令来测试 Operator,请运行以下命令:

      $ operator-sdk cleanup <project_name>

5.6.2.7. 其他资源

5.6.3. 基于 Helm 的 Operator 的项目布局

operator-sdk CLI 可为每个 Operator 项目生成或 scaffold 多个 软件包和文件。

5.6.3.1. 基于 Helm 的项目布局

使用 operator-sdk init --plugins helm 命令生成的基于 Helm 的 Operator 项目包含以下目录和文件:

文件/文件夹目的

config/

kustomize 清单,用于在 Kubernetes 集群上部署 Operator。

helm-charts/

Helm Chart 使用 operator-sdk create api 命令初始化。

Docker

用于使用 make docker-build 命令构建 Operator 镜像。

watches.yaml

Group/version/kind(GVK)和 Helm Chart 的位置。

Makefile

用于管理项目的目标。

PROJECT

包含 Operator 元数据信息的 YAML 文件。

5.6.4. Operator SDK 中的 Helm 支持

5.6.4.1. Helm chart

通过 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,所以可以更容易防止生产环境改变。

5.6.5. Hybrid Helm Operators Operator SDK 教程

与基于 Go 和基于 Ansible 的 Operator 相比(它们已实现 Operator maturity model 中的 Auto Pilot capability (level V)),Operator SDK 中对标准的基于 Helm 的 Operator 支持有一定限制。

Hybrid Helm Operator 通过 Go API 增强了基于 Helm 的现有支持能力。借助此混合的 Helm 和 Go 方法,Operator SDK 可让 Operator 作者使用以下流程:

  • 在与 Helm 相同的项目中为 Go API生成一个默认的结构或(scaffold)。
  • 通过 Hybrid Helm Operator 提供的库,在项目的 main.go 文件中配置 Helm reconciler。
重要

Hybrid Helm Operator 只是一个技术预览功能。技术预览功能不受红帽产品服务等级协议(SLA)支持,且功能可能并不完整。红帽不推荐在生产环境中使用它们。这些技术预览功能可以使用户提早试用新的功能,并有机会在开发阶段提供反馈意见。

有关红帽技术预览功能支持范围的更多信息,请参阅技术预览功能支持范围

本教程介绍了使用 Hybrid Helm Operator 的以下过程:

  • 如果不存在,使用 Helm chart 创建一个 Memcached
  • 确保部署大小与 Memcached 自定义资源(CR)spec 指定的大小相同
  • 使用 Go API 创建 MemcachedBackup 部署

5.6.5.1. 先决条件

5.6.5.2. 创建一个项目

使用 Operator SDK CLI 创建名为 memcached-operator 的 项目。

流程

  1. 为项目创建一个目录:

    $ mkdir -p $HOME/github.com/example/memcached-operator
  2. 进入该目录:

    $ cd $HOME/github.com/example/memcached-operator
  3. 运行 operator-sdk init 命令以初始化项目。使用域 example.com,所有 API 组都为 <group>.example.com:

    $ operator-sdk init \
        --plugins=hybrid.helm.sdk.operatorframework.io \
        --project-version="3" \
        --domain example.com \
        --repo=github.com/example/memcached-operator

    init 命令根据 chart 的默认清单部署的资源,在 config/rbac/role.yaml 文件中生成 RBAC 规则。验证 config/rbac/role.yaml 文件中生成的规则是否满足您的 Operator 的权限要求。

其他资源

  • 此流程会创建一个与 Helm 和 Go API 兼容的项目结构。要了解更多有关项目目录结构的信息,请参阅项目布局

5.6.5.3. 创建 Helm API

使用 Operator SDK CLI 创建 Memcached API。

流程

  • 运行以下命令创建带有组 cache、版本v1 和种类 Memcached 的 Helm API:

    $ operator-sdk create api \
        --plugins helm.sdk.operatorframework.io/v1 \
        --group cache \
        --version v1 \
        --kind Memcached
注意

此流程还将您的 Operator 项目配置为监视 API 版本 v1Memcached 资源,并构建 boilerplate Helm Chart。除了通过由 Operator SDK 构建的 boilerplate Helm chart 创建项目,也可以使用一个您的本地文件系统或远程 chart 仓库中的现有的 chart 进行创建。

有关基于现有或新 chart 创建 Helm API 的详情和示例,请运行以下命令:

$ operator-sdk create api --plugins helm.sdk.operatorframework.io/v1 --help

其他资源

5.6.5.3.1. Helm API 的 Operator 逻辑

默认情况下,您的构建 Operator 项目会监视 Memcached 资源事件,如 watches.yaml 文件中所示,并使用指定 Chart 执行 Helm 发行版本。

例 5.2. watches.yaml 文件示例

# Use the 'create api' subcommand to add watches to this file.
- group: cache.my.domain
  version: v1
  kind: Memcached
  chart: helm-charts/memcached
#+kubebuilder:scaffold:watch

其他资源

5.6.5.3.2. 使用所提供的库 API 的自定义 Helm reconciler 配置

现有基于 Helm 的 Operator 的缺点是无法配置 Helm reconciler,因为它是从用户中提取的。对于基于 Helm 的 Operator 可访问 Seam 无升级功能(级别 II 及更新的版本),它重复使用已存在的 Helm Chart,在 Go 和 Helm Operator 类型间的混合会添加值。

helm-operator-plugins 库中提供的 API 允许 Operator 作者进行以下配置:

  • 根据集群状态自定义值映射
  • 通过配置协调器的事件记录程序在特定事件中执行代码
  • 自定义协调器的日志记录器
  • 设置 Install, Upgrade, 和 Uninstall 注解,以便根据协调器监视的自定义资源中的注解启用 Helm 的操作
  • 配置协调器以使用 PrePost hook 运行

以上对协调器的配置可在 main.go 文件中完成:

main.go 文件示例

// Operator's main.go
// With the help of helpers provided in the library, the reconciler can be
// configured here before starting the controller with this reconciler.
reconciler := reconciler.New(
 reconciler.WithChart(*chart),
 reconciler.WithGroupVersionKind(gvk),
)

if err := reconciler.SetupWithManager(mgr); err != nil {
 panic(fmt.Sprintf("unable to create reconciler: %s", err))
}

5.6.5.4. 创建 Go API

使用 Operator SDK CLI 创建 Go API。

流程

  1. 运行以下命令,使用组 cache、版本 v1 和 kind MemcachedBackup 创建 Go API:

    $ operator-sdk create api \
        --group=cache \
        --version v1 \
        --kind MemcachedBackup \
        --resource \
        --controller \
        --plugins=go/v3
  2. 提示时,输入 y 来创建资源和控制器:

    $ Create Resource [y/n]
    y
    Create Controller [y/n]
    y

此流程在 api/v1/memcachedbackup_types.gocontrollers/memcachedbackup_controller.go 中生成 MemcachedBackup 资源 API。

5.6.5.4.1. 定义 API

定义 MemcachedBackup 自定义资源(CR)的 API。

通过定义 MemcachedBackup 类型来表示此 Go API,它具有 MemcachedBackupSpec.Size 字段,用于设置要部署的 Memcached 备份实例(CR)数量,以及用于存储 CR 的 pod 名称的 MemcachedBackupStatus.Nodes 字段。

注意

Node 字段用于说明 Status 字段的一个示例。

流程

  1. 通过修改 api/v1/memcachedbackup_types.go 文件中的 Go 类型定义来定义 MemcachedBackup CR 的 API,使其具有以下 specstatus

    例 5.3. api/v1/memcachedbackup_types.go 文件示例

    // MemcachedBackupSpec defines the desired state of MemcachedBackup
    type MemcachedBackupSpec struct {
    	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
    	// Important: Run "make" to regenerate code after modifying this file
    
    	//+kubebuilder:validation:Minimum=0
    	// Size is the size of the memcached deployment
    	Size int32 `json:"size"`
    }
    
    // MemcachedBackupStatus defines the observed state of MemcachedBackup
    type MemcachedBackupStatus struct {
    	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
    	// Important: Run "make" to regenerate code after modifying this file
    	// Nodes are the names of the memcached pods
    	Nodes []string `json:"nodes"`
    }
  2. 为资源类型更新生成的代码:

    $ make generate
    提示

    在修改了 *_types.go 文件后,您必须运行 make generate 命令来更新该资源类型生成的代码。

  3. 使用 specstatus 字段和 CRD 验证标记定义 API 后,生成和更新 CRD 清单:

    $ make manifests

此 Makefile 目标调用 controller-gen 实用程序在 config/crd/bases/cache.my.domain_memcachedbackups.yaml 文件中生成 CRD 清单。

5.6.5.4.2. 控制器实现

本教程中的控制器执行以下操作:

  • 如果尚无 Memcached 部署,请创建一个。
  • 确保部署大小与 Memcached CR spec 指定的大小相同。
  • 使用 memcached Pod 的名称更新 Memcached CR 状态。

有关如何配置控制器来执行上述操作的详情,请参考使用基于 Go 的 Operator 在 Operator SDK 指南中的实施控制器

5.6.5.4.3. main.go 的不同

对于基于 Go 的标准 Operator 和混合 Helm Operator,main.go 文件处理构建 Go API 的 Manager 程序初始化和运行。但是,对于 Hybrid Helm Operator,main.go 文件也会公开加载 watches.yaml 文件和配置 Helm reconciler 的逻辑。

例 5.4. main.go 文件示例

...
	for _, w := range ws {
		// Register controller with the factory
		reconcilePeriod := defaultReconcilePeriod
		if w.ReconcilePeriod != nil {
			reconcilePeriod = w.ReconcilePeriod.Duration
		}

		maxConcurrentReconciles := defaultMaxConcurrentReconciles
		if w.MaxConcurrentReconciles != nil {
			maxConcurrentReconciles = *w.MaxConcurrentReconciles
		}

		r, err := reconciler.New(
			reconciler.WithChart(*w.Chart),
			reconciler.WithGroupVersionKind(w.GroupVersionKind),
			reconciler.WithOverrideValues(w.OverrideValues),
			reconciler.SkipDependentWatches(w.WatchDependentResources != nil && !*w.WatchDependentResources),
			reconciler.WithMaxConcurrentReconciles(maxConcurrentReconciles),
			reconciler.WithReconcilePeriod(reconcilePeriod),
			reconciler.WithInstallAnnotations(annotation.DefaultInstallAnnotations...),
			reconciler.WithUpgradeAnnotations(annotation.DefaultUpgradeAnnotations...),
			reconciler.WithUninstallAnnotations(annotation.DefaultUninstallAnnotations...),
		)
...

管理器使用 HelmGo 协调器初始化:

例 5.5. HelmGo reconcilers 示例

...
// Setup manager with Go API
   if err = (&controllers.MemcachedBackupReconciler{
		Client: mgr.GetClient(),
		Scheme: mgr.GetScheme(),
	}).SetupWithManager(mgr); err != nil {
		setupLog.Error(err, "unable to create controller", "controller", "MemcachedBackup")
		os.Exit(1)
	}

   ...
// Setup manager with Helm API
	for _, w := range ws {

      ...
		if err := r.SetupWithManager(mgr); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "Helm")
			os.Exit(1)
		}
		setupLog.Info("configured watch", "gvk", w.GroupVersionKind, "chartPath", w.ChartPath, "maxConcurrentReconciles", maxConcurrentReconciles, "reconcilePeriod", reconcilePeriod)
	}

// Start the manager
   if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
		setupLog.Error(err, "problem running manager")
		os.Exit(1)
	}
5.6.5.4.4. 权限和 RBAC 清单

控制器需要特定的基于角色的访问控制(RBAC)权限与它管理的资源交互。对于 Go API,它们通过 RBAC 标记来指定,如基于 Go 的标准 Operator 的 Operator SDK 教程所示。

对于 Helm API,在 roles.yaml 中默认构建权限。目前,由于在构建 Go API 时存在一个已知问题,Helm API 的权限会被覆盖。因此,请确保 roles.yaml 中定义的权限与您的要求匹配。

注意

以下是 Memcached Operator 的 role.yaml 示例:

例 5.6. HelmGo reconcilers 示例

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: manager-role
rules:
- apiGroups:
  - ""
  resources:
  - namespaces
  verbs:
  - get
- apiGroups:
  - apps
  resources:
  - deployments
  - daemonsets
  - replicasets
  - statefulsets
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - cache.my.domain
  resources:
  - memcachedbackups
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - cache.my.domain
  resources:
  - memcachedbackups/finalizers
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - pods
  - services
  - services/finalizers
  - endpoints
  - persistentvolumeclaims
  - events
  - configmaps
  - secrets
  - serviceaccounts
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - cache.my.domain
  resources:
  - memcachedbackups/status
  verbs:
  - get
  - patch
  - update
- apiGroups:
  - policy
  resources:
  - events
  - poddisruptionbudgets
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - cache.my.domain
  resources:
  - memcacheds
  - memcacheds/status
  - memcacheds/finalizers
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch

5.6.5.5. 在集群外本地运行

您可以作为集群外的 Go 程序运行您的 Operator 项目。这可以加快部署和测试的速度,对于开发非常有用。

流程

  • 运行以下命令,以在 ~/.kube/config 文件中配置的集群中安装自定义资源定义(CRD),并在本地运行 Operator:

    $ make install run

5.6.5.6. 作为集群的部署运行

您可以作为一个部署在集群中运行 Operator 项目。

流程

  1. 运行以下 make 命令来构建和推送 Operator 镜像。在以下步骤中修改 IMG 参数来引用您可访问的库。您可以获取在存储库站点(如 Quay.io)存储容器的帐户。

    1. 构建镜像:

      $ make docker-build IMG=<registry>/<user>/<image_name>:<tag>
      注意

      由 SDK 为 Operator 生成的 Dockerfile 需要为 go build 明确引用 GOARCH=amd64。这可以在非 AMD64 构架中使用 GOARCH=$TARGETARCH。Docker 自动将环境变量设置为 -platform 指定的值。对于 Buildah,需要使用 -build-arg 来实现这一目的。如需更多信息,请参阅多个架构

    2. 将镜像推送到存储库:

      $ make docker-push IMG=<registry>/<user>/<image_name>:<tag>
      注意

      镜像的名称和标签,如 IMG=<registry> /<user> /<image_name>:<tag>,在两个命令中都可在您的 Makefile 中设置。修改 IMG ?= controller:latest 值来设置您的默认镜像名称。

  2. 运行以下命令来部署 Operator:

    $ make deploy IMG=<registry>/<user>/<image_name>:<tag>

    默认情况下,这个命令会创建一个带有 Operator 项目名称的命名空间,格式为 <project_name>-system,用于部署。此命令还从 config/rbac 安装 RBAC 清单。

  3. 验证 Operator 是否正在运行:

    $ oc get deployment -n <project_name>-system

    输出示例

    NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
    <project_name>-controller-manager       1/1     1            1           8m

5.6.5.7. 创建自定义资源

安装 Operator 后,您可以通过创建由 Operator 在集群中提供的自定义资源(CR)来测试它。

流程

  1. 切换到安装 Operator 的命名空间:

    $ oc project <project_name>-system
  2. 通过将 replicaCount 字段更新为 3,更新 config/samples/cache_v1_memcached.yaml 文件中的 Memcached CR 清单示例:

    例 5.7. config/samples/cache_v1_memcached.yaml 文件示例

    apiVersion: cache.my.domain/v1
    kind: Memcached
    metadata:
      name: memcached-sample
    spec:
      # Default values copied from <project_dir>/helm-charts/memcached/values.yaml
      affinity: {}
      autoscaling:
        enabled: false
        maxReplicas: 100
        minReplicas: 1
        targetCPUUtilizationPercentage: 80
      fullnameOverride: ""
      image:
        pullPolicy: IfNotPresent
        repository: nginx
        tag: ""
      imagePullSecrets: []
      ingress:
        annotations: {}
        className: ""
        enabled: false
        hosts:
        - host: chart-example.local
          paths:
          - path: /
            pathType: ImplementationSpecific
        tls: []
      nameOverride: ""
      nodeSelector: {}
      podAnnotations: {}
      podSecurityContext: {}
      replicaCount: 3
      resources: {}
      securityContext: {}
      service:
        port: 80
        type: ClusterIP
      serviceAccount:
        annotations: {}
        create: true
        name: ""
      tolerations: []
  3. 创建 Memcached CR:

    $ oc apply -f config/samples/cache_v1_memcached.yaml
  4. 确保 Memcached Operator 为示例 CR 创建部署,其大小正确:

    $ oc get pods

    输出示例

    NAME                                  READY     STATUS    RESTARTS   AGE
    memcached-sample-6fd7c98d8-7dqdr      1/1       Running   0          18m
    memcached-sample-6fd7c98d8-g5k7v      1/1       Running   0          18m
    memcached-sample-6fd7c98d8-m7vn7      1/1       Running   0          18m

  5. 通过将 size 更新至 2,更新 config/samples/cache_v1_memcachedbackup.yaml 文件中的 MemcachedBackup CR 清单示例:

    例 5.8. config/samples/cache_v1_memcachedbackup.yaml 文件示例

    apiVersion: cache.my.domain/v1
    kind: MemcachedBackup
    metadata:
      name: memcachedbackup-sample
    spec:
      size: 2
  6. 创建 MemcachedBackup CR:

    $ oc apply -f config/samples/cache_v1_memcachedbackup.yaml
  7. 确保 memcachedbackup pod 的数量与 CR 中指定的相同:

    $ oc get pods

    输出示例

    NAME                                        READY     STATUS    RESTARTS   AGE
    memcachedbackup-sample-8649699989-4bbzg     1/1       Running   0          22m
    memcachedbackup-sample-8649699989-mq6mx     1/1       Running   0          22m

  8. 您可以更新以上每个 CR 中的 spec,然后再次应用它们。控制器再次进行协调,并确保按照相应 CR 的 spec 中指定 pod 的大小。
  9. 清理本教程中创建的资源:

    1. 删除 Memcached 资源:

      $ oc delete -f config/samples/cache_v1_memcached.yaml
    2. 删除 MemcachedBackup 资源:

      $ oc delete -f config/samples/cache_v1_memcachedbackup.yaml
    3. 如果使用 make deploy 命令来测试 Operator,请运行以下命令:

      $ make undeploy

5.6.5.8. 项目布局

混合 Helm Operator 的构建是自定义的,以匹配 Helm 和 Go API。

文件/文件夹目的

Docker

容器引擎使用 make docker-build 命令构建 Operator 镜像的说明。

Makefile

构建包含帮助程序目标的文件,以帮助您操作项目。

PROJECT

包含 Operator 元数据信息的 YAML 文件。代表项目的配置,用于跟踪 CLI 和插件的有用信息。

bin/

包含有用的二进制文件,如管理器( manager )用于在本地运行您的项目,以及用于项目配置的 kustomize 工具。

config/

包含配置文件,其中包括所有 Kustomize 清单,以便在集群上启动 Operator 项目。插件可能会使用它来提供功能。例如,对于 Operator SDK 可以帮助创建 Operator 捆绑包,CLI 会查找在这个目录中构建的 CRD 和 CR。

config/crd/
包含自定义资源定义(CRD)。
config/default/
包含一个 Kustomize 基础,用于在标准配置中启动控制器。
config/manager/
包含清单,作为集群中的 pod 启动 Operator 项目。
config/manifests/
包含要在 bundle/ 目录中生成 OLM 清单的基础。
config/prometheus/
包含启用项目为 Prometheus 提供指标(如 ServiceMonitor 资源)所需的清单。
config/scorecard/
包含允许使用 scorecard 工具测试项目所需的清单。
config/rbac/
包含运行项目所需的 RBAC 权限。
config/samples/
包含自定义资源的示例。

api/

包含 Go API 定义。

controllers/

包含 Go API 的控制器。

hack/

包含实用程序文件,如用于构建项目文件的许可证标头的文件。

main.go

Operator 的主要程序。实例化一个新管理器,它会在 apis/ 目录中注册所有自定义资源定义(CRD),并启动 controllers/ 目录中的所有控制器。

helm-charts/

包含 Helm chart,可以使用带有 Helm 插件的 create api 命令来指定。

watches.yaml

包含 group/version/kind(GVK)和 Helm Chart 位置。用于配置 Helm 监视。