×

Operator 开发人员可以利用 Operator SDK 中的 Helm 支持来构建一个用于 Nginx 的基于 Helm 的示例 Operator 并管理其生命周期。本教程将逐步介绍以下流程

  • 创建 Nginx 部署

  • 确保部署大小与Nginx自定义资源 (CR) 规范中指定的大小相同

  • 使用状态写入器更新Nginx CR 状态,其中包含nginx pod 的名称

Red Hat 支持的 Operator SDK CLI 工具版本(包括与 Operator 项目相关的脚手架和测试工具)已弃用,并计划在未来版本的 OpenShift Container Platform 中删除。Red Hat 将在此版本的生命周期内为此功能提供错误修复和支持,但此功能将不再接收增强功能,并将从未来的 OpenShift Container Platform 版本中删除。

不建议使用 Red Hat 支持的 Operator SDK 版本创建新的 Operator 项目。拥有现有 Operator 项目的 Operator 作者可以使用 OpenShift Container Platform 4.17 版本中发布的 Operator SDK CLI 工具版本来维护其项目并创建针对较新版本的 OpenShift Container Platform 的 Operator 版本。

以下与 Operator 项目相关的基础镜像 *未* 被弃用。这些基础镜像的运行时功能和配置 API 仍受支持,用于错误修复和解决 CVE。

  • 基于 Ansible 的 Operator 项目的基础镜像

  • 基于 Helm 的 Operator 项目的基础镜像

有关 OpenShift Container Platform 中已弃用或删除的主要功能的最新列表,请参阅 OpenShift Container Platform 发行说明中的“已弃用和删除的功能”部分。

有关不受支持的社区维护的 Operator SDK 版本的信息,请参见 Operator SDK (Operator Framework).

此过程是使用 Operator Framework 的两个核心部分完成的

Operator SDK

operator-sdk CLI 工具和controller-runtime 库 API

Operator Lifecycle Manager (OLM)

在集群上安装、升级和基于角色的访问控制 (RBAC) Operator

先决条件

  • 已安装 Operator SDK CLI

  • 已安装 OpenShift CLI (oc) 4.17+

  • 使用具有 cluster-admin 权限的帐户通过 oc 登录到 OpenShift Container Platform 4.17 集群

  • 为了允许集群拉取镜像,您推送镜像的仓库必须设置为公共仓库,或者您必须配置镜像拉取密钥

创建项目

使用 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 图表初始化项目。您可以使用其他标志(例如 --helm-chart 标志)来使用现有 Helm 图表初始化项目。

    init 命令专门为监视具有 API 版本 example.com/v1 和类型 Nginx 的资源创建 nginx-operator 项目。

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

现有 Helm 图表

您可以使用以下标志,使用本地文件系统或远程图表存储库中的现有图表,而不是使用样板 Helm 图表创建项目

  • --helm-chart

  • --helm-chart-repo

  • --helm-chart-version

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

标志

--domain

my.domain

--group

charts

--version

v1

--kind

从指定的图表中推断

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

如果 --helm-chart-repo 标志未指定自定义存储库 URL,则支持以下图表引用格式

格式 说明

<repo_name>/<chart_name>

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

<url>

在指定的 URL 获取 Helm 图表存档。

如果 --helm-chart-repo 指定了自定义存储库 URL,则支持以下图表引用格式

格式 说明

<chart_name>

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

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

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

$ operator-sdk init --plugins helm --help

PROJECT 文件

由 `operator-sdk init` 命令生成的多个文件中有 Kubebuilder `PROJECT` 文件。随后在项目根目录下运行的 `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"

理解 Operator 逻辑

在此示例中,`nginx-operator` 项目为每个 `Nginx` 自定义资源 (CR) 执行以下协调逻辑:

  • 如果不存在,则创建 Nginx 部署。

  • 如果不存在,则创建 Nginx 服务。

  • 如果已启用且不存在,则创建 Nginx Ingress。

  • 确保部署、服务和可选的 Ingress 与 `Nginx` CR 中指定的所需配置匹配,例如副本数量、镜像和服务类型。

默认情况下,`nginx-operator` 项目监视 `watches.yaml` 文件中显示的 `Nginx` 资源事件,并使用指定的 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

示例 Helm Chart

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

在此示例中,提供了部署、服务和 Ingress 资源的模板,以及一个 `NOTES.txt` 模板,Helm Chart 开发人员可以使用它来传达有关发布的有用信息。

如果您还不熟悉 Helm Chart,请查看 Helm 开发文档

修改自定义资源规范

Helm 使用一个称为 values 的概念来提供对 Helm Chart 默认值的自定义,这些默认值在 `values.yaml` 文件中定义。

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

步骤
  1. `helm-charts/nginx/values.yaml` 文件中有一个名为 `replicaCount` 的值,默认设置为 `1`。要在您的部署中拥有两个 Nginx 实例,您的 CR 规范必须包含 `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 将应用整个规范,就好像它是 values 文件的内容一样,就像 `helm install -f ./overrides.yaml` 命令一样。

启用代理支持

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

  • HTTP_PROXY

  • HTTPS_PROXY

  • NO_PROXY

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

先决条件
  • 一个启用了集群范围出口代理的集群。

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

    ...
    - 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"

运行 Operator

您可以使用 Operator SDK CLI 以三种方式构建和运行您的 Operator:

  • 作为 Go 程序在集群外部本地运行。

  • 作为部署在集群上运行。

  • 打包您的 Operator 并使用 Operator Lifecycle Manager (OLM) 在集群上部署。

在集群外部本地运行

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

步骤
  • 运行以下命令以在 `~/.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}

作为部署在集群上运行

您可以将您的 Operator 项目作为部署在您的集群上运行。

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

    1. 构建镜像

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

      SDK 为 Operator 生成的 Dockerfile 明确引用了 `GOARCH=amd64` 用于 `go build`。这可以修改为 `GOARCH=$TARGETARCH` 以用于非 AMD64 架构。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

打包 Operator 并使用 Operator Lifecycle Manager 部署

打包 Operator

Operator 包格式是 Operator SDK 和 Operator Lifecycle Manager (OLM) 的默认打包方法。您可以通过使用 Operator SDK 将您的 Operator 项目构建并推送为包镜像,使其准备好用于 OLM。

先决条件
  • 在开发工作站上安装了 Operator SDK CLI

  • 安装了 OpenShift CLI ( `oc` ) v4.17+

  • 使用 Operator SDK 初始化了 Operator 项目

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

    1. 构建镜像

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

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

    2. 将镜像推送到仓库

      $ make docker-push IMG=<registry>/<user>/<operator_image_name>:<tag>
  2. 通过运行 `make bundle` 命令创建您的 Operator 包清单,该命令将调用多个命令,包括 Operator SDK `generate bundle` 和 `bundle validate` 子命令。

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

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

    • 一个名为 bundle/manifests 的 Bundle 清单目录,其中包含一个 ClusterServiceVersion 对象。

    • 一个名为 bundle/metadata 的 Bundle 元数据目录。

    • config/crd 目录中的所有自定义资源定义 (CRD)。

    • 一个 Dockerfile 文件 bundle.Dockerfile

    然后,这些文件将使用 operator-sdk bundle validate 自动验证,以确保磁盘上的 Bundle 表示正确。

  3. 通过运行以下命令来构建和推送您的 Bundle 镜像。OLM 使用索引镜像来使用 Operator Bundle,该索引镜像引用一个或多个 Bundle 镜像。

    1. 构建 Bundle 镜像。使用注册表、用户命名空间和您打算推送镜像的镜像标签的详细信息设置 BUNDLE_IMG

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

      $ docker push <registry>/<user>/<bundle_image_name>:<tag>

使用 Operator Lifecycle Manager 部署 Operator

Operator Lifecycle Manager (OLM) 帮助您在 Kubernetes 集群上安装、更新和管理 Operator 及其关联服务的生命周期。OLM 在 OpenShift Container Platform 上默认安装,并作为 Kubernetes 扩展运行,因此您可以使用 Web 控制台和 OpenShift CLI (oc) 来执行所有 Operator 生命周期管理功能,无需任何其他工具。

Operator Bundle 格式是 Operator SDK 和 OLM 的默认打包方法。您可以使用 Operator SDK 快速在 OLM 上运行 Bundle 镜像,以确保其正常运行。

先决条件
  • 在开发工作站上安装了 Operator SDK CLI

  • 已构建并推送到注册表的 Operator Bundle 镜像。

  • 安装在基于 Kubernetes 的集群上的 OLM(如果您使用 apiextensions.k8s.io/v1 CRD,例如 OpenShift Container Platform 4.17,则版本为 v1.16.0 或更高版本)。

  • 使用具有 cluster-admin 权限的帐户使用 oc 登录到集群。

步骤
  • 输入以下命令在集群上运行 Operator:

    $ operator-sdk run bundle \(1)
        -n <namespace> \(2)
        <registry>/<user>/<bundle_image_name>:<tag> (3)
    1 run bundle 命令会创建一个有效的基于文件的目录并使用 OLM 在您的集群上安装 Operator Bundle。
    2 可选:默认情况下,该命令会将 Operator 安装在您 ~/.kube/config 文件中当前活动的项目中。您可以添加 -n 标志来设置安装的不同命名空间范围。
    3 如果您未指定镜像,则该命令将使用 quay.io/operator-framework/opm:latest 作为默认索引镜像。如果您指定镜像,则该命令将使用 Bundle 镜像本身作为索引镜像。

    从 OpenShift Container Platform 4.11 开始,run bundle 命令默认支持 Operator 目录的基于文件的目录格式。已弃用的 Operator 目录的 SQLite 数据库格式仍然受支持;但是,它将在将来的版本中删除。建议 Operator 作者将其工作流程迁移到基于文件的目录格式。

    此命令执行以下操作:

    • 创建一个引用您的 Bundle 镜像的索引镜像。索引镜像是不透明且短暂的,但准确地反映了如何在生产环境中将 Bundle 添加到目录。

    • 创建一个指向您的新索引镜像的目录源,这使 OperatorHub 能够发现您的 Operator。

    • 通过创建 OperatorGroupSubscriptionInstallPlan 和所有其他必需的资源(包括 RBAC)来将您的 Operator 部署到您的集群。

创建自定义资源

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

先决条件
  • 在集群上安装的示例 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 中运行。为 nginx-sample pod 的服务帐户添加以下安全上下文约束 (SCC):

    $ 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>