×

集群服务版本 (CSV) 由ClusterServiceVersion对象定义,它是由 Operator 元数据创建的 YAML 清单,可帮助 Operator Lifecycle Manager (OLM) 在集群中运行 Operator。它是伴随 Operator 容器镜像的元数据,用于使用其徽标、描述和版本等信息填充用户界面。它也是运行 Operator 所需的技术信息的来源,例如它所需的 RBAC 规则以及它管理或依赖的自定义资源 (CR)。

Operator SDK 包括 CSV 生成器,用于为当前 Operator 项目生成 CSV,并使用 YAML 清单和 Operator 源文件中的信息进行自定义。

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

不推荐使用 Red Hat 支持的 Operator SDK 版本创建新的 Operator 项目。拥有现有 Operator 项目的 Operator 作者可以使用 OpenShift Dedicated 发布的 Operator SDK CLI 工具版本来维护他们的项目并创建针对较新版本的 OpenShift Dedicated 的 Operator 版本。

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

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

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

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

CSV 生成命令消除了 Operator 作者需要深入了解 OLM 才能使其 Operator 与 OLM 交互或将元数据发布到 Catalog Registry 的责任。此外,由于随着新的 Kubernetes 和 OLM 功能的实现,CSV 规范可能会随着时间的推移而发生变化,因此 Operator SDK 能够轻松扩展其更新系统以处理未来的新 CSV 功能。

CSV 生成工作原理

操作符捆绑清单,包括集群服务版本 (CSV),描述了如何使用 Operator Lifecycle Manager (OLM) 显示、创建和管理应用程序。Operator SDK 中的 CSV 生成器(由generate bundle子命令调用)是将您的 Operator 发布到目录并使用 OLM 部署它的第一步。该子命令需要某些输入清单来构建 CSV 清单;所有输入都在命令调用时与 CSV 基准一起读取,以便幂等地生成或重新生成 CSV。

通常,会先运行generate kustomize manifests子命令来生成generate bundle子命令使用的输入Kustomize 基准。但是,Operator SDK 提供了make bundle命令,它自动化了多个任务,包括按顺序运行以下子命令:

  1. generate kustomize manifests

  2. generate bundle

  3. bundle validate

其他资源
  • 请参阅捆绑 Operator,了解包含生成捆绑包和 CSV 的完整流程。

生成的文和资源

make bundle命令会在您的 Operator 项目中创建以下文件和目录:

  • 一个名为bundle/manifests的捆绑清单目录,其中包含一个ClusterServiceVersion (CSV) 对象。

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

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

  • 一个 Dockerfile bundle.Dockerfile

CSV 中通常包含以下资源:

角色 (Role)

定义 Operator 在命名空间内的权限。

集群角色 (ClusterRole)

定义集群范围的 Operator 权限。

部署 (Deployment)

定义如何在 Pod 中运行 Operator 的操作对象。

自定义资源定义 (CRD)

定义您的 Operator 调和的自定义资源。

自定义资源示例

符合特定 CRD 规范的资源示例。

版本管理

generate bundle子命令的--version标志在首次创建捆绑包和升级现有捆绑包时,为您的捆绑包提供语义版本。

通过在您的Makefile中设置VERSION变量,当make bundle命令运行generate bundle子命令时,将自动使用该值调用--version标志。CSV 版本与 Operator 版本相同,升级 Operator 版本时会生成新的 CSV。

手动定义的 CSV 字段

许多 CSV 字段无法使用非 Operator SDK 特定的生成的通用清单来填充。这些字段大多是关于 Operator 和各种自定义资源定义 (CRD) 的人工编写的元数据。

Operator 作者必须直接修改其集群服务版本 (CSV) YAML 文件,向以下必需字段添加个性化数据。当检测到任何必需字段中缺少数据时,Operator SDK 会在 CSV 生成期间发出警告。

下表详细说明了哪些 CSV 字段是必需的,哪些是可选的。

表 1. 必需的 CSV 字段
字段 描述

metadata.name

此 CSV 的唯一名称。应在名称中包含 Operator 版本以确保唯一性,例如app-operator.v0.1.1

metadata.capabilities

根据 Operator 成熟度模型的能力级别。选项包括Basic InstallSeamless UpgradesFull LifecycleDeep InsightsAuto Pilot

spec.displayName

用于标识 Operator 的公共名称。

spec.description

对 Operator 功能的简短描述。

spec.keywords

描述 Operator 的关键字。

spec.maintainers

维护 Operator 的个人或组织实体,包含nameemail

spec.provider

Operator 的提供者(通常是组织),包含name

spec.labels

Operator 内部使用的键值对。

spec.version

Operator 的语义版本,例如0.1.1

spec.customresourcedefinitions

Operator 使用的任何 CRD。如果deploy/中存在任何 CRD YAML 文件,则 Operator SDK 会自动填充此字段。但是,CRD 清单规范中缺少的几个字段需要用户输入。

  • description:CRD 的描述。

  • resources:CRD 利用的任何 Kubernetes 资源,例如PodStatefulSet对象。

  • specDescriptors:Operator 输入和输出的 UI 提示。

表 2. 可选的 CSV 字段
字段 描述

spec.replaces

此 CSV 替换的 CSV 名称。

spec.links

与 Operator 或正在管理的应用程序相关的 URL(例如,网站和文档),每个 URL 都包含nameurl

spec.selector

Operator 可以用来配对集群中资源的选择器。

spec.icon

Operator 独有的 base64 编码图标,设置在base64data字段中,并带有mediatype

spec.maturity

此版本软件已达到的成熟度级别。选项包括planningpre-alphaalphabetastablematureinactivedeprecated

有关上述每个字段应包含哪些数据的更多详细信息,请参阅CSV 规范

目前需要用户干预的几个 YAML 字段可以从 Operator 代码中解析。

Operator 元数据注解

Operator 开发人员可以在集群服务版本 (CSV) 的元数据中设置某些注解,以启用功能或在用户界面 (UI) 中突出显示功能,例如 OperatorHub 或Red Hat 生态系统目录。通过设置 CSV YAML 文件中的metadata.annotations字段来手动定义 Operator 元数据注解。

基础设施功能注解

features.operators.openshift.io组中的注解详细说明了 Operator 可能支持的基础设施功能,通过设置"true""false"值来指定。用户可以通过 Web 控制台或Red Hat 生态系统目录中的 OperatorHub 发现 Operator 时,查看和筛选这些功能。这些注解在 OpenShift Dedicated 4.10 及更高版本中受支持。

features.operators.openshift.io基础设施功能注解弃用了在早期版本的 OpenShift Dedicated 中使用的operators.openshift.io/infrastructure-features注解。有关更多信息,请参阅“已弃用的基础设施功能注解”。

表 3. 基础设施功能注解
注解 描述 有效值[1]

features.operators.openshift.io/disconnected

指定 Operator 是否支持被镜像到断开的目录中,包括所有依赖项,并且不需要互联网访问。Operator 利用spec.relatedImages CSV 字段通过其摘要引用任何相关的镜像。

"true""false"

features.operators.openshift.io/fips-compliant

指定操作符是否接受底层平台的 FIPS-140 配置并在引导到 FIPS 模式的节点上运行。在此模式下,操作符及其管理的任何工作负载(操作数)仅调用已提交 FIPS-140 验证的 Red Hat Enterprise Linux (RHEL) 加密库。

"true""false"

features.operators.openshift.io/proxy-aware

指定操作符是否支持在代理后面的集群上运行,方法是接受标准的HTTP_PROXYHTTPS_PROXY代理环境变量。如果适用,操作符会将其信息传递给它管理的工作负载(操作数)。

"true""false"

features.operators.openshift.io/tls-profiles

指定操作符是否实现众所周知的可调参数来修改操作符及其管理的任何工作负载(操作数)使用的 TLS 密码套件。

"true""false"

features.operators.openshift.io/token-auth-aws

指定操作符是否支持通过使用云凭证操作符 (CCO) 使用 AWS 安全令牌服务 (STS) 对 AWS API 进行令牌化身份验证的配置。

"true""false"

features.operators.openshift.io/token-auth-azure

指定操作符是否支持通过使用云凭证操作符 (CCO) 使用 Azure 托管标识对 Azure API 进行令牌化身份验证的配置。

"true""false"

features.operators.openshift.io/token-auth-gcp

指定操作符是否支持通过使用云凭证操作符 (CCO) 使用 GCP 工作负载身份基础架构 (WIF) 对 Google Cloud API 进行令牌化身份验证的配置。

"true""false"

features.operators.openshift.io/cnf

指定操作符是否提供云原生网络功能 (CNF) Kubernetes 插件。

"true""false"

features.operators.openshift.io/cni

指定操作符是否提供容器网络接口 (CNI) Kubernetes 插件。

"true""false"

features.operators.openshift.io/csi

指定操作符是否提供容器存储接口 (CSI) Kubernetes 插件。

"true""false"

  1. 有效值故意用双引号显示,因为 Kubernetes 注解必须是字符串。

包含基础设施特性注解的示例 CSV
apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
metadata:
  annotations:
    features.operators.openshift.io/disconnected: "true"
    features.operators.openshift.io/fips-compliant: "false"
    features.operators.openshift.io/proxy-aware: "false"
    features.operators.openshift.io/tls-profiles: "false"
    features.operators.openshift.io/token-auth-aws: "false"
    features.operators.openshift.io/token-auth-azure: "false"
    features.operators.openshift.io/token-auth-gcp: "false"
其他资源

已弃用的基础设施特性注解

从 OpenShift Dedicated 4.14 开始,operators.openshift.io/infrastructure-features 组的注解已被 features.operators.openshift.io 命名空间的注解组弃用。虽然我们鼓励您使用较新的注解,但目前同时使用这两组注解都是可以接受的。

这些注解详细说明了操作符支持的基础设施特性。用户可以通过 Web 控制台或 Red Hat 生态系统目录 中的 OperatorHub 查看和筛选这些特性来发现操作符。

表 4. 已弃用的 operators.openshift.io/infrastructure-features 注解
有效的注解值 描述

disconnected

操作符支持镜像到脱机目录中,包括所有依赖项,并且不需要互联网访问。操作符列出了镜像所需的所有相关镜像。

cnf

操作符提供云原生网络功能 (CNF) Kubernetes 插件。

cni

操作符提供容器网络接口 (CNI) Kubernetes 插件。

csi

操作符提供容器存储接口 (CSI) Kubernetes 插件。

fips

操作符接受底层平台的 FIPS 模式并在引导到 FIPS 模式的节点上运行。

在运行以 FIPS 模式引导的 Red Hat Enterprise Linux (RHEL) 或 Red Hat Enterprise Linux CoreOS (RHCOS) 时,OpenShift Dedicated 核心组件仅在 x86_64、ppc64le 和 s390x 架构上使用已提交给 NIST 进行 FIPS 140-2/140-3 验证的 RHEL 加密库。

proxy-aware

操作符支持在代理后面的集群上运行。操作符接受标准的代理环境变量 HTTP_PROXYHTTPS_PROXY,当集群配置为使用代理时,操作符生命周期管理器 (OLM) 会自动将其提供给操作符。必需的环境变量会传递给管理工作负载的操作数。

包含 disconnectedproxy-aware 支持的示例 CSV
apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
metadata:
  annotations:
    operators.openshift.io/infrastructure-features: '["disconnected", "proxy-aware"]'

其他可选注解

以下操作符注解是可选的。

表 5. 其他可选注解
注解 描述

alm-examples

提供具有最小配置集的自定义资源定义 (CRD) 模板。兼容的 UI 为用户预填充此模板以进一步自定义。

operatorframework.io/initialization-resource

通过在操作符安装期间将operatorframework.io/initialization-resource注解添加到集群服务版本 (CSV) 来指定单个必需的自定义资源。然后提示用户通过 CSV 中提供的模板创建自定义资源。必须包含包含完整 YAML 定义的模板。

operatorframework.io/suggested-namespace

设置建议的操作符部署命名空间。

operatorframework.io/suggested-namespace-template

Namespace对象设置清单,其中包含为指定的命名空间设置的默认节点选择器。

operators.openshift.io/valid-subscription

用于列出使用操作符所需的任何特定订阅的自由格式数组。例如,'["3Scale Commercial License", "Red Hat Managed Integration"]'

operators.operatorframework.io/internal-objects

隐藏 UI 中并非用于用户操作的 CRD。

包含 OpenShift Dedicated 许可证要求的示例 CSV
apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
metadata:
  annotations:
    operators.openshift.io/valid-subscription: '["OpenShift Container Platform"]'
包含 3scale 许可证要求的示例 CSV
apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
metadata:
  annotations:
    operators.openshift.io/valid-subscription: '["3Scale Commercial License", "Red Hat Managed Integration"]'

为受限网络环境启用您的操作符

作为操作符作者,您的操作符必须满足其他要求才能在受限网络或脱机环境中正常运行。

支持脱机模式的操作符要求
  • 用环境变量替换硬编码的镜像引用。

  • 在操作符的集群服务版本 (CSV) 中

    • 列出您的操作符可能执行其功能所需的任何相关镜像或其他容器镜像。

    • 通过摘要 (SHA) 而不是标签来引用所有指定的镜像。

  • 操作符的所有依赖项也必须支持在脱机模式下运行。

  • 您的操作符不应要求任何集群外资源。

先决条件
  • 具有 CSV 的操作符项目。以下过程使用 Memcached 操作符作为 Go、Ansible 和基于 Helm 的项目的示例。

步骤
  1. config/manager/manager.yaml文件中操作符使用的附加镜像引用设置环境变量

    config/manager/manager.yaml文件示例
    ...
    spec:
      ...
        spec:
          ...
          containers:
          - command:
            - /manager
            ...
            env:
            - name: <related_image_environment_variable> (1)
              value: "<related_image_reference_with_tag>" (2)
    1 定义环境变量,例如RELATED_IMAGE_MEMCACHED
    2 设置相关的镜像引用和标签,例如docker.io/memcached:1.4.36-alpine
  2. 在您的 Operator 项目类型相关的文件中,将硬编码的镜像引用替换为环境变量。

    • 对于基于 Go 的 Operator 项目,请将环境变量添加到controllers/memcached_controller.go文件中,如下例所示。

      controllers/memcached_controller.go文件示例
        // deploymentForMemcached returns a memcached Deployment object
      
      ...
      
      	Spec: corev1.PodSpec{
              	Containers: []corev1.Container{{
      -			Image:   "memcached:1.4.36-alpine", (1)
      +			Image:   os.Getenv("<related_image_environment_variable>"), (2)
      			Name:    "memcached",
      			Command: []string{"memcached", "-m=64", "-o", "modern", "-v"},
      			Ports: []corev1.ContainerPort{{
      
      ...
      1 删除镜像引用和标签。
      2 使用os.Getenv函数调用<相关镜像环境变量>

      如果未设置变量,则os.Getenv函数将返回空字符串。请在修改文件之前设置<相关镜像环境变量>

    • 对于基于 Ansible 的 Operator 项目,请将环境变量添加到roles/memcached/tasks/main.yml文件中,如下例所示。

      roles/memcached/tasks/main.yml文件示例
      spec:
        containers:
        - name: memcached
          command:
          - memcached
          - -m=64
          - -o
          - modern
          - -v
      -   image: "docker.io/memcached:1.4.36-alpine" (1)
      +   image: "{{ lookup('env', '<related_image_environment_variable>') }}" (2)
          ports:
            - containerPort: 11211
      
      ...
      1 删除镜像引用和标签。
      2 使用lookup函数调用<相关镜像环境变量>
    • 对于基于 Helm 的 Operator 项目,请将overrideValues字段添加到watches.yaml文件中,如下例所示。

      watches.yaml文件示例
      ...
      - group: demo.example.com
        version: v1alpha1
        kind: Memcached
        chart: helm-charts/memcached
        overrideValues: (1)
          relatedImage: ${<related_image_environment_variable>} (2)
      1 添加overrideValues字段。
      2 使用<相关镜像环境变量>(例如RELATED_IMAGE_MEMCACHED)定义overrideValues字段。
      1. overrideValues字段的值添加到helm-charts/memchached/values.yaml文件中,如下例所示。

        helm-charts/memchached/values.yaml文件示例
        ...
        relatedImage: ""
      2. 修改helm-charts/memcached/templates/deployment.yaml文件中的图表模板,如下例所示。

        helm-charts/memcached/templates/deployment.yaml文件示例
        containers:
          - name: {{ .Chart.Name }}
            securityContext:
              - toYaml {{ .Values.securityContext | nindent 12 }}
            image: "{{ .Values.image.pullPolicy }}
            env: (1)
              - name: related_image (2)
                value: "{{ .Values.relatedImage }}" (3)
        1 添加env字段。
        2 命名环境变量。
        3 定义环境变量的值。
  3. BUNDLE_GEN_FLAGS变量定义添加到您的Makefile中,并进行以下更改。

    Makefile示例
       BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
    
       # USE_IMAGE_DIGESTS defines if images are resolved via tags or digests
       # You can enable this value if you would like to use SHA Based Digests
       # To enable set flag to true
       USE_IMAGE_DIGESTS ?= false
       ifeq ($(USE_IMAGE_DIGESTS), true)
             BUNDLE_GEN_FLAGS += --use-image-digests
       endif
    
    ...
    
    -  $(KUSTOMIZE) build config/manifests | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) (1)
    +  $(KUSTOMIZE) build config/manifests | operator-sdk generate bundle $(BUNDLE_GEN_FLAGS) (2)
    
    ...
    1 删除Makefile中的这一行。
    2 将上面的行替换为此行。
  4. 要更新您的 Operator 镜像以使用摘要 (SHA) 而不是标签,请运行make bundle命令并将USE_IMAGE_DIGESTS设置为true

    $ make bundle USE_IMAGE_DIGESTS=true
  5. 添加disconnected注释,这表示 Operator 在断开连接的环境中工作。

    metadata:
      annotations:
        operators.openshift.io/infrastructure-features: '["disconnected"]'

    OperatorHub 可以通过此基础架构功能过滤 Operator。

启用 Operator 以支持多种架构和操作系统

Operator Lifecycle Manager (OLM) 假设所有 Operator 都运行在 Linux 主机上。但是,作为 Operator 作者,您可以指定您的 Operator 是否支持在其他架构上管理工作负载,如果在 OpenShift Dedicated 集群中提供了工作节点。

如果您的 Operator 支持除 AMD64 和 Linux 之外的其他变体,您可以向提供 Operator 的集群服务版本 (CSV) 添加标签,以列出支持的变体。指示支持的架构和操作系统的标签由以下内容定义:

labels:
    operatorframework.io/arch.<arch>: supported (1)
    operatorframework.io/os.<os>: supported (2)
1 <arch>设置为支持的字符串。
2 <os>设置为支持的字符串。

只有默认通道的通道头上的标签才被考虑用于按标签过滤包清单。这意味着,例如,可以在非默认通道中为 Operator 提供其他架构,但是该架构不可用于在PackageManifest API 中进行过滤。

如果 CSV 不包含os标签,则默认情况下将其视为具有以下 Linux 支持标签。

labels:
    operatorframework.io/os.linux: supported

如果 CSV 不包含arch标签,则默认情况下将其视为具有以下 AMD64 支持标签。

labels:
    operatorframework.io/arch.amd64: supported

如果 Operator 支持多个节点架构或操作系统,您也可以添加多个标签。

先决条件
  • 具有 CSV 的 Operator 项目。

  • 为了支持列出多个架构和操作系统,CSV 中引用的 Operator 镜像必须是清单列表镜像。

  • 为了使 Operator 在受限网络或断开连接的环境中正常工作,引用的镜像也必须使用摘要 (SHA) 指定,而不是使用标签。

步骤
  • 在 CSV 的metadata.labels中为 Operator 支持的每个支持的架构和操作系统添加一个标签。

    labels:
      operatorframework.io/arch.s390x: supported
      operatorframework.io/os.zos: supported
      operatorframework.io/os.linux: supported (1)
      operatorframework.io/arch.amd64: supported (1)
    1 添加新的架构或操作系统后,现在还必须显式包含默认的os.linuxarch.amd64变体。
其他资源

Operator 的架构和操作系统支持

在 OpenShift Dedicated 上的 Operator Lifecycle Manager (OLM) 中,当标记或过滤支持多种架构和操作系统的 Operator 时,支持以下字符串。

表 6. OpenShift Dedicated 上支持的架构
架构 字符串

AMD64

amd64

ARM64

arm64

IBM Power®

ppc64le

IBM Z®

s390x

表 7. OpenShift Dedicated 上支持的操作系统
操作系统 字符串

Linux

linux

z/OS

zos

不同版本的 OpenShift Dedicated 和其他基于 Kubernetes 的发行版可能支持不同的架构和操作系统集。

设置建议的命名空间

某些 Operator 必须部署在特定命名空间中,或者其辅助资源必须位于特定命名空间中才能正常工作。如果从订阅中解析,Operator Lifecycle Manager (OLM) 会将其 Operator 的命名空间资源默认为其订阅的命名空间。

作为 Operator 作者,您可以改为将所需的目标命名空间表示为集群服务版本 (CSV) 的一部分,以保持对为其 Operator 安装的资源的最终命名空间的控制。使用 OperatorHub 将 Operator 添加到集群时,这使 Web 控制台能够在安装过程中自动填充安装程序的建议命名空间。

步骤
  • 在您的 CSV 中,将operatorframework.io/suggested-namespace注释设置为您的建议命名空间。

    metadata:
      annotations:
        operatorframework.io/suggested-namespace: <namespace> (1)
    1 设置您的建议命名空间。

设置具有默认节点选择器的建议命名空间

某些 Operator 期望仅在控制平面节点上运行,这可以通过 Operator 本身在Pod规范中设置nodeSelector来实现。

为了避免获得重复的以及可能冲突的集群范围默认nodeSelector,您可以在 Operator 运行的命名空间上设置默认节点选择器。默认节点选择器将优先于集群默认值,因此集群默认值不会应用于 Operator 命名空间中的 Pod。

使用 OperatorHub 将 Operator 添加到集群时,Web 控制台会在安装过程中自动填充安装程序的建议命名空间。建议的命名空间是使用包含在集群服务版本 (CSV) 中的 YAML 命名空间清单创建的。

步骤
  • 在您的 CSV 中,使用 `Namespace` 对象的清单设置 `operatorframework.io/suggested-namespace-template`。以下示例是具有指定 namespace 默认节点选择器的示例 `Namespace` 的清单。

    metadata:
      annotations:
        operatorframework.io/suggested-namespace-template: (1)
          {
            "apiVersion": "v1",
            "kind": "Namespace",
            "metadata": {
              "name": "vertical-pod-autoscaler-suggested-template",
              "annotations": {
                "openshift.io/node-selector": ""
              }
            }
          }
    1 设置您的建议命名空间。

    如果 CSV 中同时存在 `suggested-namespace` 和 `suggested-namespace-template` 注解,则 `suggested-namespace-template` 应优先。

启用 Operator 条件

Operator Lifecycle Manager (OLM) 为 Operators 提供了一个渠道,用于沟通影响 OLM 在管理 Operator 时的行为的复杂状态。默认情况下,OLM 在安装 Operator 时会创建一个 `OperatorCondition` 自定义资源定义 (CRD)。根据 `OperatorCondition` 自定义资源 (CR) 中设置的条件,OLM 的行为会相应改变。

为了支持 Operator 条件,Operator 必须能够读取 OLM 创建的 `OperatorCondition` CR,并能够完成以下任务:

  • 获取特定条件。

  • 设置特定条件的状态。

这可以通过使用 operator-lib 库来实现。Operator 作者可以在他们的 Operator 中提供 controller-runtime 客户端,以便库访问集群中 Operator 拥有的 `OperatorCondition` CR。

该库提供了一个通用的 `Conditions` 接口,该接口具有以下方法来在 `OperatorCondition` CR 中 `Get` 和 `Set` `conditionType`:

获取

为了获取特定条件,该库使用 `controller-runtime` 中的 `client.Get` 函数,这需要 `conditionAccessor` 中存在的 `types.NamespacedName` 类型的 `ObjectKey`。

设置

为了更新特定条件的状态,该库使用 `controller-runtime` 中的 `client.Update` 函数。如果 CRD 中不存在 `conditionType`,则会发生错误。

Operator 只允许修改 CR 的 `status` 子资源。Operators 可以删除或更新 `status.conditions` 数组以包含该条件。有关条件中字段的格式和描述的更多详细信息,请参阅上游 Condition GoDocs

Operator SDK 1.36.1 支持 `operator-lib` v0.11.0。

先决条件
  • 使用 Operator SDK 生成的 Operator 项目。

步骤

要在您的 Operator 项目中启用 Operator 条件:

  1. 在您的 Operator 项目的 `go.mod` 文件中,添加 `operator-framework/operator-lib` 作为必需库。

    module github.com/example-inc/memcached-operator
    
    go 1.19
    
    require (
      k8s.io/apimachinery v0.26.0
      k8s.io/client-go v0.26.0
      sigs.k8s.io/controller-runtime v0.14.1
      operator-framework/operator-lib v0.11.0
    )
  2. 在您的 Operator 逻辑中编写您自己的构造函数,这将导致以下结果:

    • 接受一个 `controller-runtime` 客户端。

    • 接受一个 `conditionType`。

    • 返回一个 `Condition` 接口来更新或添加条件。

    因为 OLM 目前支持 `Upgradeable` 条件,您可以创建一个具有访问 `Upgradeable` 条件的方法的接口。例如:

    import (
      ...
      apiv1 "github.com/operator-framework/api/pkg/operators/v1"
    )
    
    func NewUpgradeable(cl client.Client) (Condition, error) {
      return NewCondition(cl, "apiv1.OperatorUpgradeable")
    }
    
    cond, err := NewUpgradeable(cl);

    在此示例中,`NewUpgradeable` 构造函数被进一步用于创建一个 `cond` 变量,其类型为 `Condition`。`cond` 变量将反过来具有 `Get` 和 `Set` 方法,这些方法可用于处理 OLM `Upgradeable` 条件。

其他资源

定义 Webhook

Webhook 允许 Operator 作者在资源保存到对象存储并由 Operator 控制器处理之前拦截、修改和接受或拒绝资源。Operator Lifecycle Manager (OLM) 在将这些 Webhook 与您的 Operator 一起交付时,可以管理这些 Webhook 的生命周期。

Operator 的集群服务版本 (CSV) 资源可以包含一个 `webhookdefinitions` 部分来定义以下类型的 Webhook:

  • 准入 Webhook(验证和变异)

  • 转换 Webhook

步骤
  • 向 Operator 的 CSV 的 `spec` 部分添加一个 `webhookdefinitions` 部分,并使用 `ValidatingAdmissionWebhook`、`MutatingAdmissionWebhook` 或 `ConversionWebhook` 的 `type` 包含任何 Webhook 定义。以下示例包含所有三种类型的 Webhook:

    包含 Webhook 的 CSV
      apiVersion: operators.coreos.com/v1alpha1
      kind: ClusterServiceVersion
      metadata:
        name: webhook-operator.v0.0.1
      spec:
        customresourcedefinitions:
          owned:
          - kind: WebhookTest
            name: webhooktests.webhook.operators.coreos.io (1)
            version: v1
        install:
          spec:
            deployments:
            - name: webhook-operator-webhook
              ...
              ...
              ...
          strategy: deployment
        installModes:
        - supported: false
          type: OwnNamespace
        - supported: false
          type: SingleNamespace
        - supported: false
          type: MultiNamespace
        - supported: true
          type: AllNamespaces
        webhookdefinitions:
        - type: ValidatingAdmissionWebhook (2)
          admissionReviewVersions:
          - v1beta1
          - v1
          containerPort: 443
          targetPort: 4343
          deploymentName: webhook-operator-webhook
          failurePolicy: Fail
          generateName: vwebhooktest.kb.io
          rules:
          - apiGroups:
            - webhook.operators.coreos.io
            apiVersions:
            - v1
            operations:
            - CREATE
            - UPDATE
            resources:
            - webhooktests
          sideEffects: None
          webhookPath: /validate-webhook-operators-coreos-io-v1-webhooktest
        - type: MutatingAdmissionWebhook (3)
          admissionReviewVersions:
          - v1beta1
          - v1
          containerPort: 443
          targetPort: 4343
          deploymentName: webhook-operator-webhook
          failurePolicy: Fail
          generateName: mwebhooktest.kb.io
          rules:
          - apiGroups:
            - webhook.operators.coreos.io
            apiVersions:
            - v1
            operations:
            - CREATE
            - UPDATE
            resources:
            - webhooktests
          sideEffects: None
          webhookPath: /mutate-webhook-operators-coreos-io-v1-webhooktest
        - type: ConversionWebhook (4)
          admissionReviewVersions:
          - v1beta1
          - v1
          containerPort: 443
          targetPort: 4343
          deploymentName: webhook-operator-webhook
          generateName: cwebhooktest.kb.io
          sideEffects: None
          webhookPath: /convert
          conversionCRDs:
          - webhooktests.webhook.operators.coreos.io (5)
    ...
    1 转换 Webhook 针对的 CRD 必须在此处存在。
    2 验证准入 Webhook。
    3 变异准入 Webhook。
    4 转换 Webhook。
    5 每个 CRD 的 `spec.PreserveUnknownFields` 属性必须设置为 `false` 或 `nil`。

OLM 的 Webhook 注意事项

使用 Operator Lifecycle Manager (OLM) 部署带有 Webhook 的 Operator 时,必须定义以下内容:

  • `type` 字段必须设置为 `ValidatingAdmissionWebhook`、`MutatingAdmissionWebhook` 或 `ConversionWebhook`,否则 CSV 将处于失败阶段。

  • CSV 必须包含一个名称等效于 `webhookdefinition` 的 `deploymentName` 字段中提供的值的部署。

创建 Webhook 时,OLM 确保 Webhook 只对与部署 Operator 的 Operator 组匹配的 namespace 起作用。

证书颁发机构约束

OLM 配置为为每个部署提供单个证书颁发机构 (CA)。生成并将 CA 装入部署的逻辑最初由 API 服务生命周期逻辑使用。因此:

  • TLS 证书文件安装到部署的 `/apiserver.local.config/certificates/apiserver.crt` 位置。

  • TLS 密钥文件安装到部署的 `/apiserver.local.config/certificates/apiserver.key` 位置。

准入 Webhook 规则约束

为了防止 Operator 将集群配置为不可恢复的状态,如果准入 Webhook 中定义的规则拦截任何以下请求,OLM 将 CSV 置于失败阶段:

  • 目标为所有组的请求

  • 目标为 `operators.coreos.com` 组的请求

  • 目标为 `ValidatingWebhookConfigurations` 或 `MutatingWebhookConfigurations` 资源的请求

转换 Webhook 约束

如果转换 Webhook 定义不符合以下约束,OLM 将 CSV 置于失败阶段:

  • 具有转换 Webhook 的 CSV 只能支持 `AllNamespaces` 安装模式。

  • 转换 Webhook 针对的 CRD 必须将其 `spec.preserveUnknownFields` 字段设置为 `false` 或 `nil`。

  • CSV 中定义的转换 Webhook 必须针对拥有的 CRD。

  • 对于给定的 CRD,整个集群中只能有一个转换 Webhook。

了解您的自定义资源定义 (CRD)

您的 Operator 可以使用两种类型的自定义资源定义 (CRD):它拥有的 CRD 和它依赖的、必需的 CRD。

拥有的 CRD

您的 Operator 拥有的自定义资源定义 (CRD) 是 CSV 中最重要的部分。这建立了您的 Operator 与所需的 RBAC 规则、依赖项管理和其他 Kubernetes 概念之间的链接。

您的 Operator 通常使用多个 CRD 来链接概念,例如在一个对象中进行顶级数据库配置,而在另一个对象中表示副本集。每个 CRD 都应在 CSV 文件中列出。

表 8. 拥有的 CRD 字段
字段 描述 必需/可选

名称

您的 CRD 的完整名称。

必需

版本

该对象 API 的版本。

必需

种类

您的 CRD 的机器可读名称。

必需

显示名称

您的 CRD 名称的可读版本,例如MongoDB Standalone

必需

描述

简要描述此 CRD 如何被 Operator 使用,或描述 CRD 提供的功能。

必需

此 CRD 所属的 API 组,例如database.example.com

可选

资源

您的 CRD 拥有一个或多个类型的 Kubernetes 对象。这些列在resources部分中,以告知您的用户他们可能需要排查的对象,或者如何连接到应用程序,例如公开数据库的服务或入口规则。

建议仅列出对人类重要的对象,而不是您编排的所有内容的详尽列表。例如,不要列出存储内部状态且不应由用户修改的配置映射。

可选

SpecDescriptorsStatusDescriptorsActionDescriptors

这些描述符是一种方法,可以通过提示 UI 显示 Operator 对最终用户最重要的某些输入或输出。如果您的 CRD 包含用户必须提供的密钥或配置映射的名称,则可以在此处指定。这些项目在兼容的 UI 中被链接和突出显示。

有三种类型的描述符

  • SpecDescriptors:对对象spec块中的字段的引用。

  • StatusDescriptors:对对象status块中的字段的引用。

  • ActionDescriptors:对可以对对象执行的操作的引用。

所有描述符都接受以下字段

  • DisplayNameSpecStatusAction的可读名称。

  • DescriptionSpecStatusAction的简短描述及其如何被 Operator 使用。

  • Path:此描述符所描述的对象上字段的点分隔路径。

  • X-Descriptors:用于确定此描述符具有哪些“功能”以及使用哪个 UI 组件。有关 OpenShift Dedicated 的规范React UI X-Descriptors 列表,请参阅openshift/console项目。

有关Descriptors的更多信息,还可以参阅openshift/console项目Descriptors

可选

以下示例描述了一个MongoDB Standalone CRD,它需要以密钥和配置映射的形式提供一些用户输入,并编排服务、状态集、Pod 和配置映射。

拥有的 CRD 示例
      - displayName: MongoDB Standalone
        group: mongodb.com
        kind: MongoDbStandalone
        name: mongodbstandalones.mongodb.com
        resources:
          - kind: Service
            name: ''
            version: v1
          - kind: StatefulSet
            name: ''
            version: v1beta2
          - kind: Pod
            name: ''
            version: v1
          - kind: ConfigMap
            name: ''
            version: v1
        specDescriptors:
          - description: Credentials for Ops Manager or Cloud Manager.
            displayName: Credentials
            path: credentials
            x-descriptors:
              - 'urn:alm:descriptor:com.tectonic.ui:selector:core:v1:Secret'
          - description: Project this deployment belongs to.
            displayName: Project
            path: project
            x-descriptors:
              - 'urn:alm:descriptor:com.tectonic.ui:selector:core:v1:ConfigMap'
          - description: MongoDB version to be installed.
            displayName: Version
            path: version
            x-descriptors:
              - 'urn:alm:descriptor:com.tectonic.ui:label'
        statusDescriptors:
          - description: The status of each of the pods for the MongoDB cluster.
            displayName: Pod Status
            path: pods
            x-descriptors:
              - 'urn:alm:descriptor:com.tectonic.ui:podStatuses'
        version: v1
        description: >-
          MongoDB Deployment consisting of only one host. No replication of
          data.

必需的 CRD

依赖于其他必需的 CRD 完全是可选的,它仅仅是为了减少单个 Operator 的范围,并提供一种方法来组合多个 Operator 以解决端到端的用例。

一个示例是:一个 Operator 可以设置一个应用程序并安装一个 etcd 集群(来自 etcd Operator)用于分布式锁定,以及一个 Postgres 数据库(来自 Postgres Operator)用于数据存储。

Operator 生命周期管理器 (OLM) 会检查集群中可用的 CRD 和 Operator 以满足这些要求。如果找到合适的版本,则会在所需的命名空间中启动 Operator,并为每个 Operator 创建一个服务帐户,以创建、监视和修改所需的 Kubernetes 资源。

表 9. 必需的 CRD 字段
字段 描述 必需/可选

名称

您所需的 CRD 的完整名称。

必需

版本

该对象 API 的版本。

必需

种类

Kubernetes 对象种类。

必需

显示名称

CRD 的可读版本。

必需

描述

组件如何融入您更大架构的摘要。

必需

必需的 CRD 示例
    required:
    - name: etcdclusters.etcd.database.coreos.com
      version: v1beta2
      kind: EtcdCluster
      displayName: etcd Cluster
      description: Represents a cluster of etcd nodes.

CRD 升级

如果单个集群服务版本 (CSV) 拥有自定义资源定义 (CRD),则 OLM 会立即升级该 CRD。如果多个 CSV 拥有 CRD,则只有在满足以下所有向后兼容条件后,才会升级 CRD

  • 当前 CRD 中的所有现有服务版本都存在于新 CRD 中。

  • 与 CRD 的服务版本关联的所有现有实例或自定义资源在针对新 CRD 的验证模式进行验证时都是有效的。

添加新的 CRD 版本

步骤

要向您的 Operator 添加新版本的 CRD

  1. 在 CSV 的versions部分下,在 CRD 资源中添加一个新条目。

    例如,如果当前 CRD 的版本为v1alpha1,并且您想添加一个新版本v1beta1并将其标记为新的存储版本,请为v1beta1添加一个新条目。

    versions:
      - name: v1alpha1
        served: true
        storage: false
      - name: v1beta1 (1)
        served: true
        storage: true
    1 新条目。
  2. 如果 CSV 想要使用新版本,请确保更新 CSV 的owned部分中 CRD 的引用版本。

    customresourcedefinitions:
      owned:
      - name: cluster.example.com
        version: v1beta1 (1)
        kind: cluster
        displayName: Cluster
    1 更新version
  3. 将更新的 CRD 和 CSV 推送到您的包中。

弃用或删除 CRD 版本

Operator 生命周期管理器 (OLM) 不允许立即删除自定义资源定义 (CRD) 的服务版本。相反,必须首先通过将 CRD 中的served字段设置为false来禁用 CRD 的已弃用版本。然后,可以在后续 CRD 升级中删除非服务版本。

步骤

要弃用和删除 CRD 的特定版本

  1. 将已弃用的版本标记为非服务版本,以指示此版本不再使用,并且可能在后续升级中被删除。例如

    versions:
      - name: v1alpha1
        served: false (1)
        storage: true
    1 设置为false
  2. 如果要弃用的版本当前是storage版本,则将storage版本切换到服务版本。例如

    versions:
      - name: v1alpha1
        served: false
        storage: false (1)
      - name: v1beta1
        served: true
        storage: true (1)
    1 相应地更新storage字段。

    要从 CRD 中删除作为或曾经是storage版本的特定版本,必须从 CRD 状态中的storedVersion中删除该版本。如果 OLM 检测到新 CRD 中不再存在存储版本,它将尝试为您执行此操作。

  3. 使用上述更改升级 CRD。

  4. 在后续升级周期中,可以从 CRD 中完全删除非服务版本。例如

    versions:
      - name: v1beta1
        served: true
        storage: true
  5. 如果该版本从 CRD 中删除,请确保相应地更新 CSV 的owned部分中引用的 CRD 版本。

CRD 模板

必须让您的 Operator 用户了解哪些选项是必需的,哪些是可选的。您可以为每个自定义资源定义 (CRD) 提供模板,其中包含最小的一组配置,作为名为alm-examples的注释。兼容的 UI 将预先填充此模板,供用户进一步自定义。

注释包含种类列表,例如 CRD 名称以及 Kubernetes 对象的相应metadataspec

以下完整示例为EtcdClusterEtcdBackupEtcdRestore提供了模板。

metadata:
  annotations:
    alm-examples: >-
      [{"apiVersion":"etcd.database.coreos.com/v1beta2","kind":"EtcdCluster","metadata":{"name":"example","namespace":"<operator_namespace>"},"spec":{"size":3,"version":"3.2.13"}},{"apiVersion":"etcd.database.coreos.com/v1beta2","kind":"EtcdRestore","metadata":{"name":"example-etcd-cluster"},"spec":{"etcdCluster":{"name":"example-etcd-cluster"},"backupStorageType":"S3","s3":{"path":"<full-s3-path>","awsSecret":"<aws-secret>"}}},{"apiVersion":"etcd.database.coreos.com/v1beta2","kind":"EtcdBackup","metadata":{"name":"example-etcd-cluster-backup"},"spec":{"etcdEndpoints":["<etcd-cluster-endpoints>"],"storageType":"S3","s3":{"path":"<full-s3-path>","awsSecret":"<aws-secret>"}}}]

隐藏内部对象

运营商内部通常使用自定义资源定义 (CRD) 来完成一项任务。这些对象并非供用户操作,可能会让运营商用户感到困惑。例如,数据库运营商可能具有一个Replication CRD,每当用户创建具有replication: true的数据库对象时都会创建该 CRD。

作为运营商作者,您可以通过向运营商的集群服务版本 (CSV) 添加operators.operatorframework.io/internal-objects批注,隐藏用户界面中不适合用户操作的任何 CRD。

步骤
  1. 在将某个 CRD 标记为内部对象之前,请确保任何调试信息或可能需要管理应用程序的配置都反映在 CR 的状态或spec块中(如果适用于您的运营商)。

  2. operators.operatorframework.io/internal-objects批注添加到运营商的 CSV 中,以指定要在用户界面中隐藏的任何内部对象。

    内部对象批注
    apiVersion: operators.coreos.com/v1alpha1
    kind: ClusterServiceVersion
    metadata:
      name: my-operator-v1.2.3
      annotations:
        operators.operatorframework.io/internal-objects: '["my.internal.crd1.io","my.internal.crd2.io"]' (1)
    ...
    1 将任何内部 CRD 设置为字符串数组。

初始化所需的自定义资源

运营商可能需要用户在运营商完全发挥功能之前实例化自定义资源。但是,用户很难确定需要什么或如何定义资源。

作为运营商开发者,您可以通过在运营商安装期间向集群服务版本 (CSV) 添加operatorframework.io/initialization-resource来指定单个所需的自定义资源。然后,系统会提示您通过 CSV 中提供的模板创建自定义资源。此批注必须包含一个模板,其中包含在安装期间初始化资源所需的完整 YAML 定义。

如果定义了此批注,则在从 OpenShift Dedicated Web 控制台安装运营商后,系统会提示用户使用 CSV 中提供的模板创建资源。

步骤
  • operatorframework.io/initialization-resource批注添加到运营商的 CSV 中,以指定所需的自定义资源。例如,以下批注需要创建一个StorageCluster资源并提供完整的 YAML 定义。

    初始化资源批注
    apiVersion: operators.coreos.com/v1alpha1
    kind: ClusterServiceVersion
    metadata:
      name: my-operator-v1.2.3
      annotations:
        operatorframework.io/initialization-resource: |-
            {
                "apiVersion": "ocs.openshift.io/v1",
                "kind": "StorageCluster",
                "metadata": {
                    "name": "example-storagecluster"
                },
                "spec": {
                    "manageNodes": false,
                    "monPVCTemplate": {
                        "spec": {
                            "accessModes": [
                                "ReadWriteOnce"
                            ],
                            "resources": {
                                "requests": {
                                    "storage": "10Gi"
                                }
                            },
                            "storageClassName": "gp2"
                        }
                    },
                    "storageDeviceSets": [
                        {
                            "count": 3,
                            "dataPVCTemplate": {
                                "spec": {
                                    "accessModes": [
                                        "ReadWriteOnce"
                                    ],
                                    "resources": {
                                        "requests": {
                                            "storage": "1Ti"
                                        }
                                    },
                                    "storageClassName": "gp2",
                                    "volumeMode": "Block"
                                }
                            },
                            "name": "example-deviceset",
                            "placement": {},
                            "portable": true,
                            "resources": {}
                        }
                    ]
                }
            }
    ...

了解您的 API 服务

与 CRD 一样,您的运营商可以使用两种类型的 API 服务:已拥有所需

已拥有的 API 服务

当 CSV 拥有 API 服务时,它负责描述支持它的扩展api-server的部署以及它提供的组/版本/种类 (GVK)。

API 服务由它提供的组/版本唯一标识,并且可以列出多次以表示它预期提供的不同种类。

表 10. 已拥有的 API 服务字段
字段 描述 必需/可选

API 服务提供的组,例如database.example.com

必需

版本

API 服务的版本,例如v1alpha1

必需

种类

API 服务预期提供的种类。

必需

名称

提供的 API 服务的复数名称。

必需

DeploymentName

CSV 定义的与 API 服务相对应的部署的名称(对于已拥有的 API 服务是必需的)。在 CSV 等待阶段,OLM 运营商会在您的 CSV 的InstallStrategy中搜索具有匹配名称的Deployment规范,如果找不到,则不会将 CSV 转移到“安装就绪”阶段。

必需

显示名称

API 服务名称的可读版本,例如MongoDB Standalone

必需

描述

运营商如何使用此 API 服务的简短说明,或 API 服务提供的功能的说明。

必需

资源

您的 API 服务拥有 Kubernetes 对象的一种或多种类型。这些列在资源部分中,以告知您的用户他们可能需要排除故障的对象或如何连接到应用程序,例如公开数据库的服务或入口规则。

建议仅列出对人类重要的对象,而不是您编排的所有内容的详尽列表。例如,不要列出存储内部状态且不应由用户修改的配置映射。

可选

SpecDescriptorsStatusDescriptorsActionDescriptors

与已拥有的 CRD 基本相同。

可选

API 服务资源创建

运营商生命周期管理器 (OLM) 负责为每个唯一的已拥有 API 服务创建或替换服务和 API 服务资源。

  • 服务 Pod 选择器从与 API 服务说明的DeploymentName字段匹配的 CSV 部署中复制。

  • 为每次安装生成一个新的 CA 密钥/证书对,并将 base64 编码的 CA 捆绑包嵌入相应的 API 服务资源中。

API 服务服务证书

每当安装已拥有的 API 服务时,OLM 都会处理生成服务密钥/证书对。服务证书具有一个公共名称 (CN),其中包含生成的Service资源的主机名,并由嵌入相应 API 服务资源中的 CA 捆绑包的私钥签名。

证书存储为部署命名空间中的类型kubernetes.io/tls密钥,并且名称为apiservice-cert的卷会自动附加到 CSV 中与 API 服务说明的DeploymentName字段匹配的部署的卷部分。

如果不存在,则还会将具有匹配名称的卷挂载附加到该部署的所有容器。这允许用户定义具有预期名称的卷挂载以适应任何自定义路径要求。生成的卷挂载的路径默认为/apiserver.local.config/certificates,并且任何具有相同路径的现有卷挂载都将被替换。

所需的 API 服务

OLM 确保所有必需的 CSV 都具有可用的 API 服务,并且在尝试安装之前所有预期的 GVK 都可以发现。这允许 CSV 依赖于它不拥有的 API 服务提供的特定种类。

表 11. 所需的 API 服务字段
字段 描述 必需/可选

API 服务提供的组,例如database.example.com

必需

版本

API 服务的版本,例如v1alpha1

必需

种类

API 服务预期提供的种类。

必需

显示名称

API 服务名称的可读版本,例如MongoDB Standalone

必需

描述

运营商如何使用此 API 服务的简短说明,或 API 服务提供的功能的说明。

必需