5.6. Java ベースの Operator

5.6.1. Java ベースの Operator の Operator SDK の使用を開始する

重要

Java ベースの Operator SDK はテクノロジープレビュー機能としてのみ提供されます。テクノロジープレビュー機能は、Red Hat 製品サポートのサービスレベルアグリーメント (SLA) の対象外であり、機能的に完全ではない場合があります。Red Hat は、実稼働環境でこれらを使用することを推奨していません。テクノロジープレビュー機能は、最新の製品機能をいち早く提供して、開発段階で機能のテストを行いフィードバックを提供していただくことを目的としています。

Red Hat のテクノロジープレビュー機能のサポート範囲に関する詳細は、テクノロジープレビュー機能のサポート範囲 を参照してください。

Operator SDK によって提供されるツールおよびライブラリーを使用して Java ベースの Operator をセットアップし、実行することに関連した基本内容を示すには、Operator 開発者は Java ベースの Memcached の Operator のサンプル、分散キー/値のストアをビルドして、クラスターへデプロイすることができます。

5.6.1.1. 前提条件

  • Operator SDK CLI がインストールされていること。
  • OpenShift CLI (oc) v4.12 以降がインストールされている
  • Java v11 以降
  • Maven v3.6.3 以降
  • cluster-admin パーミッションを持つアカウントを使用して、oc で OpenShift Container Platform 4.12 クラスターにログインしている
  • クラスターがイメージをプルできるようにするには、イメージをプッシュするリポジトリーを public として設定するか、イメージプルシークレットを設定する必要があります。

5.6.1.2. Java ベースの Operator の作成とデプロイ

Operator SDK を使用して Memcached の単純な Java ベースの Operator をビルドし、デプロイできます。

手順

  1. プロジェクトを作成します。

    1. プロジェクトディレクトリーを作成します。

      $ mkdir memcached-operator
    2. プロジェクトディレクトリーに移動します。

      $ cd memcached-operator
    3. quarkus プラグインを指定して operator-sdk init コマンドを実行し、プロジェクトを初期化します。

      $ operator-sdk init \
          --plugins=quarkus \
          --domain=example.com \
          --project-name=memcached-operator
  2. API を作成します。

    単純な Memcached API を作成します。

    $ operator-sdk create api \
        --plugins quarkus \
        --group cache \
        --version v1 \
        --kind Memcached
  3. Operator イメージをビルドし、プッシュします。

    デフォルトの Makefile ターゲットを使用して Operator をビルドし、プッシュします。プッシュ先となるレジストリーを使用するイメージのプル仕様を使用して IMG を設定します。

    $ 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. サンプルカスタムリソース (CR) を作成します。

    1. サンプル CR を作成します。

      $ oc apply -f config/samples/cache_v1_memcached.yaml \
          -n memcached-operator-system
    2. Operator を調整する CR を確認します。

      $ oc logs deployment.apps/memcached-operator-controller-manager \
          -c manager \
          -n memcached-operator-system
  6. CR を削除する

    次のコマンドを実行して CR を削除します。

    $ oc delete -f config/samples/cache_v1_memcached.yaml -n memcached-operator-system
  7. クリーンアップします。

    以下のコマンドを実行して、この手順の一部として作成されたリソースをクリーンアップします。

    $ make undeploy

5.6.1.3. 次のステップ

5.6.2. Java ベースの Operator の Operator SDK チュートリアル

重要

Java ベースの Operator SDK はテクノロジープレビュー機能としてのみ提供されます。テクノロジープレビュー機能は、Red Hat 製品サポートのサービスレベルアグリーメント (SLA) の対象外であり、機能的に完全ではない場合があります。Red Hat は、実稼働環境でこれらを使用することを推奨していません。テクノロジープレビュー機能は、最新の製品機能をいち早く提供して、開発段階で機能のテストを行いフィードバックを提供していただくことを目的としています。

Red Hat のテクノロジープレビュー機能のサポート範囲に関する詳細は、テクノロジープレビュー機能のサポート範囲 を参照してください。

Operator 開発者は、Operator SDK での Java プログラミング言語のサポートを利用して、Java ベースの Memcached Operator のサンプルをビルドして、分散キー/値のストアを作成し、そのライフサイクルを管理することができます。

このプロセスは、Operator Framework の 2 つの重要な設定要素を使用して実行されます。

Operator SDK
operator-sdk CLI ツールおよび java-operator-sdk ライブラリー API
Operator Lifecycle Manager (OLM)
クラスター上の Operator のインストール、アップグレード、ロールベースのアクセス制御 (RBAC)
注記

このチュートリアルでは、Java ベースの Operator の Operator SDK の使用を開始する よりも詳細に説明します。

5.6.2.1. 前提条件

  • Operator SDK CLI がインストールされていること。
  • OpenShift CLI (oc) v4.12 以降がインストールされている
  • Java v11 以降
  • Maven v3.6.3 以降
  • cluster-admin パーミッションを持つアカウントを使用して、oc で OpenShift Container Platform 4.12 クラスターにログインしている
  • クラスターがイメージをプルできるようにするには、イメージをプッシュするリポジトリーを public として設定するか、イメージプルシークレットを設定する必要があります。

5.6.2.2. プロジェクトの作成

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
5.6.2.2.1. PROJECT ファイル

operator-sdk init コマンドで生成されるファイルの 1 つに、Kubebuilder の PROJECT ファイルがあります。プロジェクトルートから実行される後続の operator-sdk コマンドおよび help 出力は、このファイルを読み取り、プロジェクトタイプが Java であることを認識しています。以下に例を示します。

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

5.6.2.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
    プラグインフラグを 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

5.6.2.3.1. 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 の観察された状態を定義します。

      注記

      以下の例では、Node ステータスフィールドを示しています。実際には、通常のステータスプロパティー を使用することが推奨されます。

      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 ファイルを更新して、MemcachedSpec.javaMemcachedStatus.java ファイルの両方に拡張する Memcached API のスキーマを定義します。

      @Version("v1")
      @Group("cache.example.com")
      public class Memcached extends CustomResource<MemcachedSpec, MemcachedStatus> implements Namespaced {}
5.6.2.3.2. CRD マニフェストの生成

MemcachedSpec および MemcachedStatus ファイルを使用して 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: {}

5.6.2.3.3. カスタムリソースの作成

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

5.6.2.4. コントローラーの実装

新規 API およびコントローラーの作成後に、コントローラーロジックを実装することができます。

手順

  1. 以下の依存関係を pom.xml ファイルに追加します。

        <dependency>
          <groupId>commons-collections</groupId>
          <artifactId>commons-collections</artifactId>
          <version>3.2.2</version>
        </dependency>
  2. この例では、生成されたコントローラーファイル MemcachedReconciler.java を以下の実装例に置き換えます。

    例5.9 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) について以下の調整 (reconciliation) ロジックを実行します。

    • Memcached デプロイメントが存在しない場合に作成する。
    • デプロイメントのサイズが、Memcached CR 仕様で指定されたサイズになるようにする。
    • Memcached CR ステータスを memcached Pod の名前で更新する。

次のサブセクションでは、実装例のコントローラーがリソースを監視する方法と reconcile ループがトリガーされる方法を説明しています。これらのサブセクションを省略し、直接 Operator の実行 に進むことができます。

5.6.2.4.1. reconcile ループ
  1. すべてのコントローラーには、reconcile ループを実装する Reconcile() メソッドのある reconciler オブジェクトがあります。以下の例のように、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);
            }
5.6.2.4.2. 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;
    }
5.6.2.4.3. 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;
    }

5.6.2.5. Operator の実行

Operator SDK CLI を使用して Operator をビルドし、実行する方法は 3 つあります。

  • クラスター外で Go プログラムとしてローカルに実行します。
  • クラスター上のデプロイメントとして実行します。
  • Operator をバンドルし、Operator Lifecycle Manager (OLM) を使用してクラスター上にデプロイします。
5.6.2.5.1. クラスター外でローカルに実行する。

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 をデフォルトの namespace にインストールします。

    $ 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 ファイルを適用して cluster-admin 権限を 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

5.6.2.5.2. クラスター上でのデプロイメントとしての実行

Operator プロジェクトは、クラスター上でデプロイメントとして実行できます。

手順

  1. 以下の make コマンドを実行して Operator イメージをビルドし、プッシュします。以下の手順の IMG 引数を変更して、アクセス可能なリポジトリーを参照します。Quay.io などのリポジトリーサイトにコンテナーを保存するためのアカウントを取得できます。

    1. イメージをビルドします。

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

      Operator の SDK によって生成される Dockerfile は、go build について GOARCH=amd64 を明示的に参照します。これは、AMD64 アーキテクチャー以外の場合は GOARCH=$TARGETARCH に修正できます。Docker は、-platform で指定された値に環境変数を自動的に設定します。Buildah では、そのために -build-arg を使用する必要があります。詳細は、Multiple Architectures を参照してください。

    2. イメージをリポジトリーにプッシュします。

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

      両方のコマンドのイメージの名前とタグ (例: IMG=<registry>/<user>/<image_name>:<tag>) を Makefile に設定することもできます。IMG ?= controller:latest の値を変更して、デフォルトのイメージ名を設定します。

  2. 以下のコマンドを実行して CRD をデフォルトの namespace にインストールします。

    $ 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 ファイルを適用して cluster-admin 権限を 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

5.6.2.5.3. Operator のバンドルおよび Operator Lifecycle Manager を使用したデプロイ
5.6.2.5.3.1. Operator のバンドル

Operator Bundle Format は、Operator SDK および Operator Lifecycle Manager (OLM) のデフォルトパッケージ方法です。Operator SDK を使用して OLM に対して Operator を準備し、バンドルイメージとして Operator プロジェクトをビルドしてプッシュできます。

前提条件

  • 開発ワークステーションに Operator SDK CLI がインストールされていること。
  • OpenShift CLI (oc) v4.12 以降がインストールされている
  • Operator プロジェクトが Operator SDK を使用して初期化されていること。

手順

  1. 以下の make コマンドを Operator プロジェクトディレクトリーで実行し、Operator イメージをビルドし、プッシュします。以下の手順の IMG 引数を変更して、アクセス可能なリポジトリーを参照します。Quay.io などのリポジトリーサイトにコンテナーを保存するためのアカウントを取得できます。

    1. イメージをビルドします。

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

      Operator の SDK によって生成される Dockerfile は、go build について GOARCH=amd64 を明示的に参照します。これは、AMD64 アーキテクチャー以外の場合は GOARCH=$TARGETARCH に修正できます。Docker は、-platform で指定された値に環境変数を自動的に設定します。Buildah では、そのために -build-arg を使用する必要があります。詳細は、Multiple Architectures を参照してください。

    2. イメージをリポジトリーにプッシュします。

      $ make docker-push IMG=<registry>/<user>/<operator_image_name>:<tag>
  2. Operator SDK generate bundle および bundle validate のサブコマンドを含む複数のコマンドを呼び出す make bundle コマンドを実行し、Operator バンドルマニフェストを作成します。

    $ 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 は、1 つ以上のバンドルイメージを参照するインデックスイメージを使用して Operator バンドルを使用します。

    1. バンドルイメージをビルドします。イメージをプッシュしようとするレジストリー、ユーザー namespace、およびイメージタグの詳細で 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 拡張として実行されるため、追加のツールなしにすべての Operator のライフサイクル管理機能に Web コンソールおよび OpenShift CLI (oc) を使用できます。

Operator Bundle Format は、Operator SDK および OLM のデフォルトパッケージ方法です。Operator SDK を使用して OLM でバンドルイメージを迅速に実行し、適切に実行されるようにできます。

前提条件

  • 開発ワークステーションに Operator SDK CLI がインストールされている。
  • ビルドされ、レジストリーにプッシュされる Operator バンドルイメージ。
  • (OpenShift Container Platform 4.12 など、apiextensions.k8s.io/v1 CRD を使用する場合は v1.16.0 以降の) Kubernetes ベースのクラスターに OLM がインストールされていること。
  • cluster-admin パーミッションのあるアカウントを使用して oc でクラスターへログインしていること。

手順

  1. 以下のコマンドを入力してクラスターで 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 フラグを追加して、インストールに異なる namespace スコープを設定できます。
    3
    イメージを指定しない場合、コマンドは quay.io/operator-framework/opm:latest をデフォルトのインデックスイメージとして使用します。イメージを指定した場合は、コマンドはバンドルイメージ自体をインデックスイメージとして使用します。
    重要

    OpenShift Container Platform 4.11 の時点で、Operator カタログに関して、run bundle コマンドはデフォルトでファイルベースのカタログ形式をサポートします。Operator カタログに関して、非推奨の SQLite データベース形式は引き続きサポートされますが、今後のリリースで削除される予定です。Operator の作成者はワークフローをファイルベースのカタログ形式に移行することが推奨されます。

    このコマンドにより、以下のアクションが行われます。

    • バンドルイメージをインジェクトしてインデックスイメージを作成します。インデックスイメージは不透明で一時的なものですが、バンドルを実稼働環境でカタログに追加する方法を正確に反映します。
    • 新規インデックスイメージを参照するカタログソースを作成します。これにより、OperatorHub が Operator を検出できるようになります。
    • OperatorGroupSubscriptionInstallPlan、および RBAC を含むその他の必要なリソースすべてを作成して、Operator をクラスターにデプロイします。

5.6.2.6. 関連情報

5.6.3. Java ベースの Operator のプロジェクトレイアウト

重要

Java ベースの Operator SDK はテクノロジープレビュー機能としてのみ提供されます。テクノロジープレビュー機能は、Red Hat 製品サポートのサービスレベルアグリーメント (SLA) の対象外であり、機能的に完全ではない場合があります。Red Hat は、実稼働環境でこれらを使用することを推奨していません。テクノロジープレビュー機能は、最新の製品機能をいち早く提供して、開発段階で機能のテストを行いフィードバックを提供していただくことを目的としています。

Red Hat のテクノロジープレビュー機能のサポート範囲に関する詳細は、テクノロジープレビュー機能のサポート範囲 を参照してください。

operator-sdk CLI は、各 Operator プロジェクトに多数のパッケージおよびファイルを生成、または スキャフォールディング することができます。

5.6.3.1. Java ベースのプロジェクトレイアウト

operator-sdk init コマンドで生成される Java ベースの Operator プロジェクトには、以下のファイルおよびディレクトリーが含まれます。

ファイルまたはディレクトリー目的

pom.xml

Operator の実行に必要な依存関係が含まれるファイル。

<domain>/

API を表すファイルが含まれるディレクトリー。ドメインが example.com の場合、このフォルダーは example/ と呼ばれます。

MemcachedReconciler.java

コントローラーの実装を定義する Java ファイル。

MemcachedSpec.java

Memcached CR の必要な状態を定義する Java ファイル。

MemcachedStatus.java

Memcached CR の観察される状態を定義する Java ファイル。

Memcached.java

Memcached API のスキーマを定義する Java ファイル。

target/kubernetes/

CRD yaml ファイルが含まれるディレクトリー。

5.6.4. 新しい Operator SDK バージョンのプロジェクトのアップグレード

OpenShift Container Platform 4.12 は Operator SDK 1.25.4 をサポートします。ワークステーションに 1.28.0 CLI がすでにインストールされている場合は、最新バージョンをインストール して CLI を 1.31.0 に更新できます。

ただし、既存の Operator プロジェクトが Operator SDK 1.25.4 との互換性を維持するには、1.22.2 以降に導入された関連する重大な変更に対し、更新手順を実行する必要があります。アップグレードの手順は、以前は 1.22.2 で作成または維持されている Operator プロジェクトのいずれかで手動で実行する必要があります。

5.6.4.1. Operator SDK 1.25.4 の Java ベースの Operator プロジェクトの更新

次の手順では、1.25.4 との互換性を確保するため、既存の Java ベースの Operator プロジェクトを更新します。

前提条件

  • Operator SDK 1.25.4 がインストールされている
  • Operator SDK 1.22.2 で作成または保守されている Operator プロジェクト

手順

  1. config/default/manager_auth_proxy_patch.yaml ファイルに以下の変更を加えます。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: controller-manager
      namespace: system
    spec:
      template:
        spec:
          containers:
          - name: kube-rbac-proxy
            image: registry.redhat.io/openshift4/ose-kube-rbac-proxy:v4.12 1
            args:
            - "--secure-listen-address=0.0.0.0:8443"
            - "--upstream=http://127.0.0.1:8080/"
            - "--logtostderr=true"
            - "--v=0"
    ...
    1
    タグバージョンを v4.11 から v4.12 に更新します。
  2. Makefile に以下の変更を加えます。

    1. マルチアーキテクチャービルドサポートを有効にするには、docker-buildx ターゲットをプロジェクトの Makefile に追加します。

      Makefile の例

      # PLATFORMS defines the target platforms for  the manager image be build to provide support to multiple
      # architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
      # - able to use docker buildx . More info: https://docs.docker.com/build/buildx/
      # - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/
      # - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=<myregistry/image:<tag>> than the export will fail)
      # To properly provided solutions that supports more than one platform you should use this option.
      PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
      .PHONY: docker-buildx
      docker-buildx: test ## Build and push docker image for the manager for cross-platform support
      	# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
      	sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
      	- docker buildx create --name project-v3-builder
      	docker buildx use project-v3-builder
      	- docker buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross
      	- docker buildx rm project-v3-builder
      	rm Dockerfile.cross

    2. Makefile に変更を適用し、Operator を再構築するには、次のコマンドを入力します。

      $ make

5.6.4.2. 関連情報