GlusterFS と OpenShift

# GlusterFS とは？

一言でいうと汎用分散ファイルシステムのことです。
細かいことは公式とか wiki とか見てください。

## GlusterFS図解

使うときは図１のようなイメージになります。
各インスタンス（VM-1等）の中にGlusterFSをインストールし、それぞれが node として機能します。
可用性を確保したい場合は各VMをAWS であれば別のAZに、Azureであればペアリージョンに配置すればよいでしょう。
図には入れてませんがNodeを設定するときに「ZONE」という変数があるのでこいつで分散配置をコントロールできる感じですかね。
※zone の効果に関しては検証したことないので想像です。
nodeの中にはdeviceを設定します。
追加でディスクを追加して使います。
fdisk でパーティション作って使えば拡張しやすいかな、と思います。
各デバイスの中にボリュームが追加されていきます。
そして図にはありませんがVolumeの中に「Brick」ができます。
Volumeはファイルシステムのストライピングやレプリケート等の機能を抽象化してVMやインスタンスを跨いだ仮想的なRAIDを実現しています。
Brickはストライピングやレプリケート実現のための実態ファイル、といったところでしょうか。
言い方が難しいのであんまり上手く言えてる感じないです。
詳しくは[公式ドキュメントのArchitecture](https://docs.gluster.org/en/latest/Quick-Start-Guide/Architecture/)を見てください。

![GlusterFS.png](https://qiita-image-store.s3.amazonaws.com/0/105030/a2c816f8-6d26-ac71-96e6-118d0f1c400a.png)
図１. GlusterFS 構成イメージ

## GlusterFSのインストール

[参考サイト](https://www.server-world.info/query?os=CentOS_7&p=glusterfs)が一番分かりやすかったです。
バージョン毎にインストール方法のページが分かれてますが、`yum list available | grep gluster` コマンドでインストール可能バージョンが一覧ででます。

```bash
[root@teswt yum.repos.d]# arch
x86_64
[root@teswt yum.repos.d]# cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)
[root@teswt yum.repos.d]# yum list available | grep gluster
～
centos-release-gluster38.noarch           1.0-1.el7.centos               extras
centos-release-gluster39.noarch           1.0-1.el7.centos               extras
centos-release-gluster40.x86_64           1.0-2.el7.centos               extras
～
[root@teswt yum.repos.d]yum install centos-release-gluster40.x86_64
～
Complete!
[root@teswt yum.repos.d]# yum list available | grep gluster
～
glusterfs-server.x86_64                   4.0.2-1.el7                    centos-gluster40
heketi.x86_64                             6.0.0-1.el7                    centos-gluster40
heketi-client.x86_64                      6.0.0-1.el7                    centos-gluster40
～
[root@teswt yum.repos.d]# yum install glusterfs-server.x86_64 heketi.x86_64 heketi-client.x86_64
～
Complete!
[root@teswt yum.repos.d]# systemctl start glusterd
[root@teswt yum.repos.d]# systemctl enable glusterd
```

## heketi

先ほどgluster-serverをインストールするときにしれっと「heketi」というツールを合わせてインストールしました。
このツールは glusterfs を Web-API でコントロールできるツールです。
heketi-cli は動作中の heketi に対して リクエストを投げ、コマンドラインから簡単にGlusterFSをコントロールするツールです。

openshift で GlusterFS を使用する場合は heketi が必須となります。
これは OpenShift のオブジェクトとして StorageClass（以後SCとする）を作成し、SC の provisioner として heketi を使用する仕組みになっているためです。
つまりもう少し正確に言うと、全てマニュアル管理にして StorageClass は使用せずに PersistentVolume のみでやっていく場合は heketi 不要ということです。

ただし、heketi は現時点では GlusterFS のストライピングボリューム方式に対応していないようです。
[公式GitHubのドキュメント](https://github.com/heketi/heketi/blob/v6.0.0/docs/api/api.md#create-a-volume)
※「Create a Volume」の「durability」の項目参照。none / replicate / disperse の３種しかない。ソースの該当箇所は[この辺り](https://github.com/heketi/heketi/blob/v6.0.0/executors/cmdexec/volume.go)かな？

なので OpenShift・kubernetes で GlusterFS を使用する場合はストライピングは使用できなさそう。なのでペタバイト級のストレージも期待しないほうが良いのかな、という印象です。StorageClass使わないでNFSとしてマニュアル管理で使用するならいけるでしょうけど。

## heketi セットアップ

デフォルトでは 8080 ポートで LISTEN されてます。
インストール後は `/etc/heketi/heketi.json` に設定がありますので空気を読んで修正しましょう。

設定例

```
[root@teswt heketi]# cat heketi.json
{
  "_port_comment": "Heketi Server Port Number",
  "port": "8080",

  "_use_auth": "Enable JWT authorization. Please enable for deployment",
  "use_auth": false,

  "_jwt": "Private keys for access",
  "jwt": {
    "_admin": "Admin has access to all APIs",
    "admin": {
      "key": "My Secret"
    },
    "_user": "User only has access to /volumes endpoint",
    "user": {
      "key": "My Secret"
    }
  },

  "_glusterfs_comment": "GlusterFS Configuration",
  "glusterfs": {
    "_executor_comment": [
      "Execute plugin. Possible choices: mock, ssh",
      "mock: This setting is used for testing and development.",
      "      It will not send commands to any node.",
      "ssh:  This setting will notify Heketi to ssh to the nodes.",
      "      It will need the values in sshexec to be configured.",
      "kubernetes: Communicate with GlusterFS containers over",
      "            Kubernetes exec api."
    ],
    "executor": "ssh",

    "_sshexec_comment": "SSH username and private key file information",
    "sshexec": {
      "keyfile": "/home/azureuser/.ssh/id_rsa",
      "user": "azureuser",
      "port": "22",
      "fstab": "/etc/fstab",
      "sudo": true
    },

    "_kubeexec_comment": "Kubernetes configuration",
    "kubeexec": {
      "host" :"https://kubernetes.host:8443",
      "cert" : "/path/to/crt.file",
      "insecure": false,
      "user": "kubernetes username",
      "password": "password for kubernetes user",
      "namespace": "OpenShift project or Kubernetes namespace",
      "fstab": "Optional: Specify fstab file on node.  Default is /etc/fstab"
    },

    "_db_comment": "Database file name",
    "db": "/var/lib/heketi/heketi.db",

    "_loglevel_comment": [
      "Set log level. Choices are:",
      "  none, critical, error, warning, info, debug",
      "Default is warning"
    ],
    "loglevel" : "debug"
  }
}
```

heketi は executer という仕組みでGlusterFSをコントロールします。デフォルトではモックになっていて動きませんのでそれっぽく設定しましょう。
このページでやっているようにマニュアルインストールする場合は ssh になるでしょう。
これはクラスタ作り直したりするときによく忘れます。。。openshift-ansible が上手く動く人はそれで良いでしょう。

### バグ

yum でインストールしたら `systemctl start heketi` しても起動しない問題が発生。
サービスファイルがバグってたので修正してから start します。

```
[root@teswt heketi]# yum list installed | grep heketi
heketi.x86_64                      6.0.0-1.el7                 @centos-gluster40
heketi-client.x86_64               6.0.0-1.el7                 @centos-gluster40
[root@teswt heketi]# cp /usr/lib/systemd/system/heketi.service /usr/lib/systemd/system/heketi.service.org
[root@teswt heketi]# vi /usr/lib/systemd/system/heketi.service
[root@teswt heketi]# diff -y /usr/lib/systemd/system/heketi.service /usr/lib/systemd/system/heketi.service.org
～
ExecStart=/usr/bin/heketi --config=/etc/heketi/heketi.json    | ExecStart=/usr/bin/heketi -config=/etc/heketi/heketi.json
～
[root@teswt heketi]# systemctl daemon-reload
[root@teswt heketi]# systemctl start heketi
[root@teswt heketi]# systemctl enable heketi
[root@teswt heketi]# systemctl status heketi
● heketi.service - Heketi Server
   Loaded: loaded (/usr/lib/systemd/system/heketi.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2018-05-01 12:20:13 UTC; 38s ago
 Main PID: 8972 (heketi)
   CGroup: /system.slice/heketi.service
           mq8972 /usr/bin/heketi --config=/etc/heketi/heketi.json

May 01 12:20:13 teswt systemd[1]: Started Heketi Server.
May 01 12:20:13 teswt systemd[1]: Starting Heketi Server...
May 01 12:20:13 teswt heketi[8972]: Heketi 6.0.0
May 01 12:20:13 teswt heketi[8972]: [heketi] INFO 2018/05/01 12:20:13 Loaded mock executor
May 01 12:20:13 teswt heketi[8972]: [heketi] INFO 2018/05/01 12:20:13 GlusterFS Application Loaded
May 01 12:20:13 teswt heketi[8972]: Listening on port 8080
```

### topology

GlusterFS のすべての Node のインストールが完了したら topology.json を作成し、heketi-cli からロードしたらクラスタセットアップ完了です。

```
[root@teswt heketi]#cat topology.json
{
    "clusters": [
        {
            "nodes": [
                {
                    "node": {
                        "hostnames": {
                            "manage": [
                                "10.0.0.4"
                            ],
                            "storage": [
                                "10.0.0.4"
                            ]
                        },
                        "zone": 1
                    },
                    "devices": [
                        "/dev/sdc"
                    ]
                }
            ]
        }
    ]
}
[root@teswt heketi]#heketi-cli topology load --json topology.json
[root@teswt heketi]# heketi-cli topology info

Cluster Id: 04f8148c8314e1ec18403a3772dd028e

    File:  true
    Block: true

    Volumes:

    Nodes:

        Node Id: ff02c98cba70151bfa85dfc2d86b8c7c
        State: online
        Cluster Id: 04f8148c8314e1ec18403a3772dd028e
        Zone: 1
        Management Hostnames: 10.0.0.4
        Storage Hostnames: 10.0.0.4
        Devices:
                Id:66254ceb8fdf77a175c2cd592c49501d   Name:/dev/sdc            State:online    Size (GiB):500     Used (GiB):0       Free (GiB):500
                        Bricks:
```

## heketi 使用時の注意点

ファイルシステムとかボリュームグループとかも自動で作成してくれるのでパーティション切る以上のことはしないようにしましょう。

## StorageClass の設定

OpenShift で GlusterFS を使用する場合、PersistentVolume を予め作成しておくか、StorageClass を作成しておいて都度都度作成するかどちらかになります。PV作成しておくの面倒なのでStorageClassを使用する方式を推奨します。

StorageClass のプロビジョナーとして色々設定できるようです。Gluster使わなくてもそっちでいいかも。

GlusterFS を使用する場合の StorageClass は以下のように記載します。

```
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: glusterfs
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://10.42.0.0:8080" 
  restauthenabled: "false"
  volumetype: "replicate:3"
```

認証有にする場合はパラメータを追加します。
認証のキーは`/etc/heketi/heketi.json`のJWTの項目に設定したキーを指定します。

```yaml

apiVersion: v1
kind: Secret
metadata:
  name: heketi-secret
  namespace: openshift
data:
  # echo -n "mypassword" | base64
  key: bXlwYXNzd29yZA== 
type: kubernetes.io/glusterfs
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow
provisioner: kubernetes.io/glusterfs
parameters:
  # heketi のURL
  resturl: "http://127.0.0.1:8081"
  # heketi-cli cluster list で確認可能。
  clusterid: "630372ccdc720a92c681fb928f27b53f"
  restauthenabled: "true"
  restuser: "admin"
  secretNamespace: "openshift"
  secretName: "heketi-secret"
  volumetype: "replicate:2"
```

これを`oc create -f storage-class.yaml` コマンドで取り込めば PersistentVolumeClaim を作成するたびに自動でストレージが作成されるようになります。

[refs：https://kubernetes.io/docs/concepts/storage/storage-classes/](https://kubernetes.io/docs/concepts/storage/storage-classes/)

# まとめ

非常に良い感じに OpenShift / kubernetes の Storage 管理を抽象化できたように思います。
Developper は PVC 作るだけなのに裏側では自動的にストレージがレプリケーションされています。
インフラレイヤーとアプリレイヤーがきれいに分割されているにも関わらずアプリレイヤーから手間をかけずにできることが非常に多くなっている感じがしてよさげですね。

プロビジョナーはたくさんありますが、クラウドサービスのプロビジョナーを使用する際は扱う際の制限が何かしらかかることが多いです。そういった意味では汎用的なストレージエンジンとして非常に使えるかもしれません。