IBM Cloud Private (無料のオンプレK8s SW製品) と GlusterFS + Heketi を繋いでみた



Kubernetesのオンプレ用ソフトウェア IBM Cloud Private Community Edition からコントロールできる永続ストレージが、別途構築が必要なので、Vagrantを利用してGlusterFSとの連携を検証してみました。

![スクリーンショット 2018-02-28 0.55.40.png](https://qiita-image-store.s3.amazonaws.com/0/42829/71c9fd44-5d08-90ab-81fb-845b6f553c36.png "スクリーンショット 2018-02-28 0.55.40.png")



## システム構成

k8sからGlusterFSをコントロールするために次の様な構成をとりました。 HeketiとGlusterFSの概要も以下にあります。

![スクリーンショット 2018-02-28 0.54.11.png](https://qiita-image-store.s3.amazonaws.com/0/42829/c58ad69c-16ca-84b2-c19c-be16b13d1154.png "スクリーンショット 2018-02-28 0.54.11.png")



## GlusterFSとは

> GlusterFSは、スケーラブルなストレージのための汎用分散ファイルシステムの1つ。InfiniBandのRDMAやTCP/IPインターコネクトなどの各種ストレージを集約し、大規模並列ネットワークファイルシステムを構築できる。GlusterFSはユーザー空間で構築されており、性能を低下させることがない。クラウドコンピューティング、生物医学、超大容量ストレージなど様々な応用がなされている。GlusterFSは、当初Gluster, Inc.によって開発された。2011年のレッドハットによるGluster買収の後はレッドハットにより開発されている。

出典 GlusterFS https://ja.wikipedia.org/wiki/GlusterFS


## Heketiとは

> Heketiは、GlusterFSボリュームのライフサイクルを管理するために使用できるRESTfulな管理インタフェースを提供します。Heketiを利用する事で、OpenStack Manila、Kubernetes、OpenShiftなどのクラウドサービスは、動的に堅牢さを保証するGlusterFSのボリュームをプロビジョンできます。Heketiは自動的にクラスタ全体でブロックを決定して、その複製を異なる障害ドメインに配置します。 Heketiはまた、任意の数のGlusterFSクラスタをサポートしているため、クラウドサービスは単一のGlusterFSクラスタに限定されずにネットワークファイルストレージを提供できます。

出典 Heketi ホーム https://github.com/heketi/heketi/wiki



## GlusterFSとHeketiのVagrantfile

GlusterFSを複数の物理サーバーにインストールして、テスト環境を構成すると大変なので、自分のMacやWindowsの仮想環境で、GlusterFSクラスタとHeketiを構成するためのVagrantfileを作成しました。　このVagrantfileを利用すると、次の図の右側の様に、３つのクラスタメンバーのGlusterFSクラスタと、一つのHeketiサーバーが起動します。 

![スクリーンショット 2018-02-27 23.57.53.png](https://qiita-image-store.s3.amazonaws.com/0/42829/ed770b14-fc03-b949-3468-0493c9951d69.png "スクリーンショット 2018-02-27 23.57.53.png")


### Vagrantfileの説明

次のリストが、vagrant でオートマチックに、GlusterFSのクラスタを構成して、起動するためのRubyで書かれたファイルです。 作業内容が判る様コメントを入れています。IPアドレスを必要に応じて自身の環境に合わせて変更して、ICP-CEと通信できる様にします。 このファイルを利用したクラスタの起動方法は、後述します。

~~~ruby
# coding: utf-8
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|

  # VirtualBoxで起動する仮想サーバーのOS
  config.vm.box = "ubuntu/xenial64"
  
  # GlusterFSのバージョン
  glusterfs_version = "3.12"


  # GlusterFSのサーバーの構成と起動
  # ホスト名 gluster-1〜gluster-3の３つのホストを起動するループを回します。
  # 192.168.1.91〜93のIPアドレスを付与、仮想サーバーのNICはブリッジモードで外部と通信できるモードにします。
  # この３つのホストには、それぞれ 20GiBのデータ保存用のディスクを付与します。
  # このデータ保存用の仮想ディスクは、
  # 仮想サーバーが起動したら、GlusferFSのリポジトリからインストールします。
  
  (1..3).each do |i|
    config.vm.define vm_name = "gluster-#{i}" do |config|
      config.cache.scope = :box
      config.vm.hostname = vm_name
      
      # IPアドレスは、ICP-CEに付与したIPアドレスからアクセスできる様に編集してください。
      ip = "192.168.1.#{i+90}"
      config.vm.network :public_network, ip: ip, bridge: "en0: Ethernet"
      
      # データ保存用ディスクの増設
      config.vm.provider :virtualbox do |p|
        vdisk = "vdisk/sdb-#{i}.vdi"
        if not File.exist?(vdisk) then
          p.customize [
            'createmedium', 'disk',
            '--filename', vdisk,
            '--format', 'VDI',
            '--size', 20 * 1024]
        end
        # Gluster device 1GiB
        p.customize [
          'storageattach', :id,
          '--storagectl', 'SCSI',
          '--port', 2,
          '--device', 0,
          '--type', 'hdd',
          '--medium', vdisk]
      end

      # 仮想サーバー起動後のGlusterFSのインストール
      config.vm.provision "shell", inline: <<-SHELL
         export DEBIAN_FRONTEND=noninteractive 
         apt-get update && apt-get install -yq python-software-properties
         add-apt-repository ppa:gluster/glusterfs-#{glusterfs_version}
         apt-get update && apt-get install -yq glusterfs-server thin-provisioning-tools
         cp /vagrant/ssh/id_rsa.pub /root/.ssh/authorized_keys
      SHELL
    end
  end


  # Heketiのインストールと GlusterFSのクラスタ設定
  # IPアドレス　192.168.1.90でブリッジモードで起動します。 必要に応じて変更してください。
  config.vm.define vm_name = "heketi" do |config|
    config.cache.scope = :box
    config.vm.hostname = vm_name
    ip = "192.168.1.90"
    config.vm.network :public_network, ip: ip, bridge: "en0: Ethernet"

    # 仮想サーバー起動後のインストールとクラスタの設定のシェルです。
    # こちらにもIPアドレスが入っているので、合わせて修正をお願いします。
    config.vm.provision "shell", inline: <<-SHELL
      export DEBIAN_FRONTEND=noninteractive  
      apt-get update && apt-get install -yq python-software-properties
      add-apt-repository ppa:gluster/glusterfs-#{glusterfs_version}
      apt-get update && apt-get install -yq glusterfs-client
      cp /vagrant/ssh/id_rsa /root/.ssh/id_rsa
      cp /vagrant/ssh/id_rsa /home/ubuntu/.ssh/id_rsa
      chown ubuntu:ubuntu /home/ubuntu/.ssh/id_rsa
      ssh -o 'StrictHostKeyChecking no' root@192.168.1.91 hostname
      ssh -o 'StrictHostKeyChecking no' root@192.168.1.92 hostname
      ssh -o 'StrictHostKeyChecking no' root@192.168.1.93 hostname
      wget https://github.com/heketi/heketi/releases/download/1.0.1/heketi-1.0.1.linux.amd64.tar.gz
      tar xzvf heketi-1.0.1.linux.amd64.tar.gz
      cp /vagrant/heketi/heketi.json /home/ubuntu/heketi/heketi.json
      # cd heketi
      # nohup ./heketi -config heketi.json &
      
    SHELL
  end
end
~~~


### 起動方法

上記のVagrantfile、必要なフォルダ、関連のファイルは、すべて GitHub の https://github.com/takara9/vagrant-glusterfs-heketi にありますので、IPアドレス以外に編集する箇所はありません。 ここから起動までのステップを記していきます。

次のコマンドで、必要なファイルをローカルに落として、作業をします。

~~~
git clone https://github.com/takara9/vagrant-glusterfs-heketi
~~~

クローンしたディレクトリに移動

~~~
cd vagrant-glusterfs-heketi
~~~


vagrantのプラグインをインストール

~~~
vagrant plugin install vagrant-cachier
~~~

ここで Vagrantfile の IPアドレスの編集をします。 
終わったら、いよいよ、仮想サーバー４台の起動です。

~~~
vagrant up
~~~

上記のコマンドで、自分のPC上に、GlusterFSのクラスタとHeketiサーバーが起動して、ICP-CEからアクセスできる様になります。


### Heketiのセットアップ

heketi-cliを使って、クラスタをセットアップするのですが、手順は、GitHub https://github.com/takara9/vagrant-glusterfs-heketi/blob/master/README.md にありますので、それに従って、セットアップを完了させます。


最後に、ICP-CEのサーバーにログインして、以下のcurlコマンドを実行してください。 以下の様に応答があれば完了です。

~~~
curl http://192.168.1.90:8080/hello
HelloWorld from GlusterFS Application
~~~



## ICP-CEのセットアップ

ICP-CEは、v2.1.0.1のインストールが完了して、稼動状態にあるものと仮定して、セットアップを進めて行きます。 設定の参考資料は、[Adding GlusterFS storage to your IBM® Cloud Private cluster](https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/manage_cluster/add_glusterfs.html)にあります。このマニュアルは、現在のk8sのバージョンに対して、少し古い部分がありますので、[Hello World application using GlusterFS Dynamic Provisioning](https://github.com/gluster/gluster-kubernetes/blob/master/docs/examples/hello_world/README.md)も合わせて参考にしながら、進めます。


### ICP-CEサーバーへの設定

ICP-CEのサーバーにログインして、sudo -s でrootで作業します。 dockerコマンドで実行するものは、Ansibleのplaybookを反映させるもので、ICP-CEが稼働するLinuxサーバーの設定を変更するものです。 

~~~
cd /opt/ibm-cloud-private-ce-2.1.0.1/cluster
sudo -s
docker run --net=host -it -e LICENSE=accept -v $(pwd):/installer/cluster ibmcom/icp-inception:2.1.0.1 bash
~~~

コンテナのシェルから、以下を実行します。

~~~
./installer.sh install --tags "Glusterfs,always" -vv | tee cluster/gluster_install.txt
~~~


### ストレージクラスの設定

次に、YAMLファイルを利用して、ストレージクラスの設定を行います。 heketiのIPアドレスは環境に合わせて修正をお願いします。 ユーザーとパスワードは、前述のVagrantfileから処理するheketi.jsonでユーザー認証を無効にしてあり、認証していないのですが、必要な行だけ入れておきます。

~~~heketi-glusterfs.yaml 
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: "gluster-heketi"
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://192.168.1.90:8080"
  restuser: "admin"
  restuserkey: "admin"
~~~

上記のYAMLを適用します。 以下を実行するには、`bx pr login` と `bx pr cluster-config mycluster`が実行されている事が必要です。

~~~
kubectl create -f heketi-glusterfs.yaml 
~~~

次の様に、Storage Classが作られて入れば、OKです。

~~~
$ kubectl get sc
NAME             PROVISIONER               AGE
gluster-heketi   kubernetes.io/glusterfs   5s
~~~


下記の様に、ICP-CE 2.1.0.1 の Kubernetes 1.8.3 では、前述のStorage Classを設定する事でGlusterFSのエンドポイントが、自動的に設定されます。

~~~
$ kubectl get ep
NAME                            ENDPOINTS                                      AGE
glusterfs-dynamic-gluster-vol   192.168.1.91:1,192.168.1.92:1,192.168.1.93:1   18m
~~~




### PVCの設定

アプリケーションを実行するポッドから永続ボリュームをマウントできる様に、PersistantVolumeClaimを定義する必要があります。
定義のYAMLファイルの例を以下にあげます。 以下は、前述で定義したストレージ・クラスを指定して10GiBのボリュームの確保を行ないます。

~~~heketi-pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: gluster-vol
 annotations:
   volume.beta.kubernetes.io/storage-class: gluster-heketi
spec:
 accessModes:
  - ReadWriteMany
 resources:
   requests:
     storage: 10Gi
~~~

上記のファイルを適用して、設定を反映します。

~~~
kubectl create -f heketi-pvc.yaml 
~~~

上記が適用されると、GlusterFSのボリュームに、ロジカルボリュームが定義され、以下のサイズの永続ボリュームが利用できる様になります。 

~~~
$ kubectl get pvc
NAME          STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS     AGE
gluster-vol   Bound     pvc-707745ee-1c20-11e8-979e-0022cfe54f6d   11Gi       RWX            gluster-heketi   18s
~~~

ここで、ストレージのサイズが小さいと実行に失敗します。 筆者の環境では、7GiB以上のサイズでしか作成に成功しませんでした。 


pvcを設定する事で、PersistentVolumeも自動的に設定されます。

~~~
$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                  
pvc-707745ee-1c20-11e8-979e-0022cfe54f6d   11Gi       RWX            Delete           Bound       default/gluster-vol     
~~~


### ICP-CEの管理画面の表示

kubectlコマンドから定義されたpvcは、管理コンソールでは次の様に表示されます。

![スクリーンショット 2018-02-28 10.39.53.png](https://qiita-image-store.s3.amazonaws.com/0/42829/1b8b3eab-fe42-dc53-2dac-b3cfdf664cf5.png "スクリーンショット 2018-02-28 10.39.53.png")




## ポッドからストレージの利用

永続ボリュームを利用するポッドとNodePortのセットを立ち上げて、前述の永続ボリュームをマウントしてみます。

~~~nginx_pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod1
  labels:
    app: nginx-pod1
spec:
  containers:
  - name: nginx-pod1
    image: gcr.io/google_containers/nginx-slim:0.8
    ports:
    - name: web
      containerPort: 80
    volumeMounts:
    - name: gluster-vol1
      mountPath: /usr/share/nginx/html
  volumes:
  - name: gluster-vol1
    persistentVolumeClaim:
      claimName: gluster-vol
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport-service
spec:
  type: NodePort
  selector:
    app: nginx-pod1
  ports:
  - protocol: TCP
    port: 80
    nodePort: 31590
~~~      

この状態だと、ボリュームの中身は空ですから、`curl http://192.168.1.100:31590` を実行しても、エラーメッセージが表示されるだけです、
そこで、このボッドにログインして、ファイルを作成します。

~~~
kubectl exec -ti nginx-pod1 /bin/sh
$ cd /usr/share/nginx/html
$ echo 'Hello World from GlusterFS!!!' > index.html
$ ls
index.html
$ exit
~~~

これで、GlusterFS上のデータが帰ってきました。

~~~
curl http://192.168.1.100:31590
Hello World from GlusterFS!!!
~~~

もう一つ名前とポート番号を変えて、ポッドを起動すると、今度は、共有するGlusterFSからindex.htmlで応答が帰ってきます。

~~~
imac:icp maho$ kubectl create -f nginx_pod2.yaml
pod "nginx-pod2" created
service "nginx-nodeport-service2" created
imac:icp maho$ kubectl get pods
NAME                           READY     STATUS              RESTARTS   AGE
bash-client-84bb76f87b-2l7ps   1/1       Running             4          7d
first-apl-b5d79797b-fjzkz      1/1       Running             2          7d
nginx-pod1                     1/1       Running             0          6m
nginx-pod2                     0/1       ContainerCreating   0          25s
imac:icp maho$ kubectl get pods
NAME                           READY     STATUS    RESTARTS   AGE
bash-client-84bb76f87b-2l7ps   1/1       Running   4          7d
first-apl-b5d79797b-fjzkz      1/1       Running   2          7d
nginx-pod1                     1/1       Running   0          9m
nginx-pod2                     1/1       Running   0          3m
imac:icp maho$ curl http://192.168.1.100:31592
Hello World from GlusterFS!!!
~~~


## まとめ

IBM Cloud Private Community Editon は、無料で利用できて、ターンキーインストールができる良いソフトなのですが、複数のノードの対応する、動的に永続ボリュームは、他のストレージ・システムと接続する必要があります。手軽に検証ができる様に、VagrantfileでGlusterFSとHeketiを組み合わせたストレージを構築して、ICP-CEの検証を実施しました。 ICP-CEの設定後は、特別な設定をする事なく、Kubernetesのチュートリアルのページに従って、利用できる様にする事ができました。


## 参考資料

### Glusterfs

1. GlusterFS Documentation http://docs.gluster.org/en/latest/
1. GlusterFS https://ja.wikipedia.org/wiki/GlusterFS
1. GLUSTER https://www.gluster.org/
1. Glusterfs / Storage Classes / Concept https://v1-8.docs.kubernetes.io/docs/concepts/storage/storage-classes/#glusterfs


### Heketi

1. Heketi GitHub https://github.com/heketi
2. Heketi Home https://github.com/heketi/heketi/wiki


### IBM Cloud Private

1. Adding GlusterFS storage to your IBM® Cloud Private cluster https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/manage_cluster/add_glusterfs.html
1. Adding GlusterFS storage https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/installing/storage_settings.html
1. Creating a storage class for GlusterFS https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/manage_cluster/create_sc_glusterfs.html
1. Creating a GlusterFS PersistentVolume https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/manage_cluster/create_glusterfs.html
1. Increasing the storage capacity of a GlusterFS cluster https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/manage_cluster/increase_gluster_storage.html


### Gluster-Kuberntes

1. Gluster-Kuberntes https://github.com/gluster/gluster-kubernetes
1. Hello World application using GlusterFS Dynamic Provisioning https://github.com/gluster/gluster-kubernetes/blob/master/docs/examples/hello_world/README.md


### YouTube
1. Provision Gluster Storage with REST API using Heketi
1. Dynamically Provision Gluster Volumes for Kubernetes Persistent Volume Claims