openshift で Container-Native Storage (glusterfs) を簡単デプロイ

[ドキュメント](https://access.redhat.com/documentation/en-us/red_hat_gluster_storage/3.3/html-single/container-native_storage_for_openshift_container_platform/)の情報が多すぎるので、glusterfs を OpenShift にデプロイするシンプルな方法を書いていこうと思います。この記事でデプロイされるGlusterFSは、いわゆる Container-Native Storage(CNS) と呼ばれ、以下でも「CNSをデプロイ」という表記で進めていきます。

バージョンは、以下を使っています。

- atomic-openshift-3.9.31
- openshift-ansible-3.9.30
- RHEL 7.5

### 構成

構成は、シンプルにmaster1台とnode3台です。各Nodeには、ディスク`/dev/vdb`を用意しておきます。(フォーマット等の必要はありません。)

~~~
+----------+
|  master  |
+----------+

+-----------+ +-----------+ +-----------+
|   node    | |   node    | |   node    |
|  /dev/vdb | |  /dev/vdb | |  /dev/vdb |
+-----------+ +-----------+ +-----------+
~~~

今回は、OpenShiftがインストール済みの構成でCNSをデプロイしていますが、OpenShiftと一緒にデプロイすることも可能です。

### 必要パッケージのインストール

masterのみに、heketi-client パッケージをインストールします。

~~~
# yum install heketi-client --enablerepo=rh-gluster-3-for-rhel-7-server-rpms
~~~

### ansible inventory ファイルの準備

絶対に必要なのは、以下の設定でだけです。ホスト名(`knakayam-ose39-c-nodeN.example.com`) とディスク名 `/dev/vdb` は環境に応じて変更してください。

~~~
[OSEv3:children]
# masters
# nodes
# etcd
# lb
glusterfs

[glusterfs]
knakayam-ose39-c-node1.example.com glusterfs_devices='[ "/dev/vdb" ]'
knakayam-ose39-c-node2.example.com glusterfs_devices='[ "/dev/vdb" ]'
knakayam-ose39-c-node3.example.com glusterfs_devices='[ "/dev/vdb" ]'
~~~

### ansible playbookの実行

以下のplaybookを実行するだけです。

~~~
  # ansible-playbook /usr/share/ansible/openshift-ansible/playbooks/openshift-glusterfs/config.yml
~~~

無事に完了すれば、以下のようになります。(okやchangedの数は環境によって異なるかもしれません。)

~~~
PLAY RECAP **********************************************************************************************
knakayam-ose39-c-node1.example.com : ok=24   changed=4    unreachable=0    failed=0
knakayam-ose39-c-node2.example.com : ok=24   changed=4    unreachable=0    failed=0
knakayam-ose39-c-node3.example.com : ok=24   changed=4    unreachable=0    failed=0
knakayam-ose39-c.example.com : ok=114  changed=37   unreachable=0    failed=0
localhost                  : ok=12   changed=0    unreachable=0    failed=0


INSTALLER STATUS ****************************************************************************************
Initialization             : Complete (0:03:19)
GlusterFS Install          : Complete (0:05:33)
~~~

### デプロイメントの確認

デプロイが完了したら、構成を覗いてみます。`glusterfs`というプロジェクトにログインして、`oc get all`とすると以下のようにデプロイされていることがわかります。pod が Running 状態になっていることを必ず確認してください。また、`storageclass`もすでにデプロイ済みなので、Dynamic Provisioningもすぐに利用可能です。あとで使ってみましょう。

~~~
# oc project glusterfs
Already on project "glusterfs" on server "https://knakayam-ose39-c.example.com:8443".

# oc get all
NAME                   DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
ds/glusterfs-storage   3         3         3         3            3           glusterfs=storage-host   1h

NAME                                                    REVISION   DESIRED   CURRENT   TRIGGERED BY
deploymentconfigs/glusterblock-storage-provisioner-dc   1          1         1         config
deploymentconfigs/heketi-storage                        1          1         1         config

NAME                    HOST/PORT                                     PATH      SERVICES         PORT      TERMINATION   WILDCARD
routes/heketi-storage   heketi-storage-glusterfs.10.64.222.1.xip.io             heketi-storage   <all>                   None

NAME                                             READY     STATUS    RESTARTS   AGE
po/glusterblock-storage-provisioner-dc-1-nntj9   1/1       Running   0          1h
po/glusterfs-storage-grnvc                       1/1       Running   0          1h
po/glusterfs-storage-nwgvc                       1/1       Running   0          1h
po/glusterfs-storage-vntqh                       1/1       Running   0          1h
po/heketi-storage-1-lhx8c                        1/1       Running   0          1h

NAME                                       DESIRED   CURRENT   READY     AGE
rc/glusterblock-storage-provisioner-dc-1   1         1         1         1h
rc/heketi-storage-1                        1         1         1         1h

NAME                              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
svc/heketi-db-storage-endpoints   ClusterIP   172.30.255.108   <none>        1/TCP      1h
svc/heketi-storage                ClusterIP   172.30.215.93    <none>        8080/TCP   1h

# oc get storageclass
NAME                PROVISIONER               AGE
glusterfs-storage   kubernetes.io/glusterfs   1h
~~~

### Dynamic Provisioning を利用する

それでは早速、Dynamic Provisioning を使ってみましょう。Dynamic Provisioning を簡単に言うと、PVCを作るだけで、先程デプロイしたCNSのストレージプールから、ストレージを切り出して使えるようにしてくれる仕組みです。


#### 1. まずは、PVC を作ります。

~~~
cat <<EOF > ./pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: gluster1
spec:
 accessModes:
  - ReadWriteMany
 resources:
   requests:
        storage: 10Gi
 storageClassName: glusterfs-storage
EOF
~~~

~~~
$ oc create -f pvc.yaml
~~~

Bound状態になったことを確認します。

~~~
$ oc get pvc
NAME       STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE
gluster1   Bound     pvc-1f691ad3-802b-11e8-a456-001a4a40dcb8   10Gi       RWX            glusterfs-storage   2h
~~~

#### 2. 続いて、podを作ります。

~~~
cat <<EOF > ./pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: gluster-pod1
spec:
  containers:
  - name: gluster-busybox
    image: busybox
    command: ["sleep", "60000"]
    volumeMounts:
    - name: gluster-vol1
      mountPath: /usr/share/busybox
      readOnly: false
  volumes:
  - name: gluster-vol1
    persistentVolumeClaim:
      claimName: gluster1
EOF
~~~

~~~
oc create -f pod.yaml
~~~

pod にボリュームがマウントできたことを確認します。

~~~
$ oc rsh gluster-pod1 mount |grep gluster
10.64.222.3:vol_8a4fecca141b626670e99f5de1fca8fc on /usr/share/busybox type fuse.glusterfs (rw,relatime,user_id=0,group_id=0,default_permissions,allow_other,max_read=131072)
~~~

### (おまけ) heketi-cli を使ってみる

まずは、環境変数の `HEKETI_CLI_SERVER` を設定します。

~~~
# export HEKETI_CLI_SERVER=http://`oc get route heketi-storage  --template={{.spec.host}}`
~~~

これだけでは、以下のようにユーザーが設定されていないと怒られてしまいます。

~~~
# heketi-cli topology info
Error: Unknown user
~~~

ユーザーとadmin keyを heketi-storage pod から抜き出して、設定します。

~~~
# oc get pod heketi-storage-1-lhx8c -o yaml |grep HEKETI_ADMIN_KEY -A1
    - name: HEKETI_ADMIN_KEY
      value: nwXRXDD0MiDCnvg6DYmdTtAqVLuawenPLZay1DSTOG0=

# export HEKETI_CLI_USER=admin
# export HEKETI_CLI_KEY=nwXRXDD0MiDCnvg6DYmdTtAqVLuawenPLZay1DSTOG0=
~~~

これで、`topology` コマンド等が叩けるようになります。

~~~
# heketi-cli topology info

Cluster Id: 889b88ba0942ad1b338dc97afd135b53

    File:  true
    Block: true

    Volumes:

	Name: heketidbstorage
	Size: 2
	Id: 7c9574a3c1a6f6f70a55435962cae64d
	Cluster Id: 889b88ba0942ad1b338dc97afd135b53
	Mount: 10.64.222.4:heketidbstorage
	Mount Options: backup-volfile-servers=10.64.222.5,10.64.222.3
	Durability Type: replicate
	Replica: 3
	Snapshot: Disabled

		Bricks:
			Id: 052069adbf9894cfbd046a9008ea4aec
			Path: /var/lib/heketi/mounts/vg_0ca6422f04c1e75001e189ba2e9f68e3/brick_052069adbf9894cfbd046a9008ea4aec/brick
			Size (GiB): 2
			Node: 33e8015235af3fb2dfd0ea86b8149cb2
			Device: 0ca6422f04c1e75001e189ba2e9f68e3

			Id: 56218e5956d3b1ef1a8342f9e26ffc4d
			Path: /var/lib/heketi/mounts/vg_08160d8b5000d74d421637f3b675e12b/brick_56218e5956d3b1ef1a8342f9e26ffc4d/brick
			Size (GiB): 2
			Node: d5b6f4ac87e00656808d445b0afb6cc5
			Device: 08160d8b5000d74d421637f3b675e12b

			Id: 9303a3943585c8745a64dd2ae44beb61
			Path: /var/lib/heketi/mounts/vg_94d95f59fa5613b473cfde03133d2321/brick_9303a3943585c8745a64dd2ae44beb61/brick
			Size (GiB): 2
			Node: 194fb7f91ff2a049bc27b2ebb7416003
			Device: 94d95f59fa5613b473cfde03133d2321


	Name: vol_8a4fecca141b626670e99f5de1fca8fc
	Size: 10
	Id: 8a4fecca141b626670e99f5de1fca8fc
	Cluster Id: 889b88ba0942ad1b338dc97afd135b53
	Mount: 10.64.222.4:vol_8a4fecca141b626670e99f5de1fca8fc
	Mount Options: backup-volfile-servers=10.64.222.5,10.64.222.3
	Durability Type: replicate
	Replica: 3
	Snapshot: Disabled

		Bricks:
			Id: 0353101752644ddbb8512314061fdaaf
			Path: /var/lib/heketi/mounts/vg_0ca6422f04c1e75001e189ba2e9f68e3/brick_0353101752644ddbb8512314061fdaaf/brick
			Size (GiB): 10
			Node: 33e8015235af3fb2dfd0ea86b8149cb2
			Device: 0ca6422f04c1e75001e189ba2e9f68e3

			Id: 9f120fa36ed4aab668459ce1bb7cd8cb
			Path: /var/lib/heketi/mounts/vg_08160d8b5000d74d421637f3b675e12b/brick_9f120fa36ed4aab668459ce1bb7cd8cb/brick
			Size (GiB): 10
			Node: d5b6f4ac87e00656808d445b0afb6cc5
			Device: 08160d8b5000d74d421637f3b675e12b

			Id: e4f7fb10888f6d58d81c3cb29c531f65
			Path: /var/lib/heketi/mounts/vg_94d95f59fa5613b473cfde03133d2321/brick_e4f7fb10888f6d58d81c3cb29c531f65/brick
			Size (GiB): 10
			Node: 194fb7f91ff2a049bc27b2ebb7416003
			Device: 94d95f59fa5613b473cfde03133d2321


    Nodes:

	Node Id: 194fb7f91ff2a049bc27b2ebb7416003
	State: online
	Cluster Id: 889b88ba0942ad1b338dc97afd135b53
	Zone: 1
	Management Hostnames: knakayam-ose39-c-node2.example.com
	Storage Hostnames: 10.64.222.4
	Devices:
		Id:94d95f59fa5613b473cfde03133d2321   Name:/dev/vdb            State:online    Size (GiB):49      Used (GiB):12      Free (GiB):37      
			Bricks:
				Id:9303a3943585c8745a64dd2ae44beb61   Size (GiB):2       Path: /var/lib/heketi/mounts/vg_94d95f59fa5613b473cfde03133d2321/brick_9303a3943585c8745a64dd2ae44beb61/brick
				Id:e4f7fb10888f6d58d81c3cb29c531f65   Size (GiB):10      Path: /var/lib/heketi/mounts/vg_94d95f59fa5613b473cfde03133d2321/brick_e4f7fb10888f6d58d81c3cb29c531f65/brick

	Node Id: 33e8015235af3fb2dfd0ea86b8149cb2
	State: online
	Cluster Id: 889b88ba0942ad1b338dc97afd135b53
	Zone: 1
	Management Hostnames: knakayam-ose39-c-node3.example.com
	Storage Hostnames: 10.64.222.5
	Devices:
		Id:0ca6422f04c1e75001e189ba2e9f68e3   Name:/dev/vdb            State:online    Size (GiB):49      Used (GiB):12      Free (GiB):37      
			Bricks:
				Id:0353101752644ddbb8512314061fdaaf   Size (GiB):10      Path: /var/lib/heketi/mounts/vg_0ca6422f04c1e75001e189ba2e9f68e3/brick_0353101752644ddbb8512314061fdaaf/brick
				Id:052069adbf9894cfbd046a9008ea4aec   Size (GiB):2       Path: /var/lib/heketi/mounts/vg_0ca6422f04c1e75001e189ba2e9f68e3/brick_052069adbf9894cfbd046a9008ea4aec/brick

	Node Id: d5b6f4ac87e00656808d445b0afb6cc5
	State: online
	Cluster Id: 889b88ba0942ad1b338dc97afd135b53
	Zone: 1
	Management Hostnames: knakayam-ose39-c-node1.example.com
	Storage Hostnames: 10.64.222.3
	Devices:
		Id:08160d8b5000d74d421637f3b675e12b   Name:/dev/vdb            State:online    Size (GiB):49      Used (GiB):12      Free (GiB):37      
			Bricks:
				Id:56218e5956d3b1ef1a8342f9e26ffc4d   Size (GiB):2       Path: /var/lib/heketi/mounts/vg_08160d8b5000d74d421637f3b675e12b/brick_56218e5956d3b1ef1a8342f9e26ffc4d/brick
				Id:9f120fa36ed4aab668459ce1bb7cd8cb   Size (GiB):10      Path: /var/lib/heketi/mounts/vg_08160d8b5000d74d421637f3b675e12b/brick_9f120fa36ed4aab668459ce1bb7cd8cb/brick
~~~

CNSを簡単にデプロイして、使ってみる手順を書いてみました。ドキュメントが複雑なので、簡単な手順で初めてみました。