IBM Cloud Virtual Private CloudにUPIインストールしたOpenShiftへのPortworx導入

# はじめに
OpenShiftのworkerノードを複数ゾーンに配置するとき、ステートフルなPodについては、どのゾーンにスケジュールされても同じ永続ボリュームにアクセスできる必要があります。IBM Cloudのマニュアルには、Block StorageとFile Storageは単一ゾーン用であり、複数ゾーンに対応する方法として以下が記載されています。

1. IBM Cloud Object Storage
2. ソフトウェア定義のストレージ(Portworx)
3. Cloudデータベース・サービス

https://cloud.ibm.com/docs/containers?topic=containers-storage_planning#persistent_storage_overview

ソフトウェア定義のストレージとしては、CNCFのGraduatedプロジェクトRookが有名ですが、ここでは無償利用可能なPortworx Essentialsをこちらの[記事](https://qiita.com/y-akio/items/ad0093daa504be746573)でUPIインストールしたOpenShift 4.8にデプロイし、GitBucketの永続ボリュームとして利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413476/0bc11825-f4f1-6096-55fc-915812ec4676.png)

■ Portworx稼働要件

https://docs.portworx.com/portworx-install-with-kubernetes/

■ GitBucket

https://github.com/gitbucket/gitbucket

#1. Portworx Essentialsの導入
##1.1. Block Storage for VPCの割り当て
各workerノードにPortworxの内部KVDB用のボリューム80GBと、データ用のボリューム120GBを作成し割り当てます。workerノードはRHCOSですが、特別な設定をすることなく割り当てることができました。

```bash:classicノード
# ボリューム作成
volume-create.sh

# ボリューム割り当て
instance-volume-attachment-add.sh
```

```bash:volume-create.sh
ibmcloud is volume-create worker-00 general-purpose jp-osa-1 --capacity 120
ibmcloud is volume-create worker-01 general-purpose jp-osa-1 --capacity 80
ibmcloud is volume-create worker-10 general-purpose jp-osa-2 --capacity 120
ibmcloud is volume-create worker-11 general-purpose jp-osa-2 --capacity 80
ibmcloud is volume-create worker-20 general-purpose jp-osa-3 --capacity 120
ibmcloud is volume-create worker-21 general-purpose jp-osa-3 --capacity 80
```

```bash:instance-volume-attachment-add.sh
function instance_id {
  instance_id=`ibmcloud is ins | grep ${1} | awk '{print $1}'` > /dev/null
  echo ${instance_id}
}

function volume_id {
  volume_id=`ibmcloud is volumes | grep ${1} | awk '{print $1}'` > /dev/null
  echo ${volume_id}
}

ibmcloud is instance-volume-attachment-add worker-00 `instance_id worker-0` `volume_id worker-00` --auto-delete true
ibmcloud is instance-volume-attachment-add worker-01 `instance_id worker-0` `volume_id worker-01` --auto-delete true
ibmcloud is instance-volume-attachment-add worker-10 `instance_id worker-1` `volume_id worker-10` --auto-delete true
ibmcloud is instance-volume-attachment-add worker-11 `instance_id worker-1` `volume_id worker-11` --auto-delete true
ibmcloud is instance-volume-attachment-add worker-20 `instance_id worker-2` `volume_id worker-20` --auto-delete true
ibmcloud is instance-volume-attachment-add worker-21 `instance_id worker-2` `volume_id worker-21` --auto-delete true
```

各workerノードにvddとvdeが追加されていることを確認できます。

```bash:classicノード
ssh core@worker-0 lsblk | egrep "120G|80G"
### 標準出力↓
vdd    252:48   0  120G  0 disk
vde    252:64   0   80G  0 disk

ssh core@worker-1 lsblk | egrep "120G|80G"
### 標準出力↓
vdd    252:48   0  120G  0 disk
vde    252:64   0   80G  0 disk

ssh core@worker-2 lsblk | egrep "120G|80G"
### 標準出力↓
vdd    252:48   0  120G  0 disk
vde    252:64   0   80G  0 disk
```

##1.2. Portworxのアカウント作成
Portworxのアカウントを作成して「Essential Entitlement ID」を入手します。
同IDはログイン後、プロファイル画面で確認することができます。

https://ask.portworx.com/get-started/


##1.3. Portworx Essentialsオペレーター導入
Portworx Essentialsオペレーターをネームスペース「kube-system」に導入します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413476/927fc5a2-5f4b-3b89-f4b0-3ec0e215e4a5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413476/986085bc-f065-d962-788b-2396ec871c60.png)

次にカスタムリソースStorage Clusterを作成します。Essentials版では内部KVDBが、Enterprise版では外部etcdが必要とのことです。内部KVDBは個別のボリュームとすることが望ましいため「/dev/vde」を割り当てています。「/dev/vdd」がデータ領域になります。定期的なライセンス更新が必要なため、事前にシークレットを作成し、Storage Clusterマニフェストでプロキシサーバーを設定しています。

```bash:classicノード
oc -n kube-system create secret generic px-essential \
  --from-literal=<Essential Entitlement ID> \
  --from-literal=px-osb-endpoint='https://pxessentials.portworx.com/osb/billing/v1/register'

oc apply -f storage-cluster.yaml
oc get pod
### 標準出力↓
NAME                                READY   STATUS    RESTARTS   AGE
autopilot-7bc65cd88-dq2jd           1/1     Running   0          10m
portworx-api-ckn7l                  1/1     Running   0          10m
portworx-api-dtb4m                  1/1     Running   0          10m
portworx-api-g4x2b                  1/1     Running   0          10m
portworx-kvdb-ddv9v                 1/1     Running   0          4m37s
portworx-kvdb-n4s4m                 1/1     Running   0          4m42s
portworx-kvdb-qj57g                 1/1     Running   0          6m2s
portworx-operator-cd6b4d4c9-br9ql   1/1     Running   0          14m
px-cluster-4nfd4                    2/2     Running   0          10m
px-cluster-fkmxb                    2/2     Running   0          10m
px-cluster-vb27l                    2/2     Running   0          10m
px-csi-ext-86975b9df6-9z2fk         3/3     Running   0          10m
px-csi-ext-86975b9df6-pbkhw         3/3     Running   0          10m
px-csi-ext-86975b9df6-zwlr6         3/3     Running   0          10m
px-lighthouse-d89df5f96-q8rxz       3/3     Running   0          10m
stork-7d6678446c-l5644              1/1     Running   0          10m
stork-7d6678446c-n6hsd              1/1     Running   0          10m
stork-7d6678446c-pd6jd              1/1     Running   0          10m
stork-scheduler-d855699cd-wgmq4     1/1     Running   0          10m
stork-scheduler-d855699cd-x45r9     1/1     Running   0          10m
stork-scheduler-d855699cd-xfwdc     1/1     Running   0          10m

oc apply -f portworx-sc.yaml
oc get sc
### 標準出力↓
NAME                             PROVISIONER                     RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
portworx-sc                      kubernetes.io/portworx-volume   Delete          Immediate           false                  42h
px-db                            kubernetes.io/portworx-volume   Delete          Immediate           true                   13m
px-db-cloud-snapshot             kubernetes.io/portworx-volume   Delete          Immediate           true                   13m
･･･
```

```yaml:storage-cluster.yaml
kind: StorageCluster
apiVersion: core.libopenstorage.org/v1
metadata:
  name: px-cluster
  namespace: kube-system
  annotations:
    portworx.io/is-openshift: "true"
    portworx.io/misc-args: "--oem esse"
spec:
  image: portworx/oci-monitor:2.7.2.1
  imagePullPolicy: Always
  deleteStrategy:
    type: UninstallAndWipe
  kvdb:
    internal: true
  storage:
    devices:
      - /dev/vdd
    journalDevice: auto
    kvdbDevice: /dev/vde
  secretsProvider: k8s
  stork:
    enabled: true
    args:
      webhook-controller: "false"
  userInterface:
    enabled: true
  autopilot:
    enabled: true
  featureGates:
    CSI: "true"
  env:
  - name: "PX_HTTP_PROXY"
    value: "http://10.192.36.132:3128"
  - name: "PX_HTTPS_PROXY"
    value: "http://10.192.36.132:3128"
```

```yaml:portworx-sc.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: portworx-sc
provisioner: kubernetes.io/portworx-volume
parameters:
  repl: "1"
```

以下はカスタムリソースStorage Clusterに関するマニュアルです。

https://docs.portworx.com/reference/crd/storage-cluster/

#2. GitBucket導入
GitBucketはGitHub風のUIを持つGitリポジトリです。機能が絞られているためか、GitLabと比較してリソース使用量が非常に少なく、家庭用NASのDockerでも動作します。

https://github.com/gitbucket/gitbucket

https://docs.gitlab.com/charts/installation/

##2.1. GitBucketデプロイ
GitBucketをステートフルセットとしてデプロイします。永続ボリューム(PV)は、ストレージクラス「portworx-sc」から動的にプロビジョニングされます。

```bash:classicノード
wget https://github.com/gitbucket/gitbucket/releases/download/4.35.3/gitbucket.war
oc new-project gitbucket
oc new-build --name=gitbucket --strategy=docker --binary
oc start-build gitbucket --from-dir=. --follow
oc get is
### 標準出力↓
NAME        IMAGE REPOSITORY                                                       TAGS     UPDATED
gitbucket   image-registry.openshift-image-registry.svc:5000/gitbucket/gitbucket   latest   40 seconds ago

oc apply -f gitbucket.yaml
oc get pod -o wide
### 標準出力↓
NAME                READY   STATUS      RESTARTS   AGE     IP            NODE       NOMINATED NODE   READINESS GATES
gitbucket-0         1/1     Running     0          4m30s   10.129.2.25   worker-0   <none>           <none>
gitbucket-1-build   0/1     Completed   0          7m38s   10.129.2.23   worker-0   <none>           <none>

oc get pvc,pv
### 標準出力↓
NAME                                          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/gitbucket-gitbucket-0   Bound    pvc-a5b047f1-eab0-447e-b1ec-b41a00373adb   10Gi       RWO            portworx-sc    5m15s

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                             STORAGECLASS   REASON   AGE
persistentvolume/pvc-a5b047f1-eab0-447e-b1ec-b41a00373adb   10Gi       RWO            Delete           Bound    gitbucket/gitbucket-gitbucket-0   portworx-sc             5m14s
```

```Dockerfile:Dockerfile
FROM registry.access.redhat.com/ubi8/ubi:latest

RUN yum --disableplugin=subscription-manager -y install java-1.8.0-openjdk \
 && yum --disableplugin=subscription-manager clean all

COPY gitbucket.war /opt/
RUN mkdir /gitbucket \
    && chmod 777 /opt \
    && chmod 777 /opt/gitbucket.war \
    && chmod 777 /gitbucket

EXPOSE 8080

CMD ["sh", "-c", "java -jar /opt/gitbucket.war --port=8080 --gitbucket.home=/gitbucket"]
```

```yaml:gitbucket.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: gitbucket
spec:
  updateStrategy:
    type: RollingUpdate
  serviceName: gitbucket
  replicas: 1
  selector:
    matchLabels:
      app: gitbucket
  template:
    metadata:
      labels:
        app: gitbucket
    spec:
      terminationGracePeriodSeconds: 10
      containers:
        - name: gitbucket
          image: image-registry.openshift-image-registry.svc:5000/gitbucket/gitbucket
          ports:
            - containerPort: 8080
          volumeMounts:
            - name: gitbucket
              mountPath: /gitbucket
  volumeClaimTemplates:
    - metadata:
        name: gitbucket
      spec:
        accessModes:
          - ReadWriteOnce
        storageClassName: portworx-sc
        resources:
          requests:
            storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
  name: gitbucket
spec:
  selector:
    app: gitbucket
  type: ClusterIP
  ports:
   - protocol: TCP
     port: 80
     targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: gitbucket
spec:
  rules:
    - host: gitbucket.apps.ocp.cloud.vpc
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: gitbucket
                port:
                  number: 80
```

GitBucketにログインし、リポジトリを作成してソースコード等をプッシュすることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413476/5045dfa5-04be-524f-11ac-09b2fd13f64e.png)


##2.2. 異なるゾーンからの永続ボリュームへのアクセス
現在、ステートフルセット「gitbucket-0」は、subnet1のworker-0で動作しています。worker-0へスケジュールしないよう設定した後にステートフルセットを削除すると、他のノードに自動起動されます。

```bash:classicノード
oc get pod -o wide
### 標準出力↓
NAME                READY   STATUS      RESTARTS   AGE     IP            NODE       NOMINATED NODE   READINESS GATES
gitbucket-0         1/1     Running     0          9m29s   10.129.2.35   worker-0   <none>           <none>

oc adm cordon worker-0
oc get nodes
### 標準出力↓
master-0   Ready                       master   16h   v1.21.1+f36aa36
master-1   Ready                       master   16h   v1.21.1+f36aa36
master-2   Ready                       master   16h   v1.21.1+f36aa36
worker-0   Ready,SchedulingDisabled    worker   15h   v1.21.1+f36aa36
worker-1   Ready                       worker   15h   v1.21.1+f36aa36
worker-2   Ready                       worker   15h   v1.21.1+f36aa36

oc delete pod gitbucket-0
oc get pod -o wide
### 標準出力↓
NAME                READY   STATUS      RESTARTS   AGE   IP            NODE       NOMINATED NODE   READINESS GATES
gitbucket-0         1/1     Running     0          25s   10.128.2.15   worker-2   <none>           <none>
```

subnet2のworker-2でステートフルセット「gitbucket-0」が動作する状況で、先程、作成したリポジトリを確認することができました。異なるゾーンからのアクセスも問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1413476/c9ce5d5c-a70e-4ae8-dda2-e6989f1257e2.png)

##2.3. Portworxの状態確認

worker-0、worker-1、worker-2で構成されるクラスター「px-cluster」を確認できます。

```bash:classicノード
oc exec px-cluster-4nfd4 -n kube-system -- /opt/pwx/bin/pxctl status
# 標準出力
Defaulting container name to portworx.
Use 'oc describe pod/px-cluster-4nfd4 -n kube-system' to see all of the containers in this pod.
Status: PX is operational
License: PX-Essential (lease renewal in 23h, 53m)
Node ID: abcfd8d8-8a8b-4ef2-9599-f39b9bd0909a
        IP: 10.244.64.111
        Local Storage Pool: 1 pool
        POOL    IO_PRIORITY     RAID_LEVEL      USABLE  USED    STATUS  ZONE    REGION
        0       LOW             raid0           117 GiB 7.9 GiB Online  default default
        Local Storage Devices: 1 device
        Device  Path            Media Type              Size            Last-Scan
        0:1     /dev/vdd2       STORAGE_MEDIUM_MAGNETIC 117 GiB         08 Jul 21 05:29 UTC
        total                   -                       117 GiB
        Cache Devices:
         * No cache devices
        Kvdb Device:
        Device Path     Size
        /dev/vde        80 GiB
         * Internal kvdb on this node is using this dedicated kvdb device to store its data.
        Journal Device:
        1       /dev/vdd1       STORAGE_MEDIUM_MAGNETIC
Cluster Summary
        Cluster ID: px-cluster
        Cluster UUID: af58a904-1a00-4df1-b019-0d4590197e16
        Scheduler: kubernetes
        Nodes: 3 node(s) with storage (3 online)
        IP              ID                                      SchedulerNodeName       Auth            StorageNode     Used    Capacity        Status  StorageStatus   Version         Kernel                          OS
        10.244.0.111    eedcb736-68a4-46f9-8dad-6803b88ed5d6    worker-0                Disabled        Yes             8.0 GiB 117 GiB         Online  Up              2.7.2.1-20328f1 4.18.0-240.22.1.el8_3.x86_64    Red Hat Enterprise Linux CoreOS 47.83.202105220305-0 (Ootpa)
        10.244.128.111  aee2172f-25c3-4e17-abc2-77d437d5b786    worker-2                Disabled        Yes             7.9 GiB 117 GiB         Online  Up              2.7.2.1-20328f1 4.18.0-240.22.1.el8_3.x86_64    Red Hat Enterprise Linux CoreOS 47.83.202105220305-0 (Ootpa)
        10.244.64.111   abcfd8d8-8a8b-4ef2-9599-f39b9bd0909a    worker-1                Disabled        Yes             7.9 GiB 117 GiB         Online  Up (This node)  2.7.2.1-20328f1 4.18.0-240.22.1.el8_3.x86_64    Red Hat Enterprise Linux CoreOS 47.83.202105220305-0 (Ootpa)
Global Storage Pool
        Total Used      :  24 GiB
        Total Capacity  :  351 GiB
```

essentials版では5ノードまでとされています。3ノード追加したところ、5番目のノードまで認識されました。6番目のノードworker-5のPod はReady状態になっていません。アラートログにも下記のログが出力されています。

>Unable to add a NEW node as cluster is operating at maximum capacity (5 nodes)

```bash:classicノード
oc get pod -o wide | grep "worker-5"
# 標準出力↓
portworx-api-wsmf5                  0/1     Running   0          14m   10.244.128.112   worker-5   <none>           <none>
px-cluster-2gsx9                    1/2     Running   0          13m   10.244.128.112   worker-5   <none>           <none>

oc exec px-cluster-4nfd4 -n kube-system -- /opt/pwx/bin/pxctl status
# 標準出力↓
･･･
Cluster Summary
        Cluster ID: px-cluster
        Cluster UUID: af58a904-1a00-4df1-b019-0d4590197e16
        Scheduler: kubernetes
        Nodes: 3 node(s) with storage (3 online), 2 node(s) without storage (2 online)
        IP              ID                                      SchedulerNodeName       Auth            StorageNode     Used    Capacity        Status  StorageStatus   Version         Kernel                          OS
        10.244.0.111    eedcb736-68a4-46f9-8dad-6803b88ed5d6    worker-0                Disabled        Yes             8.0 GiB 117 GiB         Online  Up              2.7.2.1-20328f1 4.18.0-240.22.1.el8_3.x86_64    Red Hat Enterprise Linux CoreOS 47.83.202105220305-0 (Ootpa)
        10.244.128.111  aee2172f-25c3-4e17-abc2-77d437d5b786    worker-2                Disabled        Yes             7.9 GiB 117 GiB         Online  Up              2.7.2.1-20328f1 4.18.0-240.22.1.el8_3.x86_64    Red Hat Enterprise Linux CoreOS 47.83.202105220305-0 (Ootpa)
        10.244.64.111   abcfd8d8-8a8b-4ef2-9599-f39b9bd0909a    worker-1                Disabled        Yes             7.9 GiB 117 GiB         Online  Up (This node)  2.7.2.1-20328f1 4.18.0-240.22.1.el8_3.x86_64    Red Hat Enterprise Linux CoreOS 47.83.202105220305-0 (Ootpa)
        10.244.64.112   8110a996-9f8a-42e5-ae1b-684446d673be    worker-4                Disabled        No              0 B     0 B             Online  No Storage      2.7.2.1-20328f1 4.18.0-240.22.1.el8_3.x86_64    Red Hat Enterprise Linux CoreOS 47.83.202105220305-0 (Ootpa)
        10.244.0.112    00228b69-9518-4f57-ab3e-27afa2fa3906    worker-3                Disabled        No              0 B     0 B             Online  No Storage      2.7.2.1-20328f1 4.18.0-240.22.1.el8_3.x86_64    Red Hat Enterprise Linux CoreOS 47.83.202105220305-0 (Ootpa)

oc exec px-cluster-4nfd4 -n kube-system -- /opt/pwx/bin/pxctl alerts show
# 標準出力↓
NODE    ClusterManagerFailure   10.244.128.112                          ALARM           1       Jul 8 13:33:15 UTC 2021 Jul 8 13:33:15 UTC 2021 Failed to start cluster manager on node [10.244.128.112]: Unable to add a NEW node as cluster is operating at maximum capacity (5 nodes). Please remove a no
de before attempting to add a new node.
```

ボリュームの状態を確認します。

```bash:classicノード
oc exec px-cluster-4nfd4 -n kube-system -- /opt/pwx/bin/pxctl volume list
Defaulting container name to portworx.
Use 'oc describe pod/px-cluster-4nfd4 -n kube-system' to see all of the containers in this pod.
ID                      NAME                                            SIZE    HA      SHARED  ENCRYPTED       PROXY-VOLUME    IO_PRIORITY     STATUS                          SNAP-ENABLED
505245055575650061      pvc-a5b047f1-eab0-447e-b1ec-b41a00373adb        10 GiB  1       no      no              no              LOW             up - attached on 10.244.0.111   no
```

ステートフルセット「gitbucket-0」の使用する永続ボリュームの実体はworker-0(10.244.0.111)に作成されています。コピーはされていません。ストレージクラス「portworx-sc」作成時にレプリカ数を1としたためです。

```bash:classicノード
oc exec px-cluster-4nfd4 -n kube-system -- /opt/pwx/bin/pxctl volume inspect 505245055575650061
Defaulting container name to portworx.
Use 'oc describe pod/px-cluster-4nfd4 -n kube-system' to see all of the containers in this pod.
        Volume                   :  505245055575650061
        Name                     :  pvc-a5b047f1-eab0-447e-b1ec-b41a00373adb
        Size                     :  10 GiB
        Format                   :  ext4
        HA                       :  1
        IO Priority              :  LOW
        Creation time            :  Jul 8 06:17:18 UTC 2021
        Shared                   :  no
        Status                   :  up
        State                    :  Attached: eedcb736-68a4-46f9-8dad-6803b88ed5d6 (10.244.0.111)
        Last Attached            :  Jul 8 07:28:19 UTC 2021
        Device Path              :  /dev/pxd/pxd505245055575650061
        Labels                   :  namespace=gitbucket,pvc=gitbucket-gitbucket-0,repl=1,app=gitbucket
        Mount Options            :  discard
        Reads                    :  68
        Reads MS                 :  9
        Bytes Read               :  360448
        Writes                   :  32316
        Writes MS                :  2241
        Bytes Written            :  220160000
        IOs in progress          :  0
        Bytes used               :  90 MiB
        Replica sets on nodes:
                Set 0
                  Node           : 10.244.0.111 (Pool e0b4d621-7f96-40ca-90eb-ffebd3bec40b )
        Replication Status       :  Up
        Volume consumers         :
                - Name           : gitbucket-0 (a2f60911-cf26-4c44-b6c3-951fafaf53eb) (Pod)
                  Namespace      : gitbucket
                  Running on     : worker-0
                  Controlled by  : gitbucket (StatefulSet)