×

基于 Java 的 Operator SDK 仅为技术预览功能。技术预览功能不受 Red Hat 生产服务级别协议 (SLA) 的支持,并且可能功能不完整。Red Hat 不建议在生产环境中使用它们。这些功能可让客户提前访问即将推出的产品功能,从而能够在开发过程中测试功能并提供反馈。

有关 Red Hat 技术预览功能的支持范围的更多信息,请参见 技术预览功能支持范围

Operator 开发人员可以利用 Operator SDK 中的 Java 编程语言支持来构建一个面向 Memcached(一个分布式键值存储)的示例 Java 驱动的 Operator,并管理其生命周期。

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 工具和 java-operator-sdk 库 API

Operator Lifecycle Manager (OLM)

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

先决条件

  • 已安装 Operator SDK CLI

  • 已安装 OpenShift CLI (oc) 4.17+

  • Java 11+

  • Maven 3.6.3+

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

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

创建项目

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

步骤
  1. 为项目创建一个目录

    $ mkdir -p $HOME/projects/memcached-operator
  2. 切换到该目录

    $ cd $HOME/projects/memcached-operator
  3. 使用 quarkus 插件运行 operator-sdk init 命令来初始化项目

    $ operator-sdk init \
        --plugins=quarkus \
        --domain=example.com \
        --project-name=memcached-operator

PROJECT 文件

operator-sdk init 命令生成的多个文件包括一个 Kubebuilder PROJECT 文件。从项目根目录运行的后续 operator-sdk 命令以及 help 输出会读取此文件,并知道项目类型为 Java。例如

domain: example.com
layout:
- quarkus.javaoperatorsdk.io/v1-alpha
projectName: memcached-operator
version: "3"

创建 API 和控制器

使用 Operator SDK CLI 创建自定义资源定义 (CRD) API 和控制器。

步骤
  1. 运行以下命令以创建 API

    $ operator-sdk create api \
        --plugins=quarkus \(1)
        --group=cache \(2)
        --version=v1 \(3)
        --kind=Memcached (4)
    1 将 plugin 标志设置为 quarkus
    2 将 group 标志设置为 cache
    3 将 version 标志设置为 v1
    4 将 kind 标志设置为 Memcached
验证
  1. 运行 tree 命令以查看文件结构

    $ tree
    示例输出
    .
    ├── Makefile
    ├── PROJECT
    ├── pom.xml
    └── src
        └── main
            ├── java
            │   └── com
            │       └── example
            │           ├── Memcached.java
            │           ├── MemcachedReconciler.java
            │           ├── MemcachedSpec.java
            │           └── MemcachedStatus.java
            └── resources
                └── application.properties
    
    6 directories, 8 files

定义 API

Memcached 自定义资源 (CR) 定义 API。

步骤
  • 编辑作为 create api 过程一部分生成的以下文件

    1. 更新 MemcachedSpec.java 文件中的以下属性以定义 Memcached CR 的所需状态

      public class MemcachedSpec {
      
          private Integer size;
      
          public Integer getSize() {
              return size;
          }
      
          public void setSize(Integer size) {
              this.size = size;
          }
      }
    2. 更新 MemcachedStatus.java 文件中的以下属性以定义 Memcached CR 的观察状态

      以下示例说明了节点状态字段。建议您在实践中使用 典型的状态属性

      import java.util.ArrayList;
      import java.util.List;
      
      public class MemcachedStatus {
      
          // Add Status information here
          // Nodes are the names of the memcached pods
          private List<String> nodes;
      
          public List<String> getNodes() {
              if (nodes == null) {
                  nodes = new ArrayList<>();
              }
              return nodes;
          }
      
          public void setNodes(List<String> nodes) {
              this.nodes = nodes;
          }
      }
    3. 更新 Memcached.java 文件以定义 Memcached API 的模式,该模式扩展到 MemcachedSpec.javaMemcachedStatus.java 文件。

      @Version("v1")
      @Group("cache.example.com")
      public class Memcached extends CustomResource<MemcachedSpec, MemcachedStatus> implements Namespaced {}

生成 CRD 清单

在使用 MemcachedSpecMemcachedStatus 文件定义 API 后,您可以生成 CRD 清单。

步骤
  • memcached-operator目录下运行以下命令来生成CRD:

    $ mvn clean install
验证
  • 验证target/kubernetes/memcacheds.cache.example.com-v1.yml文件中CRD的内容,如下例所示:

    $ cat target/kubernetes/memcacheds.cache.example.com-v1.yaml
    示例输出
    # Generated by Fabric8 CRDGenerator, manual edits might get overwritten!
    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      name: memcacheds.cache.example.com
    spec:
      group: cache.example.com
      names:
        kind: Memcached
        plural: memcacheds
        singular: memcached
      scope: Namespaced
      versions:
      - name: v1
        schema:
          openAPIV3Schema:
            properties:
              spec:
                properties:
                  size:
                    type: integer
                type: object
              status:
                properties:
                  nodes:
                    items:
                      type: string
                    type: array
                type: object
            type: object
        served: true
        storage: true
        subresources:
          status: {}

创建自定义资源

生成CRD清单文件后,您可以创建自定义资源 (CR)。

步骤
  • 创建一个名为memcached-sample.yaml的Memcached CR。

    apiVersion: cache.example.com/v1
    kind: Memcached
    metadata:
      name: memcached-sample
    spec:
      # Add spec fields here
      size: 1

实现控制器

创建新的API和控制器后,您可以实现控制器逻辑。

步骤
  1. 将以下依赖项添加到pom.xml文件中:

        <dependency>
          <groupId>commons-collections</groupId>
          <artifactId>commons-collections</artifactId>
          <version>3.2.2</version>
        </dependency>
  2. 在此示例中,请将生成的控制器文件MemcachedReconciler.java替换为以下示例实现:

    MemcachedReconciler.java示例
    package com.example;
    
    import io.fabric8.kubernetes.client.KubernetesClient;
    import io.javaoperatorsdk.operator.api.reconciler.Context;
    import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
    import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
    import io.fabric8.kubernetes.api.model.ContainerBuilder;
    import io.fabric8.kubernetes.api.model.ContainerPortBuilder;
    import io.fabric8.kubernetes.api.model.LabelSelectorBuilder;
    import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
    import io.fabric8.kubernetes.api.model.OwnerReferenceBuilder;
    import io.fabric8.kubernetes.api.model.Pod;
    import io.fabric8.kubernetes.api.model.PodSpecBuilder;
    import io.fabric8.kubernetes.api.model.PodTemplateSpecBuilder;
    import io.fabric8.kubernetes.api.model.apps.Deployment;
    import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
    import io.fabric8.kubernetes.api.model.apps.DeploymentSpecBuilder;
    import org.apache.commons.collections.CollectionUtils;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;
    
    public class MemcachedReconciler implements Reconciler<Memcached> {
      private final KubernetesClient client;
    
      public MemcachedReconciler(KubernetesClient client) {
        this.client = client;
      }
    
      // TODO Fill in the rest of the reconciler
    
      @Override
      public UpdateControl<Memcached> reconcile(
          Memcached resource, Context context) {
          // TODO: fill in logic
          Deployment deployment = client.apps()
                  .deployments()
                  .inNamespace(resource.getMetadata().getNamespace())
                  .withName(resource.getMetadata().getName())
                  .get();
    
          if (deployment == null) {
              Deployment newDeployment = createMemcachedDeployment(resource);
              client.apps().deployments().create(newDeployment);
              return UpdateControl.noUpdate();
          }
    
          int currentReplicas = deployment.getSpec().getReplicas();
          int requiredReplicas = resource.getSpec().getSize();
    
          if (currentReplicas != requiredReplicas) {
              deployment.getSpec().setReplicas(requiredReplicas);
              client.apps().deployments().createOrReplace(deployment);
              return UpdateControl.noUpdate();
          }
    
          List<Pod> pods = client.pods()
              .inNamespace(resource.getMetadata().getNamespace())
              .withLabels(labelsForMemcached(resource))
              .list()
              .getItems();
    
          List<String> podNames =
              pods.stream().map(p -> p.getMetadata().getName()).collect(Collectors.toList());
    
    
          if (resource.getStatus() == null
                   || !CollectionUtils.isEqualCollection(podNames, resource.getStatus().getNodes())) {
               if (resource.getStatus() == null) resource.setStatus(new MemcachedStatus());
               resource.getStatus().setNodes(podNames);
               return UpdateControl.updateResource(resource);
          }
    
          return UpdateControl.noUpdate();
      }
    
      private Map<String, String> labelsForMemcached(Memcached m) {
        Map<String, String> labels = new HashMap<>();
        labels.put("app", "memcached");
        labels.put("memcached_cr", m.getMetadata().getName());
        return labels;
      }
    
      private Deployment createMemcachedDeployment(Memcached m) {
          Deployment deployment = new DeploymentBuilder()
              .withMetadata(
                  new ObjectMetaBuilder()
                      .withName(m.getMetadata().getName())
                      .withNamespace(m.getMetadata().getNamespace())
                      .build())
              .withSpec(
                  new DeploymentSpecBuilder()
                      .withReplicas(m.getSpec().getSize())
                      .withSelector(
                          new LabelSelectorBuilder().withMatchLabels(labelsForMemcached(m)).build())
                      .withTemplate(
                          new PodTemplateSpecBuilder()
                              .withMetadata(
                                  new ObjectMetaBuilder().withLabels(labelsForMemcached(m)).build())
                              .withSpec(
                                  new PodSpecBuilder()
                                      .withContainers(
                                          new ContainerBuilder()
                                              .withImage("memcached:1.4.36-alpine")
                                              .withName("memcached")
                                              .withCommand("memcached", "-m=64", "-o", "modern", "-v")
                                              .withPorts(
                                                  new ContainerPortBuilder()
                                                      .withContainerPort(11211)
                                                      .withName("memcached")
                                                      .build())
                                              .build())
                                      .build())
                              .build())
                      .build())
              .build();
        deployment.addOwnerReference(m);
        return deployment;
      }
    }

    此示例控制器为每个Memcached自定义资源 (CR)运行以下协调逻辑:

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

    • 确保部署大小与Memcached CR规范中指定的大小匹配。

    • 使用memcached Pod的名称更新Memcached CR状态。

接下来的小节将解释示例实现中的控制器如何监视资源以及如何触发协调循环。您可以跳过这些小节,直接跳转到运行Operator

协调循环

  1. 每个控制器都有一个带有Reconcile()方法的协调器对象,该方法实现协调循环。协调循环将传递Deployment参数,如下例所示:

            Deployment deployment = client.apps()
                    .deployments()
                    .inNamespace(resource.getMetadata().getNamespace())
                    .withName(resource.getMetadata().getName())
                    .get();
  2. 如下例所示,如果Deploymentnull,则需要创建部署。创建Deployment后,您可以确定是否需要协调。如果不需要协调,则返回UpdateControl.noUpdate()的值,否则,返回`UpdateControl.updateStatus(resource)`的值。

            if (deployment == null) {
                Deployment newDeployment = createMemcachedDeployment(resource);
                client.apps().deployments().create(newDeployment);
                return UpdateControl.noUpdate();
            }
  3. 获取Deployment后,获取当前副本数和所需副本数,如下例所示:

            int currentReplicas = deployment.getSpec().getReplicas();
            int requiredReplicas = resource.getSpec().getSize();
  4. 如果currentReplicasrequiredReplicas不匹配,则必须更新Deployment,如下例所示:

            if (currentReplicas != requiredReplicas) {
                deployment.getSpec().setReplicas(requiredReplicas);
                client.apps().deployments().createOrReplace(deployment);
                return UpdateControl.noUpdate();
            }
  5. 以下示例显示如何获取Pod列表及其名称:

            List<Pod> pods = client.pods()
                .inNamespace(resource.getMetadata().getNamespace())
                .withLabels(labelsForMemcached(resource))
                .list()
                .getItems();
    
            List<String> podNames =
                pods.stream().map(p -> p.getMetadata().getName()).collect(Collectors.toList());
  6. 检查是否创建了资源并使用Memcached资源验证pod名称。如果这些条件中的任何一个不匹配,请执行协调,如下例所示:

            if (resource.getStatus() == null
                    || !CollectionUtils.isEqualCollection(podNames, resource.getStatus().getNodes())) {
                if (resource.getStatus() == null) resource.setStatus(new MemcachedStatus());
                resource.getStatus().setNodes(podNames);
                return UpdateControl.updateResource(resource);
            }

定义labelsForMemcached

labelsForMemcached是一个返回要附加到资源的标签映射的实用程序。

    private Map<String, String> labelsForMemcached(Memcached m) {
        Map<String, String> labels = new HashMap<>();
        labels.put("app", "memcached");
        labels.put("memcached_cr", m.getMetadata().getName());
        return labels;
    }

定义createMemcachedDeployment

createMemcachedDeployment方法使用fabric8 DeploymentBuilder类。

    private Deployment createMemcachedDeployment(Memcached m) {
        Deployment deployment = new DeploymentBuilder()
            .withMetadata(
                new ObjectMetaBuilder()
                    .withName(m.getMetadata().getName())
                    .withNamespace(m.getMetadata().getNamespace())
                    .build())
            .withSpec(
                new DeploymentSpecBuilder()
                    .withReplicas(m.getSpec().getSize())
                    .withSelector(
                        new LabelSelectorBuilder().withMatchLabels(labelsForMemcached(m)).build())
                    .withTemplate(
                        new PodTemplateSpecBuilder()
                            .withMetadata(
                                new ObjectMetaBuilder().withLabels(labelsForMemcached(m)).build())
                            .withSpec(
                                new PodSpecBuilder()
                                    .withContainers(
                                        new ContainerBuilder()
                                            .withImage("memcached:1.4.36-alpine")
                                            .withName("memcached")
                                            .withCommand("memcached", "-m=64", "-o", "modern", "-v")
                                            .withPorts(
                                                new ContainerPortBuilder()
                                                    .withContainerPort(11211)
                                                    .withName("memcached")
                                                    .build())
                                            .build())
                                    .build())
                            .build())
                    .build())
            .build();
      deployment.addOwnerReference(m);
      return deployment;
    }

运行Operator

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

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

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

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

在集群外部本地运行

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

步骤
  1. 运行以下命令来编译Operator:

    $ mvn clean install
    示例输出
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  11.193 s
    [INFO] Finished at: 2021-05-26T12:16:54-04:00
    [INFO] ------------------------------------------------------------------------
  2. 运行以下命令将CRD安装到默认命名空间:

    $ oc apply -f target/kubernetes/memcacheds.cache.example.com-v1.yml
    示例输出
    customresourcedefinition.apiextensions.k8s.io/memcacheds.cache.example.com created
  3. 创建一个名为rbac.yaml的文件,如下例所示:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: memcached-operator-admin
    subjects:
    - kind: ServiceAccount
      name: memcached-quarkus-operator-operator
      namespace: <operator_namespace>
    roleRef:
      kind: ClusterRole
      name: cluster-admin
      apiGroup: ""
  4. 运行以下命令通过应用rbac.yaml文件来授予memcached-quarkus-operator-operator集群管理员权限:

    $ oc apply -f rbac.yaml
  5. 输入以下命令来运行Operator:

    $ java -jar target/quarkus-app/quarkus-run.jar

    java命令将运行Operator并保持运行状态,直到您结束进程。您将需要另一个终端来完成其余命令。

  6. 使用以下命令应用memcached-sample.yaml文件:

    $ kubectl apply -f memcached-sample.yaml
    示例输出
    memcached.cache.example.com/memcached-sample created
验证
  • 运行以下命令以确认Pod已启动:

    $ oc get all
    示例输出
    NAME                                                       READY   STATUS    RESTARTS   AGE
    pod/memcached-sample-6c765df685-mfqnz                      1/1     Running   0          18s

作为部署在集群上运行

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

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

    1. 构建镜像:

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

      Operator 的 SDK 生成的 Dockerfile 明确引用了非 AMD64 架构的 `GOARCH=amd64` 用于 `go build`。这可以修改为 `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. 运行以下命令将CRD安装到默认命名空间:

    $ oc apply -f target/kubernetes/memcacheds.cache.example.com-v1.yml
    示例输出
    customresourcedefinition.apiextensions.k8s.io/memcacheds.cache.example.com created
  3. 创建一个名为rbac.yaml的文件,如下例所示:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: memcached-operator-admin
    subjects:
    - kind: ServiceAccount
      name: memcached-quarkus-operator-operator
      namespace: <operator_namespace>
    roleRef:
      kind: ClusterRole
      name: cluster-admin
      apiGroup: ""

    rbac.yaml文件将在稍后步骤中应用。

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

    $ make deploy IMG=<registry>/<user>/<image_name>:<tag>
  5. 运行以下命令通过应用前面步骤中创建的rbac.yaml文件来授予memcached-quarkus-operator-operator集群管理员权限:

    $ oc apply -f rbac.yaml
  6. 运行以下命令以验证Operator是否正在运行:

    $ oc get all -n default
    示例输出
    NAME                                                      READY   UP-TO-DATE   AVAILABLE   AGE
    pod/memcached-quarkus-operator-operator-7db86ccf58-k4mlm   0/1       Running   0           18s
  7. 运行以下命令来应用memcached-sample.yaml并创建memcached-sample pod:

    $ oc apply -f memcached-sample.yaml
    示例输出
    memcached.cache.example.com/memcached-sample created
验证
  • 运行以下命令以确认Pod已启动:

    $ oc get all
    示例输出
    NAME                                                       READY   STATUS    RESTARTS   AGE
    pod/memcached-quarkus-operator-operator-7b766f4896-kxnzt   1/1     Running   1          79s
    pod/memcached-sample-6c765df685-mfqnz                      1/1     Running   0          18s

捆绑Operator并使用Operator Lifecycle Manager部署

捆绑Operator

Operator捆绑格式是Operator SDK和Operator Lifecycle Manager (OLM)的默认打包方法。您可以通过使用Operator SDK将Operator项目构建和推送为捆绑镜像,从而使您的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>

      Operator 的 SDK 生成的 Dockerfile 明确引用了非 AMD64 架构的 `GOARCH=amd64` 用于 `go build`。这可以修改为 `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项目中创建以下文件和目录:

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

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

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

    • 一个Dockerfile bundle.Dockerfile

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

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

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

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

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

使用Operator Lifecycle Manager部署Operator

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

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

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

  • 已构建并推送到注册表的 Operator 捆绑包镜像

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

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

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

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

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

    此命令执行以下操作

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

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

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