Helm 3.0 のお試しレポート

Helm バージョン2と比較すると、Helm バージョン3 は、拍子抜けするほど簡単に利用できる。Helm v3がGAとなっているので、動作を確認してみた。

動作を確認した環境は、[15Stepで習得 Dockerから入るKubernetes コンテナ開発からK8s本番運用まで (StepUp!選書)](https://www.amazon.co.jp/dp/4865941614)のために作成した パソコンの仮想環境でK8sクラスタやSDSを利用するための、アップストリームの K8sの学習環境である。GitHubにコードを公開しているので、 本を買わなくても、この記事の読者はこの方法をトレースすることができる。（でも本を買って欲しいです(汗)...)
![K8s-Book.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/53062a40-a77f-86be-25a5-e37b8566b22f.png)

## 学習環境のセットアップ

Helmチャートで提供されるアプリケーションは、永続ストレージを用いるものが多い。そこで、同書籍に挙げた Glusterファイルシステム(以下 GFSとする)を先に起動しておき、そのあと K8sクラスタを起動する。そして、GFSと連携するため、ストレージクラスをインストールして、両者の連携を確立する。
そして、Helmチャートを適用した際に、設定変更なしで動作するように、GFSをデフォルトストレージに設定する。

GFSは、ソフトウェア定義のストレージシステム (Software Defined Storage 以下 SDSとする) であり、Heketiを利用して K8sのストレージクラスのプロビジョナーと連携する。これによって、K8sの YAMLの永続ボリュームの定義に従って、仮想ストレージ上に永続ボリュームが構築される。

GFSを開発したのは、Gluster社であり、その後、Red Hat社がGluster社を買収している。GFSは、大規模で高速なストレージを構築できることから、科学計算や医療などでビックデータ活用が必要な分野にも利用されている。

インストールの詳細の説明は、それぞれ、GitHubのREADMEに書いたので、そちらを参照していただきたい。

* GlusterFs https://github.com/takara9/vagrant-glusterfs
* Kubernetes 3ノードクラスタ https://github.com/takara9/vagrant-kubernetes

上記、二つのGitHubのコードから構築されるシステム構成は、以下のようになる。 MacやWindows10では、8GB〜16GBのメモリが必要となる。

![Sysconfig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/ff6c762c-7ff0-e3cf-ddca-877dec8dc306.png)

自分のパソコンのハードウェアの上で、K8sクラスタとソフトウェア定義ストレージが、動作するというのは、素晴らしいことである。これはハードウェア性能の向上とソフトウェアスタックの開発の成果であり、クラウドコンピューティング推進の基礎技術にもなっている。

## 手順1 GFSの起動

VirtualBoxとVagrantをセットアップしたパソコンで、以下の操作を実施することで、前述の図のGlusterクラスタの部分が、自動構築される。

~~~
$ git clone https://github.com/takara9/vagrant-glusterfs gluster
$ cd gluster
$ vagrant up
~~~

## 手順2 K8sクラスタの起動

同様に、ハイパーバイザーとフロントエンドがセットアップされたパソコンで、次のコマンドを実行することで、K8sクラスタが自動構築できる。

~~~
$ git clone https://github.com/takara9/vagrant-kubernetes k8s
$ cd k8s
$ vagrant up
~~~

## 手順3 K8sとGFSの連携

前述で立ち上げたK8sクラスタのマスターノードにログインして、ストレージクラスとPVCを作成するサンプルコードを取得する。

~~~
$ cd k8s
$ vagrant ssh master
$ git clone https://github.com/takara9/vagrant-glusterfs gluster
$ cd gluster/k8s-yaml
$ ls
gfs-client.yml  gfs-pvc-1.yml  gfs-pvc-2.yml  storageclass.yml
~~~

GFSを動的にプロビジョニングできるように、ストレージクラスを作成する。

~~~
vagrant@master:~/gluster/k8s-yaml$ kubectl apply -f storageclass.yml
storageclass.storage.k8s.io/gluster-heketi created
~~~

ストレージクラスが出来たことを確認する。

~~~
vagrant@master:~/gluster/k8s-yaml$ kubectl get storageclass
NAME             PROVISIONER               AGE
gluster-heketi   kubernetes.io/glusterfs   34m
~~~

デフォルトストレージクラスに設定するために、パッチを当てる。これ以外に、エディットで変更してもよい。

~~~
vagrant@master:~/gluster/k8s-yaml$ kubectl patch storageclass gluster-heketi -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
storageclass.storage.k8s.io/gluster-heketi patched
~~~

次のコマンドで、デフォルトになったことを確認する。

~~~
vagrant@master:~/gluster/k8s-yaml$ kubectl get storageclass
NAME                       PROVISIONER               AGE
gluster-heketi (default)   kubernetes.io/glusterfs   35m
~~~

次のサンプルYAMLを使って、永続ボリューム要求(Persistent Volume Claim)を実行して、作成されたPVCをマウントするポッドを起動することができる。このあとの動作確認などは、[15Stepで習得 Dockerから入るKubernetes コンテナ開発からK8s本番運用まで (StepUp!選書)](https://www.amazon.co.jp/dp/4865941614) p298でも解説しているので、興味に応じて参照して欲しい。これを実行しないと先に進めない訳ではないから、次に進んでも良い。

~~~
vagrant@master:~/gluster/k8s-yaml$ kubectl apply -f gfs-pvc-1.yml
persistentvolumeclaim/gvol-1 created
vagrant@master:~/gluster/k8s-yaml$ kubectl apply -f gfs-client.yml
deployment.extensions/gfs-client created
~~~


## Helm バージョン3 の使用

Helm バージョン2と比較すると、Helm バージョン3 は、拍子抜けするほど、簡単に利用できるので、ユーザーにとって、とても喜ばしいバージョンアップである。

簡単に説明すると、Helm v3のクライアントを、kubectlを利用する環境にインストールして、リポジトリを追加すれば、それで、利用可能となる。 helm init も tiller のインストールも必要がない。

注意点としては、当たり前であるが、必ず Helm v3 のクライアントを使用する必要がある。
macOSやWindows用のHelm v3 クライアントのバイナリは、https://github.com/helm/helm/releases に、リンクがあるので、ダウンロードして、/usr/local/binなどに移動すれば良い。

今回は、パソコン側のOSにインストールせず、マスターノードに Helmクライアントをインストールして試してみることにする。 マスターノードは、Vagrant で起動した仮想サーバーなので、パソコンの環境に影響を与えない。これは筆者にとっては有難い。何故ならば、業務でHelm v2 を利用するため、Helm v3 をパソコンにインストールしたくないからである。


## Helm v3 クライアントのインストール

`vagrant ssh master`でマスターノードにログインして、コマンドのダウンロードを実行する。

~~~
vagrant@master:~$ curl -O https://get.helm.sh/helm-v3.0.0-linux-amd64.tar.gz
~~~

tarファイルを展開して、helmコマンドを取り出せるようにする。

~~~
vagrant@master:~$ tar xzvf helm-v3.0.0-linux-amd64.tar.gz 
linux-amd64/
linux-amd64/helm
linux-amd64/README.md
linux-amd64/LICENSE
~~~

helmコマンドを `/usr/local/bin` に移動する。

~~~
vagrant@master:~$ sudo mv linux-amd64/helm /usr/local/bin
~~~

helmコマンドの動作を確認する。

~~~
vagrant@master:~$ helm version
version.BuildInfo{Version:"v3.0.0", GitCommit:"e29ce2a54e96cd02ccfce88bee4f58bb6e2a28b6", GitTreeState:"clean", GoVersion:"go1.13.4"}
~~~

## Helm リポジトリの追加

リポジトリを追加することで、Helmのセットアップが完了する。

~~~
vagrant@master:~$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
"stable" has been added to your repositories
~~~

'stable'に分類されるリポジトリのリスト

~~~
vagrant@master:~$ helm search repo stable
NAME                          HART VERSION	APP VERSION  DESCRIPTION                                       
stable/acs-engine-autoscaler  2.2.2        	2.1.1        DEPRECATED Scales worker nodes within agent pools 
stable/aerospike              0.3.0        	v4.5.0.5     A Helm chart for Aerospike in Kubernetes          
stable/airflow                4.4.0        	1.10.4       Airflow is a platform to programmatically autho...
~~~


## RocketChatのインストール

[RocketChat](https://rocket.chat/)は、Slackの様なユーザーインターフェースをもつチームで共同作業するための便利なツールである。このアプリケーションをHelmからインストールしてみたい。

まず、インストール時に設定するべき、HELMチャートの設定事項を取り出す。そして、修正箇所は以下のdiffの結果を参考にして、config.ymlを修正する。なお、変更後の値は `<` で始まる行である。

~~~
vagrant@master:~$ helm inspect values stable/rocketchat > config.yml
vagrant@master:~$ cp config.yml config-org.yml 
vagrant@master:~$ vi config.yml 
vagrant@master:~$ diff config.yml config-org.yml 
68c68
<   mongodbRootPassword: rocket1234!
---
>   # mongodbRootPassword:
71c71
<   mongodbPassword: rocker1234!
---
>   # mongodbPassword:
158c158
<   type: NodePort
---
>   type: ClusterIP
161c161
<   nodePort: 30000
---
>   # nodePort: 30000
~~~

上記、修正箇所のポイントとしては、パスワードの設定とNodePortの設定である。このK8sクラスタには、Ingressコントローラーなどの設定が無いので、NodePortを設定して、ワーカーノード、マスターノードのポートからアクセスできる様にする。


次に、設定ファイルを指定して、Helmで、RoeketChatをインストールする。

~~~
vagrant@master:~$ helm install -f config.yml chat stable/rocketchat
NAME: chat
LAST DEPLOYED: Sat Nov 16 23:47:06 2019
NAMESPACE: default
STATUS: deployed
REVISION: 1
<以下省略>
~~~

## RocketChatの起動と問題対応

`helm ls` で確認すると、起動していることが解りますが、Podを確認すると、クラッシュしているので、問題を探っていく。

~~~
vagrant@master:~$ kubectl get po
NAME                               READY   STATUS             RESTARTS   AGE
chat-mongodb-primary-0             0/1     CrashLoopBackOff   3          2m22s
chat-rocketchat-85c95b9777-cplrx   0/1     CrashLoopBackOff   1          2m22s
~~~

Podのログを確認すると、書き込み権限が無いことが解った。

~~~
vagrant@master:~$ kubectl logs chat-mongodb-primary-0 

Welcome to the Bitnami mongodb container
Subscribe to project updates by watching https://github.com/bitnami/bitnami-docker-mongodb
Submit issues and feature requests at https://github.com/bitnami/bitnami-docker-mongodb/issues
Send us your feedback at containers@bitnami.com

INFO  ==> ** Starting MongoDB setup **
INFO  ==> Validating settings in MONGODB_* env vars...
INFO  ==> Initializing MongoDB...
INFO  ==> Deploying MongoDB from scratch...
mkdir: cannot create directory '/bitnami/mongodb/data': Permission denied
~~~

Helmから作られたPVCを確認する。

~~~
vagrant@master:~$ kubectl get pvc
NAME                             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS     AGE
datadir-chat-mongodb-primary-0   Bound    pvc-66182513-08cb-11ea-9121-02b444486472   8Gi        RWO            gluster-heketi   3m25s
~~~

このPVCをマウントして、パーミッションを変更できる Podを起動する YAML を作成する。

~~~
vagrant@master:~$ cat gfs-wa.yml
apiVersion: v1
kind: Pod
metadata:
  name: gfs-client
spec:
  containers:
  - name: ubuntu
    image: ubuntu:16.04	
    volumeMounts:
    - name: gfs
      mountPath: /mnt
    command: ["tail", "-f", "/dev/null"]
  volumes:
  - name: gfs
    persistentVolumeClaim:
      claimName: datadir-chat-mongodb-primary-0
~~~

Helmのインスタンスを一旦削除して、PVCで作られた永続ボリュームのモードを変更する。

~~~
vagrant@master:~$ helm uninstall chat
release "chat" uninstalled
~~~

作成したYAMLを使ってポッドを起動して、PVCをマウントして、モードを変更する。

~~~
vagrant@master:~$ kubectl apply -f gfs-wa.yml
pod/gfs-client created
vagrant@master:~/gluster/k8s-yaml$ kubectl exec -it gfs-client -- bash
groups: cannot find name for group ID 2001
root@gfs-client:/#
root@gfs-client:/# df
Filesystem                                       1K-blocks    Used Available Use% Mounted on
overlay                                           10098468 2442884   7639200  25% /
tmpfs                                                65536       0     65536   0% /dev
tmpfs                                               507944       0    507944   0% /sys/fs/cgroup
172.20.1.21:vol_523c8bf30576dd5095c7d13fb5cb7f07   8364032   66816   8297216   1% /mnt
/dev/sda1                                         10098468 2442884   7639200  25% /etc/hosts
shm                                                  65536       0     65536   0% /dev/shm
tmpfs                                               507944      12    507932   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                                               507944       0    507944   0% /proc/acpi
tmpfs                                               507944       0    507944   0% /proc/scsi
tmpfs                                               507944       0    507944   0% /sys/firmware
root@gfs-client:/# cd /mnt
root@gfs-client:/mnt# chmod a+w .
root@gfs-client:/# exit
~~~

もう一度、Helm で RocketChat をインストールする。

~~~
vagrant@master:~$ helm install -f config.yml chat stable/rocketchat
~~~

再度、ポッドの状態を確認する。

~~~
vagrant@master:~$ kubectl get po
NAME                               READY   STATUS             RESTARTS   AGE
chat-mongodb-primary-0             1/1     Running            0          23s
chat-rocketchat-85c95b9777-8lrj5   0/1     CrashLoopBackOff   1          23s

約 30秒経過ほど経過すると、正常に稼働

vagrant@master:~$ kubectl get po
NAME                               READY   STATUS    RESTARTS   AGE
chat-mongodb-primary-0             1/1     Running   0          66s
chat-rocketchat-85c95b9777-8lrj5   0/1     Running   3          66s
~~~

RocketChatのコンテナをルート以外のユーザーで起動するのであれば、初期化コンテナを設定して、モードを変更するのが良いと思うが、そのようなRocketChatのチャートには設定が無いので、手作業で修正した。

## RocketChatの管理用ページにアクセスする

RocketChatのWebページにアクセスするために、マスターノードのアドレスを確認する。これは、もちろん、ワーカーノードでも良い。

~~~
vagrant@master:~$ ifconfig enp0s8
enp0s8    Link encap:Ethernet  HWaddr 08:00:27:35:50:41  
          inet addr:172.16.20.11  Bcast:172.16.20.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe35:5041/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:161847 errors:0 dropped:0 overruns:0 frame:0
          TX packets:178670 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:18273038 (18.2 MB)  TX bytes:108994581 (108.9 MB)
~~~

このアドレスに対して、すなわち、マスターノードに、http://172.16.20.11:30000/ でアクセスすると RocketChatの管理画面が表示される。本来ならば、ワーカーノードにアクセスするべきない。これは簡単に結果を得るために利用した方法である。

<img width="400" alt="RocketSetup.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/b5bbea2a-c364-ede3-7874-837df2b12fa3.png">

## まとめ

Helm v3 は、とても簡単に利用を開始できて、既存のチャートも利用できることが、確認できた。今後、OpenShift や IBM Cloud にも導入されることを期待したい。

注意点として、Helm を使う前に、K8sやYAMLの設定を良く理解していないと、問題判別などで困ることもあるので、Helmがあるから、K8sのAPIやYAMLの書き方を知らなくても良い訳では無い。