OpenShift Container Platform on IBM Cloud VPC上でNFSをPVとしたマルチインスタンスQMGRを構成する

# 概要

IBM Cloudで構成できるOpenShift Container Platform(以下､OpenShift)は現在(2021-09-14)､`Classic Infrastructure`と`VPC`のいずれかで構成できる｡(その他`Satellite`もあるがここでは割愛)
VPCで構成すると､pre-definedのStorageClassで利用できるPersistentVolume(PV)はBlockStorageに限定され､FileStorageは使用できない｡つまり､RWOのストレージしか使用できない｡

一方で､IBM MQの高可用性構成の1つであるマルチインスタンスキューマネージャー(MIQM)は､そのプライマリーインスタンスの決定方法の制約上､RWXのPVが必要となる｡
RWXのPVの調達方法としては､[OpenShift Data Foundation](https://cloud.redhat.com/products/container-storage/)を利用してPVを用意することも可能だが､どうしても[必要なCPU/RAMが膨大](https://cloud.ibm.com/docs/openshift?topic=openshift-deploy-odf-vpc#ocs-storage-vpc)となる｡
今回は､テスト目的でサクッとRWXのPVを用意するため､VPC上の仮想サーバーにNFSサーバーを構築してマウントする構成を整えたので備忘として残す｡

## 環境

全て同一VPC､Zone内で構成する

- OpenShift
    - OpenShift Container Platform 4.7.23
    - worker
        - 4Core, 16GB RAM x 4Node
- 仮想サーバー
    - RHEL 8.3
    - 2Core, 8GB RAM

## NFSサーバー

導入手順は省略

### 構成

```bash
$ mkdir /nfs/isemqgvpc-ocp
$ vim /etc/exports
# /etc/exportsに以下を追加(IPはOpenShiftのWorker NodeのIP)
/nfs/isemqgvpc-ocp 10.244.128.xx(rw,no_root_squash)
/nfs/isemqgvpc-ocp 10.244.128.yy(rw,no_root_squash)
/nfs/isemqgvpc-ocp 10.244.128.zz(rw,no_root_squash)
/nfs/isemqgvpc-ocp 10.244.128.ww(rw,no_root_squash)
```

exports -vで適切にexportできているか確認

```bash
$ exportfs -v
/nfs/isemqgvpc-ocp
                10.244.128.xx(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/nfs/isemqgvpc-ocp
                10.244.128.yy(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/nfs/isemqgvpc-ocp
                10.244.128.zz(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/nfs/isemqgvpc-ocp
                10.244.128.ww(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
```

## nfs-subdir-external-provisioner

構成したNFSサーバーに対して､PVC経由でPVを動的にプロビジョンするためのプロビジョナーを構成する｡

[nfs-subdir-external-provisioner](https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner)

### プロジェクト

`oc new-project nfs`でプロジェクトを作成､ここにプロビジョナーをデプロイする｡

### helm Chartの用意

このプロビジョナーはhelmで導入する｡

```bash
% helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
"nfs-subdir-external-provisioner" has been added to your repositories

% helm repo list

NAME                            URL                                                               
nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
```

### デプロイ

`--set`オプションはそれぞれNFSサーバーのIP,exportしたディレクトリ､このプロビジョナーで利用するStorageClassの名前を指定する｡

```bash
% helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
    --set nfs.server=10.244.128.x \
    --set nfs.path=/nfs/isemqgvpc-ocp/ \
    --set storageClass.name=nfs

I0914 13:31:38.513140   19546 request.go:668] Waited for 1.00504873s due to client-side throttling, not priority and fairness, request: GET:https://c100-e.jp-tok.containers.cloud.ibm.com:31330/apis/oidc.security.ibm.com/v1?timeout=32s
NAME: nfs-subdir-external-provisioner
LAST DEPLOYED: Tue Sep 14 13:31:41 2021
NAMESPACE: nfs
STATUS: deployed
REVISION: 1
TEST SUITE: None
```

正常であればPodが作成されるが､ReplicaSetでエラーが発生していた｡

```bash
        pods "nfs-subdir-external-provisioner-7df556686c-" is forbidden: unable
        to validate against any security context constraint: [spec.volumes[0]:
        Invalid value: "nfs": nfs volumes are not allowed to be used]
```
権限が足りないので､SCC: `houstmount-anyuid`を付与する｡

この設定については[Without Helm](https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner#without-helm)のStep 3: Setup authorizationにも記載がある｡

```bash
% oc adm policy add-scc-to-user hostmount-anyuid system:serviceaccount:nfs:nfs-subdir-external-provisioner
clusterrole.rbac.authorization.k8s.io/system:openshift:scc:hostmount-anyuid added: "nfs-subdir-external-provisioner"
```

podの起動とStorageClass `nfs`が作成されていることを確認する｡

```bash
% oc get pods

NAME                                               READY   STATUS    RESTARTS   AGE
nfs-subdir-external-provisioner-7df556686c-xvwcd   1/1     Running   0          60s
% oc get sc
 
NAME                                          PROVISIONER                                     RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
ibmc-block-bronze                             vpc.block.csi.ibm.io                            Delete          Immediate              false                  20d
ibmc-vpc-block-10iops-tier (default)          vpc.block.csi.ibm.io                            Delete          Immediate              false                  83d
ibmc-vpc-block-5iops-tier                     vpc.block.csi.ibm.io                            Delete          Immediate              false                  83d
ibmc-vpc-block-custom                         vpc.block.csi.ibm.io                            Delete          Immediate              false                  83d
ibmc-vpc-block-general-purpose                vpc.block.csi.ibm.io                            Delete          Immediate              false                  83d
ibmc-vpc-block-metro-10iops-tier              vpc.block.csi.ibm.io                            Delete          WaitForFirstConsumer   false                  83d
ibmc-vpc-block-metro-5iops-tier               vpc.block.csi.ibm.io                            Delete          WaitForFirstConsumer   false                  83d
ibmc-vpc-block-metro-custom                   vpc.block.csi.ibm.io                            Delete          WaitForFirstConsumer   false                  83d
ibmc-vpc-block-metro-general-purpose          vpc.block.csi.ibm.io                            Delete          WaitForFirstConsumer   false                  83d
ibmc-vpc-block-metro-retain-10iops-tier       vpc.block.csi.ibm.io                            Retain          WaitForFirstConsumer   false                  83d
ibmc-vpc-block-metro-retain-5iops-tier        vpc.block.csi.ibm.io                            Retain          WaitForFirstConsumer   false                  83d
ibmc-vpc-block-metro-retain-custom            vpc.block.csi.ibm.io                            Retain          WaitForFirstConsumer   false                  83d
ibmc-vpc-block-metro-retain-general-purpose   vpc.block.csi.ibm.io                            Retain          WaitForFirstConsumer   false                  83d
ibmc-vpc-block-retain-10iops-tier             vpc.block.csi.ibm.io                            Retain          Immediate              false                  83d
ibmc-vpc-block-retain-5iops-tier              vpc.block.csi.ibm.io                            Retain          Immediate              false                  83d
ibmc-vpc-block-retain-custom                  vpc.block.csi.ibm.io                            Retain          Immediate              false                  83d
ibmc-vpc-block-retain-general-purpose         vpc.block.csi.ibm.io                            Retain          Immediate              false                  83d
nfs                                           cluster.local/nfs-subdir-external-provisioner   Delete          Immediate              true                   15m
```

## MIQMのデプロイ

Cloud Pak for Integration(CP4I)で提供されるMQ Operatorを使用してデプロイする

```yaml
apiVersion: mq.ibm.com/v1beta1
kind: QueueManager
metadata:
  namespace: takzo
  name: nfs-sample
spec:
  license:
    accept: true
    license: L-RJON-BZFQU2
    use: NonProduction
  web:
    enabled: false
  version: 9.2.3.0-r1
  template:
    pod:
      containers:
        - env:
            - name: MQSNOAUT
              value: 'yes'
          name: qmgr
  queueManager:
    resources:
      limits:
        cpu: 500m
      requests:
        cpu: 250m
    name: QM02
    availability:
      type: MultiInstance      # マルチインスタンスQMGRを構成
      updateStrategy: RollingUpdate
    storage:
      defaultClass: nfs
      defaultDeleteClaim: true
      persistedData:
        class: nfs             # 作成したStorgeClassを利用
        deleteClaim: true
        enabled: true
        type: persistent-claim
      queueManager:
        class: nfs             # 作成したStorgeClassを利用
        deleteClaim: true
        type: persistent-claim
      recoveryLogs:
        class: nfs             # 作成したStorgeClassを利用
        deleteClaim: true
        enabled: true
        type: persistent-claim
```

StatefulSetでPodが2つ構成される(一方(この場合`nfs-sample-ibm-mq-1`がスタンバイノードのため､READYは`0`のまま)｡

```bash
% oc get pod -w

NAME                  READY   STATUS              RESTARTS   AGE
nfs-sample-ibm-mq-0   1/1     Running             0          91s
nfs-sample-ibm-mq-1   0/1     ContainerCreating   0          12s
nfs-sample-ibm-mq-1   0/1     Running             0          64s
nfs-sample-ibm-mq-1   0/1     Running             0          68s
```

また､PVCは各インスタンスで利用する`/var/mqm`相当のディレクトリと､インスタンス間で共有する`/var/mqm/qmgrs/<qmgr_name>`､`/var/mqm/log/<qmgr_name>`の系4つのPVで構成される｡

```bash
takzo% oc get pvc

NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
data-nfs-sample-ibm-mq-0           Bound    pvc-7697cb9e-8568-451b-826f-3575c8d7482c   2Gi        RWO            nfs            19h
data-nfs-sample-ibm-mq-1           Bound    pvc-2b3119b2-39a1-495b-91c2-eb019556571f   2Gi        RWO            nfs            19h
nfs-sample-ibm-mq-persisted-data   Bound    pvc-a71e9953-23e0-4b82-a9e9-70084a95c19b   2Gi        RWX            nfs            19h
nfs-sample-ibm-mq-recovery-logs    Bound    pvc-ead2c923-a8b4-475c-a3db-2a078ffbaa8b   2Gi        RWX            nfs            19h
```