プライベートHelm Hubを作ってHelmチャートを公開する

# 概要
Kubernetesを使う上で、自作のHelmチャートを活用したいケースは多々あると思いますが、作成したチャートをチーム内だけで公開したい場合には、自作のHelmリポジトリを作る必要が出てきます。
今回は、プライベートなKubernetes環境に[Helm Hub](https://hub.helm.sh/)ライクなGUI画面を構築し、Helmチャートを公開するサンプル実装手順を紹介します。

## 作成されるGUI画面例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233097/58579bc7-01f6-bd96-1eca-c0bde0f29b85.png)

## 構築するプライベートHelm Hubの全体像
- ここではMinikube上に、オブジェクトストレージをバックエンドにするHelmリポジトリを作り、GUIで公開します。

![monocular_demo (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233097/b1955482-2463-8a66-7c57-a5f6f63351f6.png)

## コンポーネント一覧
### Ingress
- Monocularにアクセスする際の前段に配置する負荷分散装置で、Monocularでは必須のためデプロイします。
- 今回は、Minikubeのアドオンをインストールすることにより、Kubernetes上にデプロイします。

### Monocular
- [Helm Hub](https://hub.helm.sh/)ライクなGUI画面でHelmチャートを管理できるWEBアプリケーションです。
- ブラウザ経由でアクセスし、Helmリポジトリを指定することでリポジトリに含まれるチャートの情報を表示できます。

### Chartmuseum
- カスタムHelmリポジトリ機能とその管理APIを提供するツールです。
- これ自体にはデータストアは含まれておらず、バックエンドのストレージを別途指定する必要があります。
- 今回はバックエンドのストレージにオブジェクトストレージを利用するものとします。

### MinIO
- Kubernetes上にデプロイ可能なオブジェクトストレージです。
- AWS S3互換のストレージとなっていて、AWS SDKの`aws`コマンドを利用してバケットやオブジェクトの操作が可能です。

### Minikube Node
- Minikubeが動作するインスタンスです。
- 今回はMinikubeのファイルシステム上に、Helmチャートを配置されるものとします。

# 前提事項
- 作業用PCにMinikubeがインストールされていること。
- 作業用PCにkubectl/helmコマンドがインストールされていること。
- Minikubeノードがインターネット環境に接続可能であること。

# 実行手順
## 0. 環境変数の設定
- 本手順内で有効な環境変数を設定します。デフォルト値を記載しておりこのままでも動作可能ですが、適宜編集して使用してください。

```bash
export MONOCULAR_URL=monocular.local
export MINIO_ACCESS_KEY=myAccessKey
export MINIO_SECRET_KEY=mySecretKey
export CUSTOM_HELM_REPO_BUCKET=my-helm-repo-bucket
export CUSTOM_HELM_REPO_NAME=my-helm-repo
export MINIO_RELEASE_NAME=minio
export CHARTMUSEUM_RELEASE_NAME=chartmuseum
export MONOCULAR_RELEASE_NAME=monocular
```

## 1. Minikubeのセットアップ
### 1-1. Minikubeの起動
- Minikubeを起動します。
    - 注：今回の構成がスムーズに動作するよう、CPUは2コア以上、メモリは4GB以上、ディスクは20GB以上を指定するようにします。

```
minikube start
```

### 1-2. Ingressアドオンのインストール
- Ingressアドオンを有効にしてIngressをデプロイします。

```bash
minikube addons enable ingress
```

### 1-3. /etc/hostsへのエントリー追加
- URLを指定してMonocularにアクセスできるように名前解決を設定するため、下記コマンドの出力結果をOSの`/etc/hosts`に追記します。

```bash
echo `minikube ip` ${MONOCULAR_URL}
# 例: xxx.xxx.xxx.xxx monocular.local
sudo vim /etc/hosts
```

### 1-4. Helm環境のセットアップ
- Helm環境を初期化し、クラスター上にTillerをインストールします。

```bash
helm init
```

### 1-5. Helmリポジトリの有効化
- インストール対象のMinIO,Chartmuseum,Monocularが含まれる、インターネット上で公開されているHelmリポジトリを有効にします。

```bash
helm repo add stable https://kubernetes-charts.storage.googleapis.com/
helm repo add monocular https://helm.github.io/monocular/
```

## 2. Helmを利用したサービスのデプロイ
### 2-1. MinIOのデプロイ
- MinIO関連のKubernetesリソースをデプロイします。
    - AWS S3互換のオブジェクトストレージのため、S3と同じように`accessKey`と`secretKey`を指定できます。ただし本家と同じような文字列のフォーマットである必要はなく、任意のものが設定可能です。
    - `defaultBucket`でデフォルトでバケットを作成するように指定します。
    - ストレージの設定は変更しない(デフォルトを使う)ため、Minikubeノード内のローカルファイルシステム10GBが自動で割り当てられます。

```bash
cat <<EOF | helm install stable/minio --name ${MINIO_RELEASE_NAME} -f -
accessKey: ${MINIO_ACCESS_KEY}
secretKey: ${MINIO_SECRET_KEY}
defaultBucket:
  enabled: true
  name: ${CUSTOM_HELM_REPO_BUCKET}
  policy: none
  purge: false
EOF
```

### 2-2. Chartmuseumのデプロイ
- Chartmuseum関連のKubernetesリソースをデプロイします。
    - `open`フィールドではAWS S3互換のMinIOを利用するため、S3を利用する場合と同じように指定します。
    - `STORAGE_AMAZON_ENDPOINT`にはMinIOのエンドポイントを指定します。
    - `DISABLE_API`を明示的に指定して、APIを利用可能にします。
    - `secret`には2-1で指定したものと同じものを指定します。

```bash
cat <<EOF | helm install stable/chartmuseum --name ${CHARTMUSEUM_RELEASE_NAME} -f -
env:
  open:
    STORAGE: amazon
    STORAGE_AMAZON_BUCKET: ${CUSTOM_HELM_REPO_BUCKET}
    STORAGE_AMAZON_PREFIX:
    STORAGE_AMAZON_ENDPOINT: http://${MINIO_RELEASE_NAME}:9000
    DISABLE_API: false
  secret:
    AWS_ACCESS_KEY_ID: ${MINIO_ACCESS_KEY}
    AWS_SECRET_ACCESS_KEY: ${MINIO_SECRET_KEY}
EOF
```

### 2-3. Monocularのデプロイ
- Monocular関連のKubernetesリソースをデプロイします。
    - `open`フィールドではAWS S3互換のMinIOを利用するため、S3を利用する場合と同じように指定します。
    - `sync.repos`には管理対象のHelmリポジトリを登録します。
    - 今回はChartmuseumで作成するHelmリポジトリを指定し、1分おきに最新のHelmリポジトリの内容に更新する設定とします。
    - `ingress.hosts`には、`/etc/hosts`に登録したURLを指定します。

```bash
cat <<EOF | helm install monocular/monocular --name ${MONOCULAR_RELEASE_NAME} -f -
env:
sync:
  repos:
    - name: ${CUSTOM_HELM_REPO_NAME}
      url: http://${CHARTMUSEUM_RELEASE_NAME}-chartmuseum:8080
      schedule: "*/1 * * * *"
ingress:
  enabled: true
  hosts:
    - ${MONOCULAR_URL}
EOF
```

### 2-4. 確認
- デプロイが完了していることを確認するために、下記コマンドを実行します

```bash
kubectl get po
```

- `monocular-monocular-sync-xxx...`という名前のPod以外がすべて`Running`になっていることを確認します。


## 3. カスタムHelmチャートのデプロイ
### 3-1. カスタムHelmチャートの作成
- `demo-app`という名前のサンプルHelmチャートを作成し、Helmパッケージを作成します。

```bash
cd {Helmパッケージ作成フォルダ}
helm create demo-app
helm package demo-app
ls
# -> demo-app-0.1.0.tgz という名称のファイルが作成されます。
```

### 3-2. Chartmuseumへのチャートのアップロード
- 下記コマンドで、Chartmuseumサービスへのポートフォワードを行います。

```bash
kubectl port-forward svc/${CHARTMUSEUM_RELEASE_NAME}-chartmuseum 8080
```

- 別ターミナルを開き、下記コマンドにて作成した自作Helmパッケージをアップロードします。

```bash
cd {Helmパッケージ作成フォルダ}
curl --data-binary "@demo-app-0.1.0.tgz" http://localhost:8080/api/charts
# -> 正常にアップロードされると {"saved":true} と表示されます。
```

- ポートフォワードを行ったコマンドを実行したターミナルで、<Ctrl>+Cを押して終了します。

### 3-3. オブジェクトストレージ上でのアップロード確認
- 下記コマンドで、MinIOサービスへのポートフォワードを行います。

```bash
kubectl port-forward svc/${MINIO_RELEASE_NAME} 9000
echo URL: http://${MINIO_RELEASE_NAME}:9000
```

- ブラウザから`http://localhost:9000`にアクセスして、ファイルがバケットにアップロードされていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233097/a20f85ad-1fc9-ab10-6b30-051cba9b7d1a.png)

- ポートフォワードを行ったコマンドを実行したターミナルで、<Ctrl>+Cを押して終了します。

### 3-4. Monocular上で閲覧できることの確認
- 1分以上待った上で、下記コマンドを実行します。

```bash
kubectl get po
```

- `monocular-monocular-sync-xxx...`という名前のPodがすべて`Completed`になっていることを確認します。

- その後下記コマンドによって表示されるURLにアクセスします。

```bash
http://${MONOCULAR_URL}/charts/
```

- アップロードしたdemo-appというパッケージが表示されることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233097/58579bc7-01f6-bd96-1eca-c0bde0f29b85.png)


# まとめ
今回はプライベートなKubernetes環境上にHelmリポジトリを作成し、Helm HubライクなGUIで公開するサンプルを紹介しました。
アプリケーションをコンテナ化で進めれば進めるほど、Kubernetesリソースの管理が煩雑になってくるため、Helmチャートでの管理は重要なものとなってきます。今回紹介したMonocularやChartmuseumなどを使いながら、自作のアプリケーションもどんどんHelmパッケージ化を進めていくべきではないかなと思います。