CNSAによりOpenShiftからIBM Storage Scaleを永続ボリュームとして利用する環境の構築

# はじめに

本記事では、OpenShiftクラスタから分散ファイルシステムの一つであるIBM Storage Scaleを永続ストレージとして使用するための環境構築手順を示します。
IBM Storage Scale Container Native Storage Access (CNSA) により、IBM Storage Scaleのファイルシステムに作成したPersistent Volume (PV) をOpenShift上のコンテナから利用できるようにします。
なお、検証環境はIBM Powerサーバ (ppc64le) を使用していますが、適用するMachine Config Operatorの違いを除けば他のアーキテクチャでも手順に大きな違いはありません。

# 目次

1. [検証環境](#検証環境)
1. [前提条件](#前提条件)
1. [Storage Scaleの事前作業](#storage-scaleの事前作業)
1. [OpenShiftの事前作業](#openshiftの事前作業)
1. [CNSAのインストール](#cnsaのインストール)
1. [まとめ](#まとめ)
1. [参考文献](#参考文献)

# 検証環境

以下のように、master node 3ノード、worker node 2ノードで構成されるOpenShiftクラスタ (左)、及びストレージ側のNSD node 2ノードで構成されるScaleクラスタ (右)、がそれぞれ構築済みの環境に対して、CNSAをインストールして、OpenShiftクラスタからストレージ側のScale ClusterのPVを使用できるよう構成します。
OpenShiftクラスタのworker node 2ノードによるScaleクラスタの作成やストレージ側のScaleクラスタとのリモートマウントの構成は本手順内でCNSAを使用して実施します。
なお、本検証ではクラスタを構成する全てのノードをIBM Powerサーバ (ppc64le) のLPARに構築しています。

![ocp-env.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936643/103d44c3-9a0b-63ad-dc75-27bff3d5a29e.png)

# 前提条件

以下の作業が完了していることを想定しています。

- OpenShiftクラスタが構築済み
- ストレージ側のScaleクラスタが構築済み
- ストレージ側のScaleクラスタにファイルシステムが作成済み
- ストレージ側のScaleクラスタ内のnsd nodeにScale GUIを構成済み

# Storage Scaleの事前作業

ストレージ側のScale GUIをインストールしたnsd nodeへSSHログインします。
```shell-session
# ssh root@<NSD_NODE>
```

CNSAとCSI用のScale GUIユーザを作成します。(-pオプションで指定するパスワードは適宜置き換えてください。パスワードの期限を設定したくない場合は、下記の例のように "-e 1" を指定します)
```shell-session
# /usr/lpp/mmfs/gui/cli/mkuser cnsa_storage_gui_user -p cnsa_storage_gui_password -g ContainerOperator -e 1
EFSSG0019I The user cnsa_storage_gui_user has been successfully created. 
EFSSG1000I The command completed successfully. 
```

```shell-session
# /usr/lpp/mmfs/gui/cli/mkuser csi_storage_gui_user -p csi_storage_gui_password -g CsiAdmin -e 1
EFSSG0019I The user csi_storage_gui_user has been successfully created. 
EFSSG1000I The command completed successfully. 
```

Scaleクラスタの設定値を以下のように変更します。
```shell-session
# /usr/lpp/mmfs/bin/mmchfs fs1 --noperfileset-quota 
mmchfs: Propagating the cluster configuration data to all 
  affected nodes.  This is an asynchronous process. 
```
 
```shell-session
# /usr/lpp/mmfs/bin/mmchfs fs1 -Q yes 
mmchfs: Propagating the cluster configuration data to all 
  affected nodes.  This is an asynchronous process. 
```

```shell-session
# /usr/lpp/mmfs/bin/mmchconfig enforceFilesetQuotaOnRoot=yes -i 
mmchconfig: Command successfully completed 
mmchconfig: Propagating the cluster configuration data to all 
  affected nodes.  This is an asynchronous process. 
```

```shell-session
# /usr/lpp/mmfs/bin/mmchconfig controlSetxattrImmutableSELinux=yes -i 
mmchconfig: Command successfully completed 
mmchconfig: Propagating the cluster configuration data to all 
  affected nodes.  This is an asynchronous process. 
```

```shell-session
# /usr/lpp/mmfs/bin/mmchfs fs1 --filesetdf 
```

```shell-session
# /usr/lpp/mmfs/bin/mmchfs fs1 --auto-inode-limit 
```

```shell-session
# /usr/lpp/mmfs/bin/mmchconfig tscCmdAllowRemoteConnections=no -i 
mmchconfig: [I] Setting the tscCmdAllowRemoteConnections configuration parameter to "no" requires all remote clusters to be running with release level (minReleaseLevel) set to at least 5.1.3.0. Otherwise, set tscCmdAllowRemoteConnections to "yes". 
mmchconfig: Command successfully completed 
mmchconfig: Propagating the cluster configuration data to all 
  affected nodes.  This is an asynchronous process. 
```

(補足) tscCmdAllowRemoteConnectionsはバージョンによって推奨値が異なります。Storage Scale、及びStorage Scale container nativeのバージョンが5.1.3以降の場合は、"no" が推奨値となります。

# OpenShiftの事前作業

OpenShiftクラスタへログインします。
```shell-session
# oc login https://<URL>:6443 -u kubeadmin
```

IBM Storage Scaleのコンテナイメージを取得するために、[IBM container software library](https://myibm.ibm.com/products-services/containerlibrary) にて、entitlement keyを作成して、コピーします。

作成したkeyのbase64エンコード文字列を生成します。("REPLACE_WITH_GENERATED_ENTITLEMENT_KEY" は前ステップでコピーしたkeyで置き換えます)
```shell-session
# echo -n "cp:REPLACE_WITH_GENERATED_ENTITLEMENT_KEY" | base64 -w0
```

authority.jsonを作成します。("REPLACE_WITH_BASE64_ENCODED_KEY_FROM_PREVIOUS_STEP"は前ステップで作成したbase64エンコード文字列で、"REPLACE_WITH_GENERATED_ENTITLEMENT_KEY"はkeyで置き換えます)
```shell-session
# cat << EOF > authority.json
{
  "auth": "REPLACE_WITH_BASE64_ENCODED_KEY_FROM_PREVIOUS_STEP",
  "username":"cp",
  "password":"REPLACE_WITH_GENERATED_ENTITLEMENT_KEY"
}
EOF
```

authority.jsonを".dockerconfigjson"に追加するため、一時ファイルをtemp_config.jsonに出力します。
```shell-session
# oc get secret/pull-secret -n openshift-config -ojson | \ 
jq -r '.data[".dockerconfigjson"]' | \ 
base64 --decode | \ 
jq '.[]."cp.icr.io" += input' - authority.json > temp_config.json 
```

temp_config.jsonの出力内容にauthority.jsonの内容が含まれるか確認します。
```shell-session
# cat temp_config.json | grep cp.icr.io -A4
    "cp.icr.io": {
      "auth": "REPLACE_WITH_BASE64_ENCODED_KEY_FROM_PREVIOUS_STEP",
      "username": "cp",
      "password":"REPLACE_WITH_GENERATED_ENTITLEMENT_KEY"
    }
```

temp_config.jsonの内容をpull secretに反映します。
```shell-session
# oc set data secret/pull-secret -n openshift-config --from-file=.dockerconfigjson=temp_config.json
secret/pull-secret data updated 
```

pull secretが正しく更新されたことを確認します。
```shell-session
# oc get secret/pull-secret -n openshift-config -ojson | \ 
jq -r '.data[".dockerconfigjson"]' | \ 
base64 -d - 
```

pull secretを更新後、全てのノードに反映されたか確認します。(UPDATEDがFalseからTrueに変わることを確認します)
```shell-session
# oc get mcp 
NAME     CONFIG                                             UPDATED   UPDATING   DEGRADED   MACHINECOUNT   READYMACHINECOUNT   UPDATEDMACHINECOUNT   DEGRADEDMACHINECOUNT   AGE 
master   rendered-master-5aef6880696be7056e06f3aaff5a4f99   False     True       False      3              0                   0                     0                      29h 
worker   rendered-worker-a8181618befe656a89764715b24b4c5a   False     True       False      2              0                   0                     0                      29h 
```

```shell-session
# oc get mcp 
NAME     CONFIG                                             UPDATED   UPDATING   DEGRADED   MACHINECOUNT   READYMACHINECOUNT   UPDATEDMACHINECOUNT   DEGRADEDMACHINECOUNT   AGE 
master   rendered-master-3b1d34897e4400b2c72de5e00c60102e   True      False      False      3              3                   3                     0                      29h 
worker   rendered-worker-6934d103c902c19881c854556918a877   True      False      False      2              2                   2                     0                      29h 
```

worker nodeにMachine Config Operator (MCO) を適用します。(本検証環境では、ppc64leアーキテクチャ用のOperatorを適用しています)
```shell-session
# oc apply -f https://raw.githubusercontent.com/IBM/ibm-spectrum-scale-container-native/v5.1.9.x/generated/scale/mco/ocp4.14/mco_ppc64le.yaml 
machineconfig.machineconfiguration.openshift.io/00-worker-ibm-spectrum-scale-kernel-devel created
```

MCO適用後、全worker nodeに反映されたか確認します。(UPDATEDがFalseからTrueに変わることを確認します)
```shell-session
# oc get mcp 
NAME     CONFIG                                             UPDATED   UPDATING   DEGRADED   MACHINECOUNT   READYMACHINECOUNT   UPDATEDMACHINECOUNT   DEGRADEDMACHINECOUNT   AGE 
master   rendered-master-3b1d34897e4400b2c72de5e00c60102e   True      False      False      3              3                   3                     0                      29h 
worker   rendered-worker-6934d103c902c19881c854556918a877   False     True       False      2              0                   0                     0                      29h 
```

```shell-session
# oc get mcp 
NAME     CONFIG                                             UPDATED   UPDATING   DEGRADED   MACHINECOUNT   READYMACHINECOUNT   UPDATEDMACHINECOUNT   DEGRADEDMACHINECOUNT   AGE 
master   rendered-master-3b1d34897e4400b2c72de5e00c60102e   True      False      False      3              3                   3                     0                      29h 
worker   rendered-worker-43bacb06a2e3f90e61c07f880f2a8a95   True      False      False      2              2                   2                     0                      29h 
```

worker nodeにkernel-develがインストールされたことを確認します。
```shell-session
# oc get nodes -lscale.spectrum.ibm.com/daemon-selector= \
-ojsonpath="{range .items[*]}{.metadata.name}{'\n'}" |\
xargs -I{} oc debug node/{} -T -- chroot /host sh -c "rpm -q kernel-devel" 2> /dev/null
kernel-devel-5.14.0-284.71.1.el9_2.ppc64le
kernel-devel-5.14.0-284.71.1.el9_2.ppc64le
```

# CNSAのインストール

worker node2台がScaleのquorum nodeの役割を持つように手動でラベルをセットします。(worker nodeが3台未満の場合は、quorumの自動割当に失敗するため、手動で割り当てる必要があります。3台以上ある場合は、自動割当が可能であるため、本手順は必ずしも必要ありません)
```shell-session
# oc label node worker1.ocp4.ocptest.com scale.spectrum.ibm.com/designation=quorum 
node/worker1.ocp4.ocptest.com labeled 
```

```shell-session
# oc label node worker2.ocp4.ocptest.com scale.spectrum.ibm.com/designation=quorum 
node/worker2.ocp4.ocptest.com labeled 
```

worker nodeにStorage Scaleをインストールします。
```shell-session
# oc apply -f https://raw.githubusercontent.com/IBM/ibm-spectrum-scale-container-native/v5.1.9.x/generated/scale/install.yaml 
namespace/ibm-spectrum-scale created 
namespace/ibm-spectrum-scale-csi created 
namespace/ibm-spectrum-scale-dns created 
namespace/ibm-spectrum-scale-operator created 
...<略>...
validatingwebhookconfiguration.admissionregistration.k8s.io/ibm-spectrum-scale-validating-webhook-configuration created 
```

```shell-session
# oc get namespaces | grep ibm-spectrum-scale 
ibm-spectrum-scale                                 Active   30s 
ibm-spectrum-scale-csi                             Active   30s 
ibm-spectrum-scale-dns                             Active   30s 
ibm-spectrum-scale-operator                        Active   30s 
```

```shell-session
# oc get pods -n ibm-spectrum-scale-operator 
NAME                                                     READY   STATUS    RESTARTS   AGE 
ibm-spectrum-scale-controller-manager-85597c84bf-hbwzh   1/1     Running   0          53s 
```

```shell-session
# oc get pods -n ibm-spectrum-scale-csi 
NAME                                               READY   STATUS    RESTARTS   AGE 
ibm-spectrum-scale-csi-operator-75c9f5978d-8gp9p   1/1     Running   0          61s 
```

Storage Scaleのコンテナイメージのpull secretを関係するnamespaceに作成します。
```shell-session
# export ENTITLEMENT_KEY=<REPLACE WITH ICR ENTITLEMENT KEY>
```

```shell-session
# for namespace in ibm-spectrum-scale ibm-spectrum-scale-dns ibm-spectrum-scale-csi; do 
    oc create secret docker-registry ibm-entitlement-key -n ${namespace} \ 
    --docker-server=cp.icr.io \ 
    --docker-username cp \ 
    --docker-password ${ENTITLEMENT_KEY} 
  done 
secret/ibm-entitlement-key created 
secret/ibm-entitlement-key created 
secret/ibm-entitlement-key created 
```

```shell-session
# unset ENTITLEMENT_KEY 
```

ClusterのCustom Resource Definition (CRD) をダウンロードします。
```shell-session
# curl -fs https://raw.githubusercontent.com/IBM/ibm-spectrum-scale-container-native/v5.1.9.x/generated/scale/v1beta1/cluster/cluster.yaml > cluster.yaml || echo "Failed to download Cluster Sample CR" 
```

worker node 2ノードでクラスタを構成するようラベルをセットします。
```shell-session
# oc label nodes -lnode-role.kubernetes.io/worker= scale.spectrum.ibm.com/daemon-selector= 
node/worker1.ocp4.ocptest.com labeled 
node/worker2.ocp4.ocptest.com labeled
```

ライセンス承諾の項目をfalseからacceptへ変更します。
```shell-session
# sed -i 's/accept: false/accept: true/' cluster.yaml
```

```shell-session
# grep -v '#' cluster.yaml | grep accept
    accept: true 
```

ClusterのCRDを適用します。
```shell-session
# oc apply -f cluster.yaml 
cluster.scale.spectrum.ibm.com/ibm-spectrum-scale created 
```

Clusterが作成され、いくつかのpodがRunning状態になっていることを確認します。
```shell-session
# oc get cluster 
NAME                 EDITION       AGE 
ibm-spectrum-scale   data-access   6s 
```

```shell-session
# oc get pods -n ibm-spectrum-scale 
NAME                               READY   STATUS    RESTARTS        AGE 
ibm-spectrum-scale-gui-0           4/4     Running   1 (100s ago)    4m58s 
ibm-spectrum-scale-gui-1           4/4     Running   3 (51s ago)     117s 
ibm-spectrum-scale-pmcollector-0   2/2     Running   0               4m58s 
ibm-spectrum-scale-pmcollector-1   2/2     Running   0               3m56s 
worker1                            2/2     Running   1 (3m24s ago)   4m58s 
worker2                            2/2     Running   1 (3m25s ago)   4m58s
```

リモートマウントの準備として、ストレージ側のScaleクラスタのGUIユーザのsecretを作成します。
```shell-session
# oc create secret generic cnsa-remote-mount-storage-cluster-1 --from-literal=username='cnsa_storage_gui_user' --from-literal=password='cnsa_storage_gui_password' -n ibm-spectrum-scale
secret/cnsa-remote-mount-storage-cluster-1 created 
```

```shell-session
# oc create secret generic csi-remote-mount-storage-cluster-1 --from-literal=username='csi_storage_gui_user' --from-literal=password='csi_storage_gui_password' -n ibm-spectrum-scale-csi
secret/csi-remote-mount-storage-cluster-1 created 
```

```shell-session
# oc label secret csi-remote-mount-storage-cluster-1 -n ibm-spectrum-scale-csi product=ibm-spectrum-scale-csi
secret/csi-remote-mount-storage-cluster-1 labeled 
```

リモートマウントの準備として、Storage Scale GUIのCA certificate取得して、ConfigMapを作成します。(GUIのIPアドレスは環境に合わせて変更してください)
```shell-session
# oc create configmap cacert-storage-cluster-1 --from-literal=storage-cluster-1.crt="$(openssl s_client -showcerts -connect 192.168.0.8:443 </dev/null 2>/dev/null|openssl x509 -outform PEM)" -n ibm-spectrum-scale 
configmap/cacert-storage-cluster-1 created 
```

RemoteClusterのCRDをダウンロードします。
```shell-session
# curl -fs https://raw.githubusercontent.com/IBM/ibm-spectrum-scale-container-native/v5.1.9.x/generated/scale/v1beta1/remotecluster/remotecluster.yaml > remotecluster.yaml || echo "Failed to download RemoteCluster Sample CR" 
```

RemoteClusterの設定項目を変更します。
```shell-session
# vi remotecluster.yaml
-> 環境に合わせて、リモートクラスタ名、ストレージ側のContact Node、ストレージ側のScale GUIのホスト名、などを変更します。
```

DNSにストレージ側のnsd nodeの情報を登録します。
```shell-session
# vi /var/named/reverse.db
-> 逆引き名前解決ゾーンファイルにストレージ側のnsd nodeの情報を登録します。
```

```shell-session
# vi /var/named/zonefile.db
-> 正引き名前解決ゾーンファイルにストレージ側のnsd nodeの情報を登録します。
```

```shell-session
# systemctl restart named
```

RemoteClusterのCRDを適用します。
```shell-session
# oc apply -f remotecluster.yaml 
remotecluster.scale.spectrum.ibm.com/remotecluster created 
```

RemoteClusterが作成されたことを確認します。
```shell-session
# oc get remotecluster -n ibm-spectrum-scale 
NAME            HOST       READY   AGE 
remotecluster   nsd1       True    16s 
```

FilesystemのCRDをダウンロードします。
```shell-session
# curl -fs https://raw.githubusercontent.com/IBM/ibm-spectrum-scale-container-native/v5.1.9.x/generated/scale/v1beta1/filesystem/filesystem.remote.yaml > filesystem.remote.yaml || echo "Failed to download Filesystem Sample CR" 
```

Filesystemの設定項目を変更します。
```shell-session
# vi filesystem.remote.yaml
-> 環境に合わせて、ファイルシステム名、リモートクラスタ名、などを変更します。
```

FilesystemのCRDを適用します。
```shell-session
# oc apply -f filesystem.remote.yaml 
filesystem.scale.spectrum.ibm.com/remote created 
```

Filesystemが作成されていることを確認します。
```shell-session
# oc get filesystem -n ibm-spectrum-scale 
NAME     ESTABLISHED   AGE 
remote   False         12s 
```

OpenShift側のworker nodeにScaleクラスタが正しく構成されたか確認します。
```shell-session
# oc get pods -n ibm-spectrum-scale 
NAME                               READY   STATUS    RESTARTS      AGE 
ibm-spectrum-scale-gui-0           4/4     Running   1 (90m ago)   93m 
ibm-spectrum-scale-gui-1           4/4     Running   3 (89m ago)   90m 
ibm-spectrum-scale-pmcollector-0   2/2     Running   0             93m 
ibm-spectrum-scale-pmcollector-1   2/2     Running   0             92m 
worker1                            2/2     Running   1 (92m ago)   93m 
worker2                            2/2     Running   1 (92m ago)   93m 
```

```shell-session
#  oc exec $(oc get pods -lapp.kubernetes.io/name=core \ 
-ojsonpath="{.items[0].metadata.name}" -n ibm-spectrum-scale)  \ 
-c gpfs -n ibm-spectrum-scale -- mmlscluster 
 
GPFS cluster information 
======================== 
  GPFS cluster name:         ibm-spectrum-scale.stg.ocp4.ocptest.com 
  GPFS cluster id:           11759767058287518289 
  GPFS UID domain:           ibm-spectrum-scale.stg.ocp4.ocptest.com 
  Remote shell command:      /usr/bin/ssh 
  Remote file copy command:  /usr/bin/scp 
  Repository type:           CCR 
 
 Node  Daemon node name                                         IP address    Admin node name                                         Designation 
-------------------------------------------------------------------------------------------------------------------------------------------------- 
   1   worker1.daemon.ibm-spectrum-scale.stg.ocp4.ocptest.com.  192.168.0.6  worker1.admin.ibm-spectrum-scale.stg.ocp4.ocptest.com.  quorum-manager-perfmon 
   2   worker2.daemon.ibm-spectrum-scale.stg.ocp4.ocptest.com.  192.168.0.7  worker2.admin.ibm-spectrum-scale.stg.ocp4.ocptest.com.  quorum-manager-perfmon 
```

```shell-session
# oc exec $(oc get pods -lapp.kubernetes.io/name=core \ 
-ojsonpath="{.items[0].metadata.name}" -n ibm-spectrum-scale)  \ 
-c gpfs -n ibm-spectrum-scale -- mmgetstate -a 
 
 Node number  Node name  GPFS state   
------------------------------------- 
           1  worker1    active 
           2  worker2    active 
```

```shell-session
# oc get remotecluster.scale -n ibm-spectrum-scale 
NAME            HOST       READY   AGE 
remotecluster   nsd1       True    9m42s 
```

```shell-session
# oc get filesystem.scale -n ibm-spectrum-scale 
NAME     ESTABLISHED   AGE 
remote   True          3m23s 
```

```shell-session
# oc exec $(oc get pods -lapp.kubernetes.io/name=core \ 
> -ojsonpath="{.items[0].metadata.name}" -n ibm-spectrum-scale)  \ 
> -c gpfs -n ibm-spectrum-scale -- mmlsmount remote -L 
                                                                       
File system remote (test.ocptest.com:fs1) is mounted on 4 nodes: 
  192.168.0.8    nsd1                    scale.ocptest.com           
  192.168.0.9    nsd2                    scale.ocptest.com           
  192.168.0.6    worker1.daemon.ibm-spectrum-scale.stg.ocp4.ocptest.com. ibm-spectrum-scale.stg.ocp4.ocptest.com  
  192.168.0.7    worker2.daemon.ibm-spectrum-scale.stg.ocp4.ocptest.com. ibm-spectrum-scale.stg.ocp4.ocptest.com  
```

```shell-session
# oc get pods -n ibm-spectrum-scale-csi 
NAME                                                  READY   STATUS    RESTARTS   AGE 
ibm-spectrum-scale-csi-7pcwv                          3/3     Running   0          3m43s 
ibm-spectrum-scale-csi-attacher-7b667f577-4zqdv       1/1     Running   0          3m43s 
apiVersion: storage.k8s.io/v1 
ibm-spectrum-scale-csi-attacher-7b667f577-9wnr8       1/1     Running   0          3m43s 
ibm-spectrum-scale-csi-hrd8l                          3/3     Running   0          3m43s 
ibm-spectrum-scale-csi-operator-75c9f5978d-8gp9p      1/1     Running   0          5h9m 
ibm-spectrum-scale-csi-provisioner-58b6f949cc-666cd   1/1     Running   0          3m43s 
ibm-spectrum-scale-csi-resizer-5b7c48f489-p8wv7       1/1     Running   0          3m43s 
ibm-spectrum-scale-csi-snapshotter-5b88f546c8-q6kts   1/1     Running   0          3m43s 
```
 
```shell-session
# oc get pods -n ibm-spectrum-scale-dns 
NAME            READY   STATUS    RESTARTS   AGE 
coredns-24tfl   1/1     Running   0          97m 
coredns-9rrbx   1/1     Running   0          97m 
coredns-d8b96   1/1     Running   0          97m 
coredns-xpx4f   1/1     Running   0          97m 
coredns-zlmmv   1/1     Running   0          97m 
```

ファイルセット単位でボリュームを提供するストレージクラスを定義します。(クラスタIDには、ストレージ側のScaleクラスタのクラスタIDを入力します)
```shell-session
# cat << EOF > storageClass_fileset.yaml  
apiVersion: storage.k8s.io/v1 
kind: StorageClass 
metadata: 
    name: ibm-spectrum-scale-csi-fileset 
provisioner: spectrumscale.csi.ibm.com 
parameters: 
    volBackendFs: remote 
    clusterId: "3691603570354871692" 
reclaimPolicy: Delete 
EOF
```

```shell-session
# oc apply -f storageClass_fileset.yaml  
storageclass.storage.k8s.io/ibm-spectrum-scale-csi-fileset created 
```

```shell-session
# oc get sc 
NAME                             PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE 
ibm-spectrum-scale-csi-fileset   spectrumscale.csi.ibm.com      Delete          Immediate              false                  17s 
ibm-spectrum-scale-internal      kubernetes.io/no-provisioner   Delete          WaitForFirstConsumer   false                  3h28m 
ibm-spectrum-scale-sample        spectrumscale.csi.ibm.com      Delete          Immediate              true                   42m 
```

試しにPVを作成してみます。
```shell-session
# cat << EOF > ibm-spectrum-scale-pvc-1.yaml  
apiVersion: v1 
kind: PersistentVolumeClaim 
metadata: 
  name: ibm-spectrum-scale-pvc-1 
spec: 
  storageClassName: ibm-spectrum-scale-csi-fileset 
  accessModes: 
    - ReadWriteMany 
  resources: 
    requests: 
      storage: 1Gi 
EOF
```

```shell-session
# oc apply -f ibm-spectrum-scale-pvc-1.yaml  
persistentvolumeclaim/ibm-spectrum-scale-pvc-1 created 
```

```shell-session
# oc get pvc 
NAME                       STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS                     AGE 
ibm-spectrum-scale-pvc-1   Pending                                      ibm-spectrum-scale-csi-fileset   3s 
```

```shell-session
# oc get pvc 
NAME                       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                     AGE 
ibm-spectrum-scale-pvc-1   Bound    pvc-56f96b0e-44cd-4adb-8ead-60aa9c03b504   1Gi        RWX            ibm-spectrum-scale-csi-fileset   11s 
```

STATUSがBoundに変われば正常に作成されています。

# まとめ

OpenShiftクラスタにCNSAをインストールして、IBM Storage Scaleのファイルシステムをリモートマウントすることにより、リモートのファイルシステムを永続ストレージとして使用できる環境が構築できました。
別の記事では、この環境を拡張して、OpenShift API for Data Protection (OADP) によるバックアップを行えるようにしたいと思います。

# 参考文献
- [IBM Storage Scale Documentation](https://www.ibm.com/docs/en/storage-scale/5.1.9)
- [IBM Storage Scale Container Native Documentation](https://www.ibm.com/docs/en/scalecontainernative/5.1.9?topic=overview)