Helmの概要とChart(チャート)の作り方

# 記事の内容
この記事では、 Helm Chart(チャート)を作るというゴールに向けて、以下のことを説明します。

- Helm自体の概説 (前半)
- Helmチャートの作り方 (後半)

## この記事の作成に至った動機付けと背景

- Helm自体や、その利用手順についての情報は多いが、「Helmチャートそのものの作り方」について、特に日本語で説明したものが少ないように思えたため。
- Helmについては、チャートの作り方を含めて [https://helm.sh/](https://helm.sh/) のサイトにある[公式ガイド](https://docs.helm.sh/)に良くまとまっているため、「それを頭からちゃんと読めば良い」のは確かなのですが、もう少し「本家ガイドを読む前にさっと流して理解できるまとめ」があっても良いように思えたため。

人数的には明らかに「`Helmを利用するだけの人 > Helmチャートを作成する人`」だと思いますが、後者の方の初期ステップのお役に立てば幸いです。

---

# Helm とは

> Helm自体の解説は、既にWeb上で多くの良い解説記事や資料が日本語でも豊富にあると思います。既にご存じの方は読み飛ばして下さい。

[公式サイト](https://helm.sh/)には「The package manager for Kubernetes」つまり「Kubernetes用のパッケージマネージャ」と記載されています。

ではその「Kubernetes用のパッケージ」とは何か、その単位とは何なのかということになりますが、これは「**1つのアプリケーション(業務システム)としての動作を行う為に必要なKubernetesの様々な種類のリソース(Deployment, Service, Ingress, Secret, ConfigMap, PersistentVolume, … など)**」であり、それをひとまとめにして管理する仕組みと、そのためのツールセットを提供するもの、と理解しておけば良いでしょう。

## パッケージマネージャとは

パッケージマネージャというと、下表のようなものが想起されるかたもいらっしゃると思います。(きっとその理解で間違ってはいないでしょう)

例えば、他の「パッケージマネージャ」と呼ばれるものと対比的に記述すると以下のような形になります。

| パッケージマネージャ | パッケージとして扱う対象 |  クライアントコマンド    | サーバーコンポーネント | リポジトリ |
|--------------|------------------|------------------|------------|-------|
| Helm         | Kubernetesリソース群の一式  | helmコマンド  | tiller | Helmチャートリポジトリ<br>通常のWebサーバーであればプライベートリポジトリを構築可能(*)
| NPM(Node Package Manager)  | npmモジュール     | npmコマンド  | - | npmリポジトリ(公式・プライベート)<br>SinopiaやVerdaccioなどでプライベートリポジトリを構築可能     
| APT (Advanced Packaging Tool) | Debパッケージ | aptコマンド | - | aptリポジトリ(公式・プライベート)<br>apt-mirrorやaptlyなどでプライベートリポジトリを構築可能
|  :  | : | : | : | :

どのパッケージマネージャも「“パッケージ”を登録し共有するリポジトリの概念と仕組みを持つ」、「パッケージのインストールやアンインストールができる」、そして「あるパッケージが他のパッケージを利用する(依存する)という関係性を保持する」といった性質を持っていますが、まさにHelmもそれらの性質と役割を担うものです。

- 自分のKubernetesクラスター環境へのデプロイ(インストール)・削除(アンインストール)
- パッケージを共有する仕組み(リポジトリ)
- 新規のパッケージを開発する支援機能


(*) Helmのリポジトリ(チャートリポジトリ)として振る舞う為の要件は非常にシンプルなため、静的なWebサーバーだけでも構築することが出来ます。そのため、例えばGitHub Pagesの仕組みを使って、GitHubのリポジトリをそのままHelmリポジトリとして公開するといったことも可能です。

## なぜHelmが必要となるか(登場の背景)

背景としては、概ね以下の流れであるという理解で良いのかなと思います。

1. コンテナ技術(Docker)が登場した。
2. 大量のコンテナのインフラ管理のための仕組みが必要になり、(docker-swarmや) Kubernetesというコンテナオーケストレーション基盤と位置づけられるソフトウェアが登場した。
3. 自然な帰結として、次はその基盤上で、Kubernetesのリソース群を効率良く、アプリケーションという論理的な単位で扱えるパッケージマネージャが必要になった。**→ Helmの登場**

### 具体的なメリットの例

もっと単純に、Helmが提供してくれる利点の一例を挙げると、「アプリのアンインストール」が簡単に実現できる、というものがあります。

確かに kubectlコマンドだけでも、Kubernetesリソースを「作成する」時は、`kubectl apply -f myapp.yaml` コマンドで一気に作成することができます。

- 上記の例ではmyapp.yamlに、YAMLそのものの仕様である「---」区切りで複数のリソース定義をするという仕組みを利用することで、結果として1回のコマンド実行で複数のKubernetesリソースを一気に作成・定義することができます。

ただし、作成された大量のKubernetesリソースを一括で整合性をもって削除することは、1回のkubectl deleteコマンドでは実現できず、Helmのようなパッケージマネージャがあって初めて実現できるといえます。

このように、Kubernetesクラスター上に多数のアプリケーションをデプロイしていくことを考えると、Kubernetesの世界にも「パッケージマネージャ」の必要性が高まることは、自然な流れだと理解いただけるでしょう。


## Helmの全体像

さて、この当たりで図をベースに話を進めた方が良いと思いますので、手製の図を掲載します。

![helm_overview.png](https://qiita-image-store.s3.amazonaws.com/0/73663/f188a49f-6852-d419-0686-b3f4c1edaa22.png)


## Helm の構成要素

上記の図にも登場している、Helmの構成要素について下表に示します。

| 構成要素 | 説明 |  補足
|--------------|------------------|------------------|
| helm(CLI)| go言語で開発されたコマンドラインツール。 | ローカルOS環境の$HELM_HOMEでポイントする場所に、設定ファイル群や、「ローカルリポジトリ」を作り出し、その上でtillerと通信してKubernetesクラスタとのやりとりを行います。
| tiller(サーバー)| Kubernetesクラスタ内にリソースとして定義され、動作するサーバーアプリ。| helmコマンドからの要求に基づき、apiserverを介してKubernetesクラスタ内のリソース作成・削除・情報取得などの操作を行います。
| chart(チャート)| Helmにおける管理対象としての「パッケージ」|実体は.tgz形式の圧縮ファイル。様々なファイル群で構成され、Kubernetesのリソースを生成するためのテンプレートファイルやデフォルト値の設定ファイルなどが含まれる。 |
| release(リリース) | chartを使って実際にデプロイ(インストール)されたクラスタ上のオブジェクトをまとめて表したもの。|リリースは、暗黙にせよ明示的にせよ、「リリース名」が必ず与えられ、識別されます。
| chartリポジトリ| チャートをhelmクライアントに提供するWebサーバー | 仕様として定められたindex.yamlおよびchartファイル(.tgz)群をサービスすれば、それはchartリポジトリとなりえます。

## Helmを理解する上での補足

図を眺めて頂ければおおよその理解はできると思いますが、追加で幾つかポイントを挙げます。
(図だけでは漏れていることも含みます)

- 「Helmの全体」は、「helmクライアントコマンド」+「tillerサーバーコンポーネント」(+「helmチャートリポジトリ」とその中に登録されるチャート)から構成されます。
- Helmは、*最近のKubernetesの話題においては当たり前のように登場することも多いですが*、それ自体はKubernetesにとって必須のコンポーネントではなく、あくまでオプションです。
    - 従って、必要なら自分でHelmを所定のインストール手順で導入する必要があります。(helmコマンドバイナリをインストールした後で行う`helm init`コマンド)
    - **ただし**、Kubernetesを内部にラップしたようなソフトウェア製品(例:[IBM Cloud Private](https://www.ibm.com/cloud/private))では、初期時点でHelmが組み込み済のものも存在します。
- Helmを構成するサーバーコンポーネントであるtillerは、、デフォルトではKubernetesクラスターのシステム用の名前空間である`kube-system`にリソースを構成し、そこでインスタンスが起動します。
    - その意味では、Kubernetesシステムの中核コンポーネントの一種であると言えなくもないでしょう。
- Helmチャートのリポジトリは、「**Dockerイメージレジストリと同様に**」、様々な場所に存在しますし、自分だけあるいは自社内用のプライベートなリポジトリを構築することができます。
    - 初期状態では、Helm公式の安定版リポジトリが`"stable"`という名前で1つ登録済みです。<br>URLとしては[https://kubernetes-charts.storage.googleapis.com](https://kubernetes-charts.storage.googleapis.com)です。
    - そしてローカル環境のリポジトリが`"local"`という名前で1つ、合計2つ登録されています。<br> URLとしては [http://127.0.0.1:8879/charts](http://127.0.0.1:8879/charts)です。
    - 安定的ではなくstableに昇格していないものの、公式扱いされるリポジトリとして、incubatorという名前のリポジトリがあります。<br>URLとしては [http://storage.googleapis.com/kubernetes-charts-incubator](http://storage.googleapis.com/kubernetes-charts-incubator) です。
    - それ以外にも、様々な企業が自社製品のデプロイのためにHelmチャートリポジトリを公開・提供しています。例えば、IBMだと [https://raw.githubusercontent.com/IBM/charts/master/repo/stable/](https://raw.githubusercontent.com/IBM/charts/master/repo/stable/)のURLにて、様々なミドルウェア製品のためのHelmチャートリポジトリを公開しています。
- <font color="red">※注意</font>：Helmチャートリポジトリは、Dockerイメージレジストリとは全く別ものです。
    - HelmチャートリポジトリはあくまでHelmチャートのリポジトリであり、そこにDockerイメージは含まれていません。当然、DeploymentなどPodの実体イメージはDockerイメージを参照しているので関係は持ちますが、それは単に参照しているだけであり、どのイメージを使うかはそのチャートの中身の記述次第です。
- Helmチャート内で指定されたコンテナイメージに、実際にpullアクセス出来るかどうかは、「そのKubernetesクラスタ環境とその指定されたイメージを提供するDockerイメージレジストリのネットワーク疎通レベルの話」から、「認証が必要なプライベートなイメージリポジトリであるなら、その認証情報のためのimagePullSecretsが正しくSecretリソースとして作成されているかといったKubernetes定義上の問題」まで、必要な条件が満たされている必要があります。
- <font color="red">※注意</font>：Helmチャートリポジトリ内の情報(どのような名前・バージョンのチャートが登録されているか)、は、Helmクライアント側でキャッシュしています。最新のそのリポジトリ内の情報を得るには、`helm repo update`コマンドを実行して、再度取得してキャッシュをリフレッシュする必要があります。
- Helmチャートを使って実際にKubernetesクラスターにアプリケーションを導入する処理は`helm install`コマンドで行いますが、その対象名前空間は`--namespace`オプションで指定するか、指定しなければそのKUBECONFIGのコンテキストにおける「デフォルトの名前空間」が使われます。


## Helm chart と release とは

さていよいよ本論の**chart(以下、チャート)**についてです。

> chart(チャート)という名前は「海図」を意味する単語に由来しており、tillerは「舵柄」。どちらもKubernetes(「操舵輪」)からくる世界観に合わせた名前だと思いますが、特にアナロジーとして分かりやすい訳でもないと思いますので、気にしないでおきましょう。

チャートは以下のようなものです：

- 物理的には「**再利用が可能なKubernetesリソースの一式を、所定の仕様でパッケージングしたファイル**」です。
    - tarボール形式でgzip圧縮された状態(ファイル拡張子は.tgz)です。
    - この.tgzファイルがリポジトリに登録(=アップロードされて配置された状態)されます。
        - 実際には複数のチャートがあり得るので、それらの目録(インデックス)としてのindex.yamlと共に配置されます。
        - 逆に言うと、**このindex.yamlとチャートの.tgzファイルがHTTP(またはHTTPS)でサービスされるURLがHelmチャートリポジトリである**ということになります。
    - 圧縮ファイルとしての形態は、共有のためにHelmチャートリポジトリに配置される最終的な形であり、実際には所定の構造や名前のファイル群が配置された1個のディレクトリです。

- 内容的には「go言語のテンプレート書式で記述されたテキストファイルや、パラメーターのデフォルト値が記述されたYAMLファイルなどの集合体」です。
    - Helmチャートはまさにテンプレートそのものであり、`helm install`コマンドでのインストール時にコマンドラインオプション(`--set`や`--value`など)でパラメーターを与えることができるようになっています。

> go言語は、JavaやJavaScriptと異なり、標準ライブラリとして必要十分な機能を持つテンプレートエンジンを提供しています。後に簡単に解説しますが、チャートを開発する上では、このテンプレートエンジン用のDSLを学習する必要があります。

### Release(リリース)とは

では、**リリース**とは何でしょうか。チャートと併せて理解しておきましょう：

- Helmチャートを実際にそのKubernetesクラスターにデプロイしたら、そのインストールによってデプロイされた構成全体を意味する定義が作成されます。これを**「リリース」**と呼びます。
    - (プログラミングの世界でいうなら、チャートという「クラス」からリリースという「インスタンス」が生成されるようなイメージです)
    - つまり、同じKubernetesクラスターでも、1つのチャートから、名前が異なる限りにおいて複数のリリースを作成することが出来ます。
- リリースには必ず名前がつけられています。
    - 名前は `helm install`コマンドの`--nameオプション`で指定します。
    - <font color="red">※注意</font>：指定しなかった場合は適当な単語のランダムな組み合わせの名前で作成されてしまうので、原則として明示的に指定します。
- `helm install`コマンドが成功し、作成されたリリースは、そのまとまりで削除や内容の更新が可能です。
    - 同じチャートの異なる(より新しい)リビジョンを使って内容を書き換えることが「更新」になります。
    - また、`helm rollback`コマンドによって、指定したリビジョンの内容に復帰させるということが可能です。
    - `helm delete`コマンドで「リリース」を削除することができますが、`--purge`オプションをつけない限り、「DELETED」の状態としてそのリリース定義自体は維持されます。この振る舞いによって、`helm rollback`で「リリース削除の取り消し」も可能です。
- インストール後は、`helm list`コマンドによって、作成済みのリリースの一覧を得ることができます。
    - 「DELETED」な状態のリリースを表示するには、`--all`オプションの指定が必要です。

> `helm install`コマンドは、`helm upgrade`コマンドの`--installオプション(-iオプション)`で代替できるので、実際には helm install コマンドを使わず、helm upgradeコマンドだけで統一することができます。

## チャートの利用手順

実際にチャートを利用する際の手順と内部の流れは、以下のようなものとなります。

0. Helm環境が導入されていなければ、以下の手順で先にクライアント環境とKubernetes環境のセットアップを行う必要があります。
    1. OSに応じたhelm CLIコマンドを入手し、インストールする。
    2. kubectlが実行可能で、Kubernetesクラスタのマスターノードにアクセス可能な状態で、`helm init`コマンドを実行する。
        - `helm init`コマンドの実行により、`$HELM_HOME`環境変数(初期値は`$HOME/.helm`)以下に所定のディレクトリとファイル群が生成されると同時に、tillerに関するリソースがkubernetesクラスタのkube-system名前空間に作成されます。
1. helmクライアント環境において、チャートがある場所がまだ認識済みでないリポジトリであれば、そのHelmチャートリポジトリのURLを登録(`helm repo add`コマンド)して、Helmクライアント環境がチャートの検索先として認識出来るようにします。
    - 例：公式incubatorリポジトリをHelmクライアント環境登録するためには、以下のようにコマンドを実行します。<br>
    ``` helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator ```
    - `helm repo add`コマンドは、`$HELM_HOME/repository/repositories.yaml`を更新しています。`helm repo list`コマンドで一覧を表示することも出来ますが、それはこのファイルの内容を整形表示しています。
2. helmクライアント環境において、チャート名を指定して、自Kubernetesクラスタ環境へのインストールを行います。(`helm install --name <リリース名> --namespace <名前空間> <チャート名>`コマンド)
    - 実際にはリソースを作成せずに、どのようなリソースが登録されるかを事前にチェックするために、`--dry-run`オプションを指定して初回は実行することをお勧めします。
3. ドライランではなく実際の実行を行うと、以下のような流れで処理が進みます。
    1. チャートに含まれているテンプレートファイル群にデフォルト値や実行時のパラメーター値とマージしながら、goテンプレートエンジンがKubernetesのリソース定義が作成される。
    2. 前後の参照関係(依存関係)が判断されながら、そのリソース定義を使って内部的にtillerにgRPCプロトコルで要求が行われる。
    3. tillerは、受信した要求に対応し、クラスタ内でapiserverにREST/JSON通信を行い、対象となる名前空間にリソースを作成する。

helmのチャートを利用する、つまり使う立場としては、helmコマンド(CLI)の使い方やリポジトリの考え方を知っていれば良いので、それほど難しいものではありません。

## Helm 関連 の Web UI 提供ツール

Helmの利用は、主にhelmコマンド(CLI)を使用しますが、Helm関連でUI(Web GUI)を提供するものとしては、以下が存在します。

### [chartmuseum](https://github.com/kubernetes-helm/chartmuseum)

Web UIつきのHelmチャートリポジトリ機能を提供するツールです(helmクライアントと同じく、chartmuseumもGo言語で開発されています)。
Helmチャートリポジトリを構成する最低条件は「index.yamlとチャートそのもの.tgzをHTTP GETリクエストに対して返すこと」ですが、やはりチャートの一覧表示や、アップロードを受けつけて保存するといった機能を提供するWebアプリケーションがあると便利です。chartmuseumはまさにそのような機能を提供するものです。チャートを保存するバックエンドのストレージとして、以下を選択出来ます。

 - Amazon S3
 - Google Cloud Storage
 - Microsoft Azure Blob Storage
 - Alibaba Cloud OSS Storage
 - Openstack Object Storage

このcharmuseum自体のHelmチャートも公式安定版サイト[stable/chartmuseum](https://github.com/kubernetes/charts/tree/master/stable/chartmuseum)として提供されています。


### [monocular](https://github.com/kubernetes-helm/monocular)

monocularは、Helmクライアント(CLI)のWeb UI版といえます。登録されたHelmチャートリポジトリを複数参照しつつ選択してそのチャートを元にクラスターへデプロイする、といったHelmクライアント機能を提供するWebアプリケーションです。

![MonocularScreenshot.gif](https://qiita-image-store.s3.amazonaws.com/0/73663/2df1dc0e-53ae-be10-4659-639baf9d054b.gif)

これらのツールを導入すれば(あるいは、既に管理者の手によって導入されていれば)、CLIを使わずブラウザで同じ操作を行うことも可能です。

このmonocularのHelmチャートも提供されていますが、このチャートを提供するHelmリポジトリは専用のサイトになっており、以下のように`helm repo add`コマンドでリポジトリを登録してから使用する必要があります。

```
$ helm repo add monocular https://kubernetes-helm.github.io/monocular
$ helm install monocular/monocular
```

---

それでは以降は後編として、Helmチャートの作り方について記載します。

## Helmチャートの開発

この記事の存在意義の否定になってしまうかもしれませんが:sweat_smile:、チャートの開発は、既存の公式チャートの中身を見ることが最良の学習手段といえます。

*なのですが*、いきなりガイドを読み始めるとやや敷居が高い(億劫)のも事実です。(少なくとも私はそうでした)

ということで、前準備としての情報を整理してみたいと思います。

### Helmチャートの開発を行う上で知っておくべき知識

個人的な意見ですが、Helmチャートの開発は、難しい作業というより「面倒くさい」との表現を使いたくなる作業だと思います。

Kubernetesの人気が高まる一方で、大量に登場するYAMLリソースファイルとその管理が煩雑さや敷居の高さを揶揄した「**wall of YAML (YAMLの壁)**」という言葉をすら目にするようになってきました。
Helmはそれを解決するものではなく、むしろチャートという新たな独自のYAMLを登場させています。

ただ、Kubernetesオブジェクト(リソース)のYAMLは、Kubernetesのユーザー(アプリケーション開発者含む)が否応なく意識せざるをえませんが、HelmのチャートのYAMLはHelmの(クライアントとしての)ユーザーはあまり意識する必要はなく、その「面倒くささ」はHelmチャートの作成者が耐えればすむものといえます。

では、そのHelmチャートの開発のために必要な前提知識を並べてみましょう。

### 前提知識1. Helmチャートの構造

Helmチャートは最終的には.tgz形式の圧縮ファイルになりますが、そもそもの構造は[ガイド](https://docs.helm.sh/developing_charts/#charts)にあるように、以下の構造のもとで予約された名前のファイル名などが配置された1つのディレクトリとなります。

```
<チャート名ディレクトリ>/
  Chart.yaml          # チャートの概要が記述されたYAMLファイル(ファイル名は予約)
  LICENSE             # オプション:このチャートのライセンス情報
  README.md           # オプション: チャートの説明
  requirements.yaml   # オプション: このチャートが利用する(依存する)他のチャートの一覧。(ファイル名は予約)
  values.yaml         # このチャートのデフォルト設定値が定義されたYAMLファイル。ファイル名は予約)
  charts/             # このチャートが依存するチャートをコピー配置するディレクトリ(ディレクトリ名は予約)
  templates/          # チャートの本体ともいえる、KubernetesオブジェクトのリソースYAMLのテンプレート群を配置するディレクトリ(ディレクトリ名は予約)
  templates/NOTES.txt # オプション:利用方法を生成するテキストファイル
  tests/              # オプション:helm testで実行されるテスト用YAMLを配置するディレクトリ(ディレクトリ名は予約)
```

上記のChart.yaml、requirementes.yaml, values.yaml そしてtemplatesディレクトリはまずはそのファイル名と役割は理解しておくことが何よりも必要なことと言えます。

このディレクトリ構造の雛形は、`helm create <チャート名>`コマンドで作成することができます。コマンドを実行すると、カレントディレクトリに指定したチャート名のディレクトリが作成され、その中に予約ファイル群が作成されるので、書き換えて利用します。

実際には上記以外にも幾つか、予約されたファイルが存在します。

#### その他のファイル: templates/_helpers.tpl

テンプレートのヘルパー関数が定義されたファイルです。`_helpers.tpl`ファイルは、"`_`"で始まっているため、templatesディレクトリ以下において、Kubernetesのリソーステンプレートとして使われないというルールに沿っているだけでなく、Partialファイルとしてのデフォルト扱いを受ける特別なファイルです。(.tplはそのファイルに対する慣習的な拡張子です)

- `_`で始まっているファイルは、他のテンプレートファイル内のどこからでも利用できるという共通扱いになります。つまり、名前がアンダースコア（`_`）で始まるファイルは、内部にマニフェストがないものとみなされます。
- これらのファイルは、Kubernetesオブジェクト定義へは変換されませんが、のチャートテンプレート内のどこでも使用できる位置づけです。
- これらのファイルはpartialsやhelpersと呼ばれる、共通のコードブロック(defineアクションで定義され、templateアクションで呼び出される)や、ヘルパー関数などが定義されます。

#### その他のファイル: .helmignoreファイル

`helm package`コマンドで.tgzファイルへとパッケージを行う際に、このファイルに記述したglobパターンにマッチするファイルは無視されます。

> .gitignoreや.svnignoreなどと同じ位置づけのファイルです。



### テンプレートDSL

 HelmはGo言語で開発されていると前編の記事で触れていますが、Helmチャートの役割は、言ってしまえば Kubernetesに作成するオブジェクト(リソース)の定義体YAMLをどのように生成するかなので、テンプレートエンジンが登場します。(go標準ライブラリにおいて、text/templateパッケージで提供されるもの)

「Helmチャート開発者 イコール Go言語の開発経験者」であれば良いのでしょうが、そもそもそうでない場合のほうが多いでしょう。その場合、Helmチャートの作成者は新規に高機能なテンプレート用DSLを学ぶ必要がある、ということになります。これはHelmチャート作成の上でやや敷居が高いところといえるでしょう。

Helmは、Go言語のテンプレートエンジンであることを覆い隠すことはせず、むしろその機能を積極的に使う方向ですので、Kubernetes公式のHelmチャートを読もうとしても、このDSLならではの書式が頻繁に登場するので「(なんとなくは分かるものの)すっと読めない」ことがその敷居を上げてしまっている印象もあります。

いずれにしても、Helmではこの条件分岐や、各種定数の参照(ユーザーが指定することになる「リリース名」などに)、マクロ(関数)の定義と呼び出しなどが可能な高機能なDSLを駆使してテンプレートとなるYAMLファイルを作成することになります。

なお、templates/ディレクトリの.yamlファイルは自動的にテンプレートエンジンによって全てテンプレートとして読込まれ、処理され、生成されたKubernetesリソースとして作成されることになります。


### Helmチャートの設計と作成

それでは実際のHelmチャートの設計と作成の手順を確認しましょう。Helmチャートを作成するに当たっては、大まかには下図のような流れで考えていくことになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/73663/06303d6d-98f7-1aac-6c21-1280c9f81304.png)


#### **[手順1]** 再利用する(再利用可能な)Helmチャートの検討

何よりも最初に行うべきは、自分のチャートが再利用できる(=依存する)チャートを探し、決定するということです。

自分の作成したいアプリケーション全体を考えて、「既存のチャート(それがKubernetes公式提供のものであれ、企業や個人がGitHubで公開しているものであれ)」がその一部分を提供してくれるかという観点で、公式stableやincubatorその他のリポジトリを`helm search <keyword>`コマンドや、あるいはWeb上を検索して探します。

例えば、自分の作成したいチャート、つまりアプリケーションが「アプリケーションサーバー」と「データベース」で構成されているなら、それらの構成要素に対し既存のチャートが既に提供されているか、という観点で調べましょう。

もし上手くチャートが提供されているなら、requirements.yaml にその利用対象のチャートの情報を記述します。例えば、想定するアプリケーションがApache CouchDBをデータベースに利用するWebアプリケーションであった場合、公式incubatorリポジトリのApache CouchDBのチャート(チャート名：couchdb)を利用できると判断した場合は、以下のようになります。

```
dependencies:
  - name: couchdb
    version: 0.1.2
    repository: http://storage.googleapis.com/kubernetes-charts-incubator
```

利用するチャートのバージョンを指定することも忘れずに行います。なお、このバージョンはあくまで**チャートのバージョン(リビジョン)であって、そのプログラム(ここではApache CouchDB)自身のバージョンとは無関係である**ことに注意して下さい。

また、これはチャートの構成仕様上やむを得ないことですが、<font color="red">チャートにはそれぞれ「パラメーター化されている箇所」が決まっており、必ずしも自分のチャートにとって望む「パラメーターを指定して変更したいポイント」が指定出来るようになっているとは限りません</font>。
生憎と、自分が切り替えたいポイントがテンプレート内で固定となってしまっている場合があります。

それが受け入れられなければ、そのチャートを再利用することができない(自チャートの依存対象とすることができない)という判断をせざるを得ない場合もあります。

> そのような場合には、似たような内容を自分のチャート内のテンプレートとして定義していく必要があります。もし、上手く再利用できる既存のチャートがなかった場合は、多数のリソースに対して1つずつテンプレートを定義していく必要があるかもしれません。(そして現実にはそのケースも多い)


#### **[手順2]** 自チャート内で必要なKubernetesオブジェクト(リソース)の決定

チャートを作ると言っても、いきなりチャートのYAMLファイルを書き始めるのは避けた方が良いでしょう。

まずは1つ1つ、通常の手順でリソース定義のYAMLファイルを作成し、`kubectl apply`コマンドでリソースを作成し、“意図通りに動く状態”を構築・確認したあとで、それらの定義を元に、テンプレート化することをお勧めします。


#### **[手順3]** チャートの可変パラメータ部分のデフォルト値の決定

Kubernetesのリソースには大量の設定項目がありますが、その全てをパラメータ化することは労力と時間の兼ね合いで難しいことも多いでしょう。

そのため、「ここはパラメータ化しておいたほうが良いだろう」というところを識別しつつ、同時にそのパラメータのデフォルト値を考えます。このデフォルト値は、チャート定義ファイルの1つであるvalues.yamlの内容として定義します。

このvalues.yamlの定義は、テンプレートファイル内から `.Values.aaa.bbb` のように、".Values"を接頭辞として、そのYAMLのルート構造以下にアクセスすることで値にアクセスし、利用できます。


#### **[手順4]** チャートの公開手段と場所の決定

早い段階から並行して、作成するチャートをどのように利用者に公開するのかを検討することをお勧めします。

Helmチャートリポジトリの実体は、`helm package`コマンドで.tgzファイルを作成しておいたファイル群と、それに対して `helm repo index`コマンドを実行して生成したindex.yamlファイルを配置した単なるWebサーバーである、ということは既に記載の通りです。

しかし、実際にはリポジトリがなくても、以下のように`helm install`でtgzファイルそのものを指定してインストールを行うことも可能です。

```
 $ helm install --name mychartrelease ./mychart/mychart.tgz
```

極めて限定的な提供範囲(社内かつ少人数など)であれば、Helmリポジトリを用意せずに、共有ファイルサーバーに.tgzファイルを置いておくだけ、という運用でも、場合によっては問題無いケースすらあり得ます。

また、`helm package`コマンドでパッケージングを行う以前に、チャート用のディレクトリそのものの構造でも、`helm install`コマンドでインストール対象とすることが出来ます。

```
 $ helm install --name mychartrelease ./mychart
```

つまり、「ディレクトリを共有する」という手段によっても最低限のHelmチャートの提供は可能ということになり、これは、GitリポジトリでHelmチャートディレクトリ(unpacked chart directory)を共有し、必要とする人が `git clone`で入手し、利用して貰うという方法もとりうるということになります。

とはいえ、Helmリポジトリを構築すれば各チャートのバージョン(リビジョン)管理をhelmクライアントが認識し、利用者にとって管理しやすいというメリットもあります。そのようなHelm本来の機能を活用したい場合は、上記のような簡易的な提供手段ではなく、社内用のHelmリポジトリを用意することが良いでしょう。

社内において、Helmリポジトリを立てるに当たってまだ決まった運用ルールがない場合もあると思いますので、早期に検討して、必要なら並行して動いておく方が良いでしょう。

#### **[手順5]** チャートの作成とテスト

helmコマンドには、新規のチャート作成のための雛形作成機能が備わっていて、それを足場とすることができます。

作業する任意の親ディレクトリ(Gitリポジトリ化しておくことがお勧め)で、`helm create <チャート名>`を実行します。

```
$ helm create mychart
Creating mychart
```

そうするとカレントディレクトリに、指定した名前のディレクトリが作成され、先に示した構造のファイルとディレクトリ群が作成されます。以降は、Helmチャートの実作成作業として、実態としてはtemplatesディレクトリ以下に、テンプレートファイルを配置していくことになります。

##### helm dependency buildによる依存チャートのダウンロード

自チャートが利用する(依存する)チャートが存在する場合、それらをrequirements.yamlファイルに記載しますが、実際にはその依存するチャート実態の物理コピーがcharts/ディレクトリ以下に配置しておく必要があります。

requirements.yaml ファイルの内容を元に実際にネットワーク通信を行い、認識しているHelmチャートリポジトリから.tgzファイルをダウンロードし、charts/ディレクトリ下にコピー配置するのが `helm dependency build`コマンドです。

> requirements.yamlを更新したら、`helm dependency update`コマンドを実行します。

このようにして自チャートの作成を行ったら、以下の手順で検証とテストを行うことになります。

##### helm lintによる検証

最低限、テンプレートの文法などに誤りが無いかのチェックを行う機能が`helm lint`コマンドによって提供されています。

OKであれば、以下のように `no failures`と表示されます。

```
     $ helm lint ./mychart
     ==> Linting ./mychart
     [INFO] Chart.yaml: icon is recommended
 
     1 chart(s) linted, no failures
```


ただし、あくまでこれは静的解析なので、ここでエラーが検知されなかったからといって、問題無く利用できるHelmチャートであるという確認ができた訳ではありません。

実際のテストは、`helm install --name リリース名 ./mychart`  または `helm upgrade --install リリース名 ./mychart` のように、ディレクトリを指定して実際にHelmクライアントからTillerを経由してKubernetes環境にデプロイしてみることで行う事ができます。

> Helmにはこの[ガイド](https://docs.helm.sh/developing_charts/#chart-tests)で示されているように、templates/tests/ディレクトリにテスト用YAMLを配置してそれとの比較から問題無くリソースが作成されているかどうかを検証するテスト機能が備わっています。しかし、複雑なチャート構成でなければ、特にこの機能を使うまでもなく、動作テストを行ったほうが良いことも多いでしょう。

実際に問題なければ、`helm package mychart`コマンドを実行し、パッケージングつまり.tgzファイルの作成を行います。

```
$ helm package mychart
    Successfully packaged chart and saved it to: C:\Users\xxxx\mychart-0.1.0.tgz

```

コマンドの結果、チャートがパッケージングされ、.tgzファイルが生成されます。


##### index.yamlの生成

Helmチャートリポジトリとして、最も原始的な index.yaml と .tgzファイルを手で配置する形式の場合、 index.yaml も作成する必要があります。このファイルは以下のような構造のYAMLファイルで、tgzファイルへのリンクや、そのdigest値が記録されているファイルです。(複数のチャートの情報がentriesセクション以下に列挙されます。

```
apiVersion: v1
entries:
  mychart:
  - apiVersion: v1
    appVersion: 1.0.0
    created: 2018-05-26T23:34:02.0184416+09:00
    description: My sample chart
    digest: 7cae70f1d315efe20067b8355b74fb9f16268b5d39b8433b3f9f34fe90c26eed
    maintainers:
    - name: John Doe
    name: mychart
    urls:
    - mychart-0.1.0.tgz
    version: 0.1.0
generated: 2018-05-26T23:34:02.014444+09:00
```

このファイルは、`helm repo index`コマンドを実行することで生成することができます。

> Helmチャートリポジトリとしての機能を提供するツール([chartmuseum](https://github.com/kubernetes-helm/chartmuseum)や[JFrog Artifactory](https://jfrog.com/)など)を使っている場合は、.tgzファイルをアップロードすればスキャンしてindex.yamlを再生成してくれるようなものもあります。

これでindex.yamlファイルと、チャート本体である.tgzファイルが完成しました。あとはこれらをサービスするWebサーバーに配置します。



## Helmチャートの利用

あとはHelmチャートを利用する側(ユーザー/クライアント)側の話になります。

Helmクライアントには、前述の通り「自分が認識しているリポジトリ」があるので、新規のHelmリポジトリは`helm repo add`コマンドでHelmクライアント側で登録し認識させる必要があります。

```
$ helm repo add fantastic-charts https://fantastic-charts.storage.googleapis.com --username my-username --password my-password
```

一度登録したあとは、`helm repo update`コマンドで定期的にローカルのキャッシュをリフレッシュしつつ、`helm install`コマンド (または `helm upgrade --install`コマンド)で、そのリポジトリが提供しているHelmチャートを使ったデプロイを行えば良いことになります。


> 注意：BASIC認証が設定され、サービスしているHelmリポジトリのWebサーバーにアクセスする場合は、`--username`、`--password`オプションが`helm repo add`コマンドのオプションとして追加されている**v2.9.0以降**が必要になります。


## まとめ と 終わりに

実際の細かなHelmチャートのテンプレート作成のテクニックまでは踏み込んでいませんが、Helmチャート作成から配置と利用までの大まかな流れは掴んでいただけたのではないでしょうか。

Kubernetesのエコシステムの成長と共に、その周辺のツール群も様々なものが登場していますが、Helmはその中でも公式のパッケージマネージャとして、実質的なコアコンポーネントの1つとして利用されていくのではないかと思います。

Helmの概要と共に、「チャートを利用する側」ではなく、「チャートを作る側」として作業を行うにあたっての最初のステップの一助になれば幸いです。

---

### 追記・補足：Helmチャート開発のための環境について

実際のチャート開発では、ローカルPCで基本的なHelmチャートの開発やテストを行えた方が良いことが多いです。実際の(“ちゃんとした”)Kubernetesクラスタを自由に利用できる環境であれば良いですが、カジュアルな動作確認をするためにも、ローカルPCで動作するKubernetes環境として、[minikube](https://github.com/kubernetes/minikube)環境があると良いでしょう。

<font color="red">※注意</font>：minikubeのインストールについてはこの記事では触れませんが、OSそしてminikube自体のバージョンの組み合わせによっては上手く動作しない、といった問題が生じることも多いため、単純に「最新バージョンのminikube」を使おうとはせずに、動くと分かっているバージョンの組み合わせを使うことをお勧めします。