Operatorを作って、OpenShiftで動作させてみた

<!-- wp:heading -->
<h2 id="operatorについて">Operatorについて</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Operatorは、Custom Resource Definitionsのインスタンスの生成に応じて、Podの作成など特定の動作を行うプログラムです。KubernetesおよびOpenShiftで動作します。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>KubernetesやOpenShift上で動作するステートフル・アーキテクチャーの製品のインストーラや、その製品の稼働を支援するサポート・プログラム等を、Operatorを使って実装することができます。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>今回は、Operaotrのサンプル作成時の忘備録/メモとして、下記に記します。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Operatorの詳細については、<a href="https://cloud.redhat.com/learn/topics/operators">What is an Operator?</a>を参照ください。</p>
<!-- /wp:paragraph -->

試した環境は、OpenShift 4.6です。

<!-- wp:heading -->
<h2 id="サンプルのoperatorについて">サンプルのOperatorについて</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>この記事では、サンプルとして、製品の機能をチェックするオペレータを作成します。このサンプルのOperatorは、OpenShiftで、CRDのインスタンスが作成されると、Podが作成され、製品機能をチェックするプログラムを起動する、という振る舞いをします。</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 id="operatorによって作成されるポッド上で動作するプログラム-前提">Operatorによって作成されるポッド上で動作するプログラム（前提）</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>製品の機能をチェックするコンテナイメージを作成して、レジストリーに登録しておきます。（例として、onelineVerify.jar）</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>FROM docker.io/ibmjava
COPY onelineVerify.jar /onelineVerify.jar
RUN chmod +x /onelineVerify.jar
ENTRYPOINT &#91;"java","-jar", "/onelineVerify.jar"]
CMD &#91;"RepositoryURL","AdminID","Password"]</code></pre>
<!-- /wp:code -->

<!-- wp:code -->
<pre class="wp-block-code"><code>docker build -t quay.io/name/online-verify .
docker push quay.io/name/online-verify</code></pre>
<!-- /wp:code -->

<!-- wp:heading -->
<h2 id="operator-sdkのインストール">Operator SDKのインストール</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Operator SDKをインストールします。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>
# Operator SDKのダウンロード
export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac)
export OS=$(uname | awk '{print tolower($0)}')
export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/v1.11.0
curl -LO ${OPERATOR_SDK_DL_URL}/operator-sdk_${OS}_${ARCH}
chmod +x operator-sdk_${OS}_${ARCH} &amp;&amp; sudo mv operator-sdk_${OS}_${ARCH} /usr/local/bin/operator-sdk</code></pre>
<!-- /wp:code -->

<!-- wp:heading -->
<h2 id="ansible-ベースのオペレータ-テンプレートの作成">Ansible ベースのオペレータ・テンプレートの作成</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>初期化コマンドを使用して、オペレータのテンプレートを作成します。Anbisleベースが一番お手軽です。Ansibleベース以外に、Go言語ベース、Helmベースが選べます。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>mkdir -p ${HOME}/projects/sample-operator
cd ${HOME}/projects/sample-operator

# Ansibleベースのオペレータ・テンプレートの作成
operator-sdk init --plugins=ansible --domain=example.com</code></pre>
<!-- /wp:code -->

<!-- wp:heading -->
<h2 id="apiの追加と編集">APIの追加と編集</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>APIを作成し、チェックプログラムを実行するPodを作成する処理を記述します。APIに必要なパラメータを、CRDとして設定します。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code># APIの作成
operator-sdk create api --group sample --version v1 --kind Myapiname --generate-playbook</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>CRDのインスタンスが作成されたときの振る舞いを記述します。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>$home/projects/sample-operator/playbooks/myapiname.yml</code></pre>
<!-- /wp:code -->

<!-- wp:syntaxhighlighter/code {"language":"yaml"} -->
<pre class="wp-block-syntaxhighlighter-code">---
- hosts: localhost
  gather_facts: no
  collections:
    - community.kubernetes
    - operator_sdk.util

  vars:
    - elmns: '{{ ansible_operator_meta.namespace }}'

  tasks:

    - name: Create pod for ibm java
      community.kubernetes.k8s:
        state: present
        definition:
          apiVersion: v1
          kind: Pod
          metadata:
            name: '{{ ansible_operator_meta.name }}-ibmjava'
            namespace: '{{ ansible_operator_meta.namespace }}'
            labels:
              app: ibmjava
          spec:
            containers:
            - name: ibmjava
              args:
              - "{{ repository_url }}"
              - "{{ admin_user_id }}"
              - "{{ password }}"
              image: quay.io/name/online-verify</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>API実行に必要なCRDを定義します。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>$home/projects/sample-operator/config/crd/bases/sample.example.com_myapinames.yaml</code></pre>
<!-- /wp:code -->

<!-- wp:syntaxhighlighter/code {"language":"yaml"} -->
<pre class="wp-block-syntaxhighlighter-code">metadata:
  name: myapinames.sample.example.com
spec:
  group: sample.example.com
  names:
    kind: Myapiname
    listKind: MyapinameList
    plural: myapinames
    singular: myapiname
  scope: Namespaced
  versions:
  - name: v1
    schema:
      openAPIV3Schema:
        description: Myapiname is the Schema for the myapinames API
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: Spec defines the desired state of Myapiname
            type: object
            properties:
              repository_url:
                type: string
              admin_user_id:
                type: string
              password:
                type: string
            x-kubernetes-preserve-unknown-fields: true
          status:
            description: Status defines the observed state of Myapiname
            type: object
            x-kubernetes-preserve-unknown-fields: true
        type: object
    served: true
    storage: true
    subresources:
      status: {}</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>画面表示時のサンプル文字列を設定します。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>$home/projects/sample-operator/config/samples/aiasupport_v1_myapiname.yaml</code></pre>
<!-- /wp:code -->

<!-- wp:syntaxhighlighter/code {"language":"yaml"} -->
<pre class="wp-block-syntaxhighlighter-code">apiVersion: sample.example.com/v1
kind: Myapiname
metadata:
  name: myapiname-sample
spec:
  repository_url: https://elm.example.com/ccm
  admin_user_id: elmadmin
  password: password</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:heading -->
<h2 id="ビルド-レポジトリーへのプッシュ">ビルド・レポジトリーへのプッシュ</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Operatorのコンテナ・イメージと、Operatorバンドルのイメージを作成し、レジストリーにプッシュします。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>初回の <code>make bundle</code>コマンド時は、バンドル情報の入力を求められます。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>make docker-build IMG=quay.io/name/sample-operator:0.0.1
make docker-push IMG=quay.io/name/sample-operator:0.0.1
make bundle IMG=quay.io/name/sample-operator:0.0.1
make bundle-build BUNDLE_IMG=quay.io/name/sample-operator-bundle:0.0.1
make bundle-push BUNDLE_IMG=quay.io/name/sample-operator-bundle:0.0.1
</code></pre>
<!-- /wp:code -->

<!-- wp:heading -->
<h2 id="openshiftへのoperatorのデプロイ-インストール">OpenShiftへのOperatorのデプロイ（インストール）</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>以下のコマンドにより、レジストリーに登録されたOperatorバンドルイメージを、OpenShiftにデプロイします。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>operator-sdk run bundle quay.io/name/sample-operatorbundle:0.0.1</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>デプロイが成功すると、OpenShiftのメニューのInstalled Operatorsに、作成したOperatorが表示されます。</p>
<!-- /wp:paragraph -->

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/ec1ee0d3-9d40-33f8-79ae-c71804da49ca.png)


<!-- wp:heading -->
<h2 id="crdのインスタンス作成">CRDのインスタンス作成</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Openshiftのメニューから、Operatorに追加したAPI用のCRDのインスタンスを作成します。（例として、Myapiname）</p>
<!-- /wp:paragraph -->


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/47478e6a-e443-635e-36c4-f7b3dee659bc.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/4a0a7c3a-9638-753c-15fb-abaf455de901.png)


<!-- wp:paragraph -->
<p>CRDのインスタンスが作成されると、記述された処理が実行され、Pod作成および、チェックツールの実行が行われます。</p>
<!-- /wp:paragraph -->

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/f8366313-122b-e0fa-e7ae-6e4665e58b4e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203516/c683a597-dfaf-37a8-ad27-2f034ffcdb26.png)


<!-- wp:heading -->
<h2 id="operatorのアンデプロイ">Operatorのアンデプロイ</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>以下のコマンドで、OperatorをOpenShiftからアンデプロイ／アンインストールできます。</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"bash"} -->
<pre class="wp-block-syntaxhighlighter-code">operator-sdk cleanup sample-operator</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:heading -->
<h2 id="まとめ">まとめ</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Operatorのサンプルの作成について、記述しました。自分の備忘録およびメモのために作成しましたが、誰かに役に立てば幸いです。</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 id="参照">参照</h2>
<!-- /wp:heading -->

<!-- wp:list -->
<ul><li><a href="https://cloud.redhat.com/learn/topics/operators">What is an Operator?</a></li><li><a href="http://Operator SDK">Operator SDK</a></li><li><a href="https://operatorhub.io/">OperatorHub</a></li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->