ROKSでODF(OpenShift Data Foundation)を利用する



#1.目的
ROKS(Red Hat OpenShift on IBM Cloud)で利用できる外部ストレージの一つとしてSDS(Software Defined Storage)のRedHat OCS(Openshift Container Storage)ありましたがODF(OpenShift Data Foundation)と名前が変わり2021/10月に新しくリリースされました。ROKS Storageの動的プロビジョニングのためのPVC(Permanent Volume claim)を利用するためにはSDSでは新規にStorage Classを作成する必要ありますが、ODFでは以前のPortworxに比べて準備含めてStorage Class作成までの作業が大幅に軽減されています。本稿はこのODFの作成手順及び検証になります。

#2. ROKSのストレージ・サービスについて
ROKSで利用できるstorageサービスを簡単にまとめると以下表のようになります。ROKS-VPCではこれまでFileStorageが利用できなかったため業務システムの可用性を求めるのであればPortworxしか選択肢がありませんでした、ただしPortWokxはClusterへの導入前に(RawBlockDevice準備のため*1)BlockStorageを手動で追加後WorkerNodeに接続してStorageClassを作成する、IAM設定など結構煩雑なIBM Cloud CLIコマンド作業が必要でした。ODFでは、IBM Cloud Portal GUI画面からアドオンのボタンを押すだけでROKSのStorageClass作成され事前のBlockStorageのオーダーも不要で、作業負荷が大幅に軽減されています。またDISKサイズ拡張/追加/WorkerNode追加の際もPortworxは上記同様のStorage追加/接続作業,ポッド再起動が必要になるのに対してODFではCRD(Custom Resource Definition)の変更/クラスター適用のみで済み容易に行えます。価格もODFはPortworxより安くなっており大変利用しやすくなりました。

*1 BlockStorageが対象,ベアメタルの内蔵DISKは不要
*2 PortworxはWorkerNode更新の時、DISKの再接続(ROKS-VPC)、POD再起動(ROKS-Classic)必要になる。
[Portworx制限](https://cloud.ibm.com/docs/openshift?topic=openshift-portworx#portworx_limitations)


|項目 | FileStorage | BlockStorage |  Portworx | ODF |
|:-----------|:-----------:|:------------:|:------------:|:------------:|
|提供元| IBM　|IBM　| Portworx | Red Hat |
|タイプ  |FileStorage|BlockStorage|SDS|SDS|
|対応ROKS  |Classicのみ|Classic/VPC|Classic/VPC|Classic/VPC|
| 可用性     | ◯　複数ワーカー・ノード間の共有可能 |✖️単一ワーカー・ノードのアクセスのみ |◎複数ワーカー・ノード対応/複数ゾーン対応|◎複数ワーカー・ノード対応/複数ゾーン対応|
|アクセス|◯ RWX/ROX/RWO|△ RWOのみ  |◯ RWX/ROX/RWO|◯ RWX/ROX/RWO|
| 特徴  | 単一のゾーン・クラスター内でのみ複数ワーカー・ノード間ファイル共有        | 単一のポッドのハイパフォーマンス・アクセス  |複数のポッドとワーカー・ノードにまたがる共有ストレージ・アクセス及び複数ゾーン対応(データ複製あり)|複数のポッドとワーカー・ノードにまたがる共有ストレージ・アクセス及び複数ゾーン対応(データ複製あり)|


#3.OpenShift Data Foundation作成手順
### 前提条件
導入前に下記を確認ください
・OpenShift Data FoundationはROKS4.7以上でサポートされています。
・VPCではWorkerNode(最低16vCPU64GBメモリ)が3ノード以上必要になり、高可用性を確保するためMultiZoneで各々ゾーンに最低１台ずつの稼働が推奨されます。
・Classicの場合はODF のために必要なローカル・ディスクを備えたフレーバー・タイプ mb4c.32x384.3.8tb.ssd または mb4c.20x64.2x1.9tb.ssd のワーカー・ノード(10GpbsNIC)を選択して3 つのゾーンの各ゾーンにワーカー・ノード1台以上用意します。

###ODFアドオンのインストール

[コンソール画面よりインストール手順]
(https://cloud.ibm.com/docs/openshift?topic=openshift-deploy-odf-vpc#install-odf-console-vpc)

![スクリーンショット 2021-12-17 11.14.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/bb5a00da-5679-5c25-3e8f-30409eb2898e.png)

上記環境でのIBM Cloud Portal画面よりROKS-VPCにODFを導入する手順を説明します。まず導入対象のROKSクラスターの概要画面を開きます。

![スクリーンショット 2021-12-01 12.16.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/4aec22fe-8be0-94c8-168e-a8e6491c71ba.png)

下にスクロールすると、アドオンメニューがでてくるのでOpenShift Data　Foundationのインストールボタン押します。
![スクリーンショット 2021-12-01 12.17.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/2a99be14-3b54-b5d2-26a1-734200d94f8e.png)

パラメータ画面が現れるので、ここではデフォルト設定を利用するとしてインストールボタンを押すと導入が開始されます。

[パラメータ一覧]
(https://cloud.ibm.com/docs/openshift?topic=openshift-deploy-odf-vpc&locale=ja#odf-vpc-param-ref)

*ocsDeploy=True パラメーターを指定することで、デフォルトの構成パラメーターを使用してODFをデプロイします。Storageサイズを変更する場合はosdSizeの値を変更します。

![スクリーンショット 2021-12-01 12.18.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/45a97edc-c394-8d96-5f81-427599c7b486.png)

しばらくすると概要画面のアドオンのインストール済みにOpenShift Data　Foundationが現れます。これで導入作業自体は完了です。BlockStorage手動追加/WorkerNode接続などのCLIコマンドは一切不要です。

![スクリーンショット 2021-12-01 12.37.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/55bf19ad-6b73-ae8f-dc64-836e0d731a63.png)

###(ODF導入確認)
念のためODFが正常に導入されているか確認します。
対象Clusterにログインした後、ODF関連PODが正常に作成・稼働されていることを確認します。

```
 % oc get pods -n openshift-storage        
NAME                                                              READY   STATUS            RESTARTS   AGE
csi-cephfsplugin-c8fvb                                            3/3     Running           0          7m
csi-cephfsplugin-d5fsh                                            3/3     Running           0          7m
csi-cephfsplugin-provisioner-6c9776bbc8-8xzh4                     6/6     Running           0          7m
csi-cephfsplugin-provisioner-6c9776bbc8-xx4hf                     6/6     Running           0          7m
csi-cephfsplugin-qlrqs                                            3/3     Running           0          7m
csi-rbdplugin-pdfvn                                               3/3     Running           0          7m1s
csi-rbdplugin-provisioner-687475fc7-29qlk                         6/6     Running           0          7m1s
csi-rbdplugin-provisioner-687475fc7-49qrf                         6/6     Running           0          7m1s
csi-rbdplugin-rh78n                                               3/3     Running           0          7m1s
csi-rbdplugin-xwlfc                                               3/3     Running           0          7m1s
noobaa-core-0                                                     1/1     Running           0          40s
noobaa-db-pg-0                                                    0/1     PodInitializing   0          41s
noobaa-operator-cc59bd495-slq7c                                   1/1     Running           0          7m47s
ocs-metrics-exporter-69b665554b-q9t9n                             1/1     Running           0          7m47s
ocs-operator-b54b74c46-tkc9x                                      0/1     Running           0          7m47s
rook-ceph-crashcollector-10.10.0.12-f5b65f86b-qpzfw               1/1     Running           0          3m33s
rook-ceph-crashcollector-10.11.0.4-59dd9fbbd8-mjh8p               1/1     Running           0          4m22s
rook-ceph-crashcollector-10.12.12.4-6fbf976d8d-htv5v              1/1     Running           0          5m22s
rook-ceph-mds-ocs-storagecluster-cephfilesystem-a-c4d48c44j9rtf   2/2     Running           0          26s
rook-ceph-mds-ocs-storagecluster-cephfilesystem-b-7f46cd4cdmcnx   2/2     Running           0          25s
rook-ceph-mgr-a-556db4dfcf-x82l4                                  2/2     Running           0          2m29s
rook-ceph-mon-a-75d99c6bcc-56qt7                                  2/2     Running           0          5m30s
rook-ceph-mon-b-6b947b5959-8mspr                                  2/2     Running           0          4m22s
rook-ceph-mon-c-85cd4b55-d5v54                                    2/2     Running           0          3m33s
rook-ceph-operator-f45cb99f7-zd22c                                1/1     Running           0          7m47s
rook-ceph-osd-0-649c97f74c-nbr9r                                  2/2     Running           0          53s
rook-ceph-osd-1-d567f4478-2mn52                                   2/2     Running           0          52s
rook-ceph-osd-2-5ff7d948c4-btfng                                  2/2     Running           0          42s
rook-ceph-osd-prepare-ocs-deviceset-0-data-0kmpp8-xrjmh           0/1     Completed         0          2m28s
rook-ceph-osd-prepare-ocs-deviceset-1-data-05d7hm-rcglx           0/1     Completed         0          2m27s
rook-ceph-osd-prepare-ocs-deviceset-2-data-0wq5x7-wj6dg           0/1     Completed         0          2m27s
```

OCSclusterのカスタム・リソース定義 (CRD)を参照します。
ocscluster-autoという名前で作成されています

```
 % oc get ocscluster
NAME              AGE
ocscluster-auto   63s
```

ocscluster-autoの内容を確認すると、先ほどの
アドオンのインストール画面で入力したパラメーターが確認できます。

```
 % oc describe ocscluster ocscluster-auto
Name:         ocscluster-auto
Namespace:    
Labels:       <none>
Annotations:  <none>
API Version:  ocs.ibm.io/v1
Kind:         OcsCluster
Metadata:
  Creation Timestamp:  2021-12-01T03:19:02Z
  Finalizers:
    finalizer.ocs.ibm.io
  Generation:  1
  Managed Fields:
    API Version:  ocs.ibm.io/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:finalizers:
          .:
          v:"finalizer.ocs.ibm.io":
      f:spec:
        .:
        f:billingType:
        f:clusterEncryption:
        f:monSize:
        f:monStorageClassName:
        f:numOfOsd:
        f:ocsUpgrade:
        f:osdSize:
        f:osdStorageClassName:
      f:status:
        .:
        f:storageClusterStatus:
    Manager:         manager
    Operation:       Update
    Time:            2021-12-01T03:20:47Z
  Resource Version:  29515
  Self Link:         /apis/ocs.ibm.io/v1/ocsclusters/ocscluster-auto
  UID:               2559a231-4fe6-42c0-896d-1368e7e88ef9
Spec:
  Billing Type:            advanced
  Cluster Encryption:      false
  Mon Size:                20Gi
  Mon Storage Class Name:  ibmc-vpc-block-metro-10iops-tier
  Num Of Osd:              1
  Ocs Upgrade:             false
  Osd Size:                250Gi
  Osd Storage Class Name:  ibmc-vpc-block-metro-10iops-tier
Status:
  Storage Cluster Status:  Ready
Events:                    <none>
 % oc get ocscluster
NAME              AGE
ocscluster-auto   6h9m
```

###ODFを使用するアプリをデプロイしてアクセスする。

AddOnの導入により作成されたODFのストレージクラスをリストします。

```
 % oc get sc | grep openshift

ocs-storagecluster-ceph-rbd                   openshift-storage.rbd.csi.ceph.com      Delete          Immediate              true                   18m
ocs-storagecluster-ceph-rgw                   openshift-storage.ceph.rook.io/bucket   Delete          Immediate              false                  18m
ocs-storagecluster-cephfs                     openshift-storage.cephfs.csi.ceph.com   Delete          Immediate              true                   18m
openshift-storage.noobaa.io                   openshift-storage.noobaa.io/obc         Delete          Immediate              false                  10m
```
上記ストレージ・クラスを参照するPVC を作成します。 
以下ではocs-storagecluster-cephfs ストレージ・クラスを使用するためのPVC用のyamlファイルを作成します

```
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: odf-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: ocs-storagecluster-cephfs
```
該当クラスター内に PVC を作成します。

```
 % oc create -f odf_pv.yaml 
persistentvolumeclaim/odf-pvc created
```

作成したPVCをマウントするアプリケーションを作成します。
以下の例では、test.txt ファイルに現在の日時を書き込む nginx ポッドを作成します。

```
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: nginx
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo $(date -u) >> /test/test.txt; sleep 600; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /test
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: odf-pvc
```
クラスター内にポッドを作成します。ポッドがデプロイされたことを確認するために、アプリが Running 状況になるまで待ちます。

```
 % oc create -f odf_app.yaml
pod/app created
% oc get pods
NAME   READY   STATUS    RESTARTS   AGE
app    1/1     Running   0          6m51s

```

PODにログインして、アプリケーションがデータを書き込めることを確認します。

```
 % oc get pods
NAME   READY   STATUS    RESTARTS   AGE
app    1/1     Running   0          6m51s
 % oc exec app -it bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@app:/# cat /test/test.txt
Wed Dec 1 03:53:38 UTC 2021
root@app:/# exit
exit
```

[https://cloud.ibm.com/docs/openshift?topic=openshift-ocs-deploy-app]

###ODFを使用するアプリをデプロイして複数ゾーン・ノードからアクセスする。

次に他ゾーンのWorker Nodeから参照できるかの確認を行います。
現在のPODはWorkerNode10.12.12.4で稼働しています

```
 % oc get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
app    1/1     Running   0          11m   172.17.28.170   10.12.12.4   <none> 

```

参照用のアプリケーション作成して上記で確認した他Nodeで稼働させます

```
apiVersion: v1
kind: Pod
metadata:
  name: app01
spec:
  containers:
  - name: app01
    image: nginx
    volumeMounts:
    - name: persistent-storage
      mountPath: /test
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: odf-pvc
```
他ゾーンのWorker NodeにScheduleされるようにcordon実施します

```
 % oc adm cordon 10.12.12.4
node/10.12.12.4 cordoned
```
参照用のアプリケーション用のpodを作成します

```
 % oc create -f odf_app01.yaml
pod/app01 created
```

他Node10.10.0.12で稼働していることを確認

```
 % oc get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
app01   1/1     Running   0          23s   172.17.13.113   10.10.0.12   <none>           <none>
```

PODにログインして先ほどのアプリケーションで作成・書き込みしたファイルが参照できるか確認します。

```
 % oc exec app01 -it bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@app01:/# cat /test/test.txt
Wed Dec 1 03:53:38 UTC 2021
Wed Dec 1 04:03:38 UTC 2021
Wed Dec 1 04:13:38 UTC 2021
Wed Dec 1 04:23:38 UTC 2021
```

###参考 (IBM Cloud CLIを利用してODFを作成する手順)
[CLI からのアドオンのインストール]
(https://cloud.ibm.com/docs/openshift?topic=openshift-deploy-odf-vpc#install-odf-cli-vpc)

[ODF カスタム・リソースの作成]
(https://cloud.ibm.com/docs/openshift?topic=openshift-deploy-odf-vpc#ocs-vpc-deploy-crd)

ここではIBM Cloud CLIを利用してODFを作成する手順を紹介します。導入対象のクラスタにログイン後アドオンInstallを実行します。ここでは"odfDeploy=false"を指定して、後ほどカスタム・リソース定義 (CRD)を作成してStorageSizeを変更できるようにします。

```
 % ibmcloud oc cluster addon enable openshift-data-foundation -c sakacluster-jp-tok-3-bx2.16x64 --version 4.7.0 --param "odfDeploy=false"
クラスター sakacluster-jp-tok-3-bx2.16x64 のアドオン openshift-data-foundation(4.7.0) を有効にしています...
アドオンのデプロイが完了して利用可能になるには数分かかる場合があります。
インストール・オプションを使用します...

アドオン・オプション
オプション                 値   
osdStorageClassName        ibmc-vpc-block-metro-10iops-tier   
workerNodes                all   
containerPrivateEndpoint   <Please provide the satellite link for the container private endpoint if using a satellite cluster>   
monSize                    20Gi   
ocsUpgrade                 false   
osdDevicePaths             <Please provide IDs of the disks to be used for OSD pods if using local disks or standard classic cluster>   
numOfOsd                   1   
odfDeploy                  false   
osdSize                    250Gi   
billingType                advanced   
clusterEncryption          false   
monDevicePaths             <Please provide IDs of the disks to be used for mon pods if using local disks or standard classic cluster>   
monStorageClassName        ibmc-vpc-block-metro-10iops-tier   
OK

 % ibmcloud oc cluster addon ls -c sakacluster-jp-tok-3-bx2.16x64
OK
名前                        バージョン   正常性の状態   正常性の状況   
openshift-data-foundation   4.7.0        -              Enabling   
vpc-block-csi-driver        4.0          normal         Addon Ready. For more info: http://ibm.biz/addon-state (H1500)   
 % oc get pods -A | grep ibm-ocs-operator-controller-manager

kube-system                                        ibm-ocs-operator-controller-manager-58fcf45bd6-q6b2q    1/1     Running   0          51s

```

OcsCluster という名前のカスタム・リソース定義 (CRD) を作成します。 
ここではStorageClassはMulti-Zone用のBlockStorageのibmc-vpc-block-10iops-tierを利用します。

```
apiVersion: ocs.ibm.io/v1
kind: OcsCluster
metadata:
 name: ocscluster-vpc
spec:
 monStorageClassName: ibmc-vpc-block-10iops-tier  # For multizone clusters, specify a storage class with a waitForFirstConsumer volume binding mode
 monSize: 20gi
 osdStorageClassName: ibmc-vpc-block-10iops-tier  # For multizone clusters, specify a storage class with a waitForFirstConsumer volume binding mode
 osdSize: 100gi # The OSD size is the total storage capacity of your OCS storage cluster
 numOfOsd: 1
 billingType: advanced
 ocsUpgrade: false
```
該当クラスターに上記のOcsClusterカスタム・リソースを作成します。

```
 % oc create -f odf01.yaml              
ocscluster.ocs.ibm.io/ocscluster-vpc created

```
あとは、PVC作成以降はCloudPortalからの手順と同様になります。
ODF再導入が必要になる場合はまずは下記のようにocsclusterの削除が必要になります。

```
 % oc get ocscluster
NAME             AGE
ocscluster-vpc   27m
 % oc delete ocscluster ocscluster-vpc
ocscluster.ocs.ibm.io "ocscluster-vpc" deleted

```