目的と対象読者
helmについて今まで理解していなかったのですが、Documentを読んでキャッチアップしてみました。しかしDocumentは網羅性がある一方で概要を把握するには情報過多で、それができるチュートリアルもうまく見つからなかったので、備忘録も兼ねて記事にすることにしました。
以下のような方を対象にして書いているつもりです。
- helmのアーキテクチャーや用語を理解したい
- helmの基本的な使い方を広く浅く理解したい
また以下の前提で動作を確認していきます。
- kubernetes(以下k8s)クラスタが構築されている
- helmやtillerがインストールされている
- helmのバージョンはv2である
helmの構成要素
helmとはk8sのパッケージマネジャーのことです。
パッケージとはk8sのマニフェスト(リソースの設定ファイル)の集合であり、helmはそれらを管理するためのツールと言えます。
c.f https://github.com/helm/helm#helm
Helm is a tool for managing Kubernetes charts. Charts are packages of pre-configured Kubernetes resources.
このパッケージマネジャーは具体的には、以下のような機能を提供しています。
c.f https://docs.helm.sh/architecture/
- パッケージを共有、取得、管理する
- パッケージを作成、更新する
- パッケージをk8sクラスタに適用、巻き戻し、削除
これらの機能があることで、誰かが作ったマニフェストと同じようなものを作る必要がなくなったり、誰がいつどんな目的でk8sクラスタにこのマニフェストを適用したのか分からなくなることを防いだり、あるタイミングでapplyした内容に巻き戻したりすることができます。
まずは、helmに登場する用語を整理しましょう。
用語はDocumentで解説されており、詳しくはそちらを参照してください。
用語 | 説明 |
---|---|
helm | k8sのパッケージマネジャー |
chart | パッケージ(マニフェストの集合) |
repository | chartを保管したりダウンロードするサーバー |
release | k8sクラスタに適用されたchartで履歴管理用に保管される |
tiller | chartをk8sクラスタに適用したりreleaseを管理するサーバー |
これだけだとイメージが湧かないと思うので、図にすると以下のようになります。
これらのことから、helmはchartを見つけたり作成してrepositoryに保管し、chartの内容からk8sリソースをクラスタ上に作成し、その度にreleaseを作ることができる一連の利用シーンが理解できるかと思います。そして、releaseが作られることで、適用した内容をバージョン管理できるので巻き戻しや更新などの管理も可能になります。
c.f https://docs.helm.sh/using_helm/#three-big-concepts
chartを作る
chartの構成要素
上述の通り、chartとはパッケージであり、k8sリソースの設定ファイルの集合です。
c.f https://docs.helm.sh/developing_charts/#charts
Helm uses a packaging format called charts. A chart is a collection of files that describe a related set of Kubernetes resources.
概要について説明できたので次は作りながらchartをどのように作るかを見ていきたい思います。まず、chartは以下のような構成要素から成り立ちます。
c.f https://docs.helm.sh/developing_charts/#the-chart-file-structure
構成要素 | 機能 |
---|---|
Chart.yaml | chartに関するメタ情報が記述される(nameなど) |
requirements.yaml | 依存する外部のchartが指定される |
values.yaml | templateに当てはめる値が記述される |
charts/ | 現在のchartが依存するchartの一覧 |
templates/ | values.yamlの値を嵌め込むことができるk8sマニフェストを作る雛形の一覧 |
実際にchartを作ってみます。まず、chartをk8sクラスタにデプロイするには、tillerサーバーを初期化させる必要があります。
kubectl config view --minify
で現在接続しているクラスタを確認し、そのクラスタのkube-system
namespace内にtillerのpodを作成します。
$ kubectl config view --minify
$ helm init
$ kubectl --namespace kube-system get pods --selector name=tiller
NAME READY STATUS RESTARTS AGE
tiller-deploy-7995854f67-jzx4d 1/1 Running 0 55m
次に、以下のコマンドでmychartというchartを作成します。
c.f https://docs.helm.sh/chart_template_guide/#a-starter-chart
$ helm create mychart
Creating mychart
実際に、上記のchartの構成要素となるファイルが生成されていることが確認できます。
$ ls mychart
Chart.yaml charts templates values.yaml
template
まずはtemplateを作ります。templateは、k8sマニフェストの雛形で後述のvalues.yamlやコマンド引数で渡される値を嵌め込み、tiller経由でk8sクラスタに適用されます。
c.f https://docs.helm.sh/chart_template_guide/#charts
The templates/ directory is for template files. When Tiller evaluates a chart, it will send all of the files in the templates/ directory through the template rendering engine. Tiller then collects the results of those templates and sends them on to Kubernetes.
The values.yaml file is also important to templates. This file contains the default values for a chart. These values may be overridden by users during helm install or helm upgrade
ここではconfigmapのtemplateを作ってみますが、先ほど生成されたデフォルトのtemplateは利用しないので削除します。
$ rm -rf mychart/templates/*
その上で、mychart/templates/configmap.yaml
に以下のconfigmapのマニフェストを作成します。これはtemplateですが、値は既に嵌め込まれた状態です。
# mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
helm install [chart-name]
で先ほどのtemplateをtiller経由でデプロイしてみます。
$ helm install ./mychart
NAME: hardy-grizzly
LAST DEPLOYED: Sat Feb 9 19:23:20 2019
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
mychart-configmap 1 0s
実際に、hardy-grizzly
という名前のchartが以下のマニフェストとしてデプロイされたようです。
c.f https://docs.helm.sh/chart_template_guide/#debugging-templates
$ helm get manifest hardy-grizzly
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
実際にconfigmapが作成されていることも確認できました。
$ kubectl get cm
NAME DATA AGE
mychart-configmap 1 47m
また、templateは値を嵌め込むだけではなく、値に応じた条件分岐(if
)や利用する値のスコープの制御(with
)、ループ(range
)などを使ってtemplateを作ることもできます。
c.f https://docs.helm.sh/chart_template_guide/#flow-control
values
templateに値を渡す
templateを作成したので、次はtemplateに値を渡してみましょう。
templateに値を提供する方法は主に二つあります。
c.f https://docs.helm.sh/developing_charts/#templates-and-values
- values.yamlを開発者が用意する
- chartの利用者が helm install コマンド時に値を渡す(values.yamlを上書きすることができる)
実際にvalues.yamlからtemplateに値を渡してみます。以下のように、values.yamlを書き換えます。
# mychart/values.yaml
favoriteDrink: coffee
先ほどのconfigmapのtemplateを以下のように書き換えます。
# mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favoriteDrink }}
以下の--dry-run --debug
フラグを使うことで、実際にはデプロイせずに、デプロイされるchartの内容を確認できます。
c.f https://docs.helm.sh/chart_template_guide/#adding-a-simple-template-call
When you want to test the template rendering, but not actually install anything, you can use helm install --debug --dry-run ./mychart. This will send the chart to the Tiller server, which will render the templates. But instead of installing the chart, it will return the rendered template to you so you can see the output:
$ helm install --dry-run --debug ./mychart
NAME: wishing-porcupine
REVISION: 1
RELEASED: Sat Feb 9 19:39:31 2019
CHART: mychart-0.1.0
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
favoriteDrink: coffee
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: wishing-porcupine-configmap
data:
myvalue: "Hello World"
drink: coffee
values.yamlで指定した値がtemplateで利用されていることが確認できます。
また、--set
フラグでvalues.yamlの値をinstall時に上書きすることもできます。
$ helm install --dry-run --debug --set favoriteDrink=slurm ./mychart
NAME: jittery-aardvark
REVISION: 1
RELEASED: Sat Feb 9 19:41:04 2019
CHART: mychart-0.1.0
USER-SUPPLIED VALUES:
favoriteDrink: slurm
COMPUTED VALUES:
favoriteDrink: slurm
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: jittery-aardvark-configmap
data:
myvalue: "Hello World"
drink: slurm
subchartの値を操作する
次にsubchart(現在のchartが依存するchart)を作ってみます。
$ helm create mychart/charts/mysubchart
Creating mysubchart
$ rm -rf mysubchart/templates/*
subchartのtemplateに以下のファイルを追加します。
# mychart/charts/mysubchart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cfgmap2
data:
dessert: {{ .Values.dessert }}
そして、subchartのvalues.yamlを以下のように書き換えます。
# mychart/charts/mysubchart/values.yaml
dessert: cake
top levelのchart(mychart)はsubchart(mychart/charts/mysubchart)のvalues.yamlも利用することができます。その場合は対象のsubchartの名前を挟む必要があります。
c.f https://docs.helm.sh/developing_charts/#scope-dependencies-and-values
Charts at a higher level have access to all of the variables defined beneath
以下のように、対象のsubchartの名前を指定して、そのsubchartのvalues.yamlの値をtop levelのtemplateから参照できます。
# mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favoriteDrink }}
dessert: {{ .Values.mysubchart.dessert }}
$ helm install --dry-run --debug ./mychart
---
# Source: mychart/charts/mysubchart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: imprecise-chimp-cfgmap2
data:
dessert: cake
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: imprecise-chimp-configmap
data:
myvalue: "Hello World"
drink: coffee
dessert: cake
またsubchartのtemplateに渡される値をtop level のvalues.yamlから上書きすることもできます。
subchartでは、以下のように値が指定されています。
# mychart/charts/mysubchart/values.yaml
dessert: cake
これをtop levelのvalues.yamlで上書きしてみます。
# mychart/values.yaml
favoriteDrink: coffee
mysubchart:
dessert: ice cream
cake
ではなく、ice cream
に値が上書きされていることが確認できます。
$ helm install --dry-run --debug ./mychart
---
# Source: mychart/charts/mysubchart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: illocutionary-seal-cfgmap2
data:
dessert: ice cream
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: illocutionary-seal-configmap
data:
myvalue: "Hello World"
drink: coffee
dessert: ice cream
値の上書きの優先順位
実際は以下のような優先順位でtemplateに渡す値を上書きすることができます。
c.f https://docs.helm.sh/chart_template_guide/#values-files
- --set フラグでkey-valueを指定
- -f フラグで利用するvalues.yamlを指定
- top levelのvalues.yaml
- subchartのvalues.yaml
このような前提を成り立たせるためにsubchartはそれだけで独立(親のchartに依存しない)する必要があります。なぜなら親が必ずsubchartで定義した値を上書きするとは限らないからです。
c.f https://docs.helm.sh/chart_template_guide/#subcharts-and-global-values
global values
ここまでvalues.yamlの機能を説明してきましたが、グローバルな値を定義することも可能です。
c.f https://docs.helm.sh/chart_template_guide/#global-chart-values
Global values are values that can be accessed from any chart or subchart by exactly the same name.
The Values data type has a reserved section called Values.global where global values can be set.
今まで特定のsubchartのvalues.yamlを上書きするには、subchartの名前(Chart.yamlのname)を指定する必要がありました。
# values.yaml
mysubchart_1:
dessert: ice cream
mysubchart_2:
dessert: ice cream
しかし、global valuesだとsubchartの名前の指定なく全てのsubchartの{{ .Values.global.dessert }}
の値を上書きできます。
# values.yaml
global:
dessert: ice cream
書くための規則
chartを今まで作成してきましたが、書く上でのベストプラクティスが存在します。
yamlのフォーマット
c.f https://docs.helm.sh/chart_best_practices/#formatting-yaml
- tabではなく、2 spaceでインデントする
chart
c.f https://docs.helm.sh/chart_best_practices/#chart-names
- 小文字で始まる名前をつける
- 大文字やアンダースコア, ドットは名前に使うべきではない
template
c.f https://docs.helm.sh/chart_best_practices/#templates
- camelCaseではなくdashed notationでファイルを名付ける(e.g my-example-configmap.yaml)
- resourceの種類を反映したファイル名前にする(e.g my-service.yaml)
values
c.f https://docs.helm.sh/chart_best_practices/#values
- 小文字で始まるcamelCaseで名付ける(e.g
chickenNoodleSoup: true
) - 丁寧にnestして値を定義した方がいい
- nestしていると、それぞれの名前空間が存在するかチェックされるので安全
- 名前空間が区切られていた方が分かりやすい
release管理をする
releaseとは、k8sクラスタにデプロイされたマニフェストの集合(chart)です。
したがって、helm install [chart-name]
でtillerがk8sクラスタにapplyするとreleaseが作成されます。
$ helm ls
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
hardy-grizzly 1 Sat Feb 9 19:23:20 2019 DEPLOYED mychart-0.1.0 1.0 default
helm delete [release-name]
でクラスタからreleaseの内容のマニフェストを削除することができます。
しかし削除されても履歴管理のためにrelease自体は残されます。
c.f https://docs.helm.sh/using_helm/#uninstall-a-release
Because Helm tracks your releases even after you’ve deleted them, you can audit a cluster’s history, and even undelete a release (with helm rollback).
$ helm delete hardy-grizzly
release "hardy-grizzly" deleted
$ helm ls --deleted
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
hardy-grizzly 1 Sat Feb 9 19:23:20 2019 DELETED mychart-0.1.0 1.0 default
これを以下のように巻き戻すこともできます。
$ helm rollback hardy-grizzly 1
Rollback was a success! Happy Helming!
$ helm ls
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
hardy-grizzly 2 Sat Feb 9 20:27:44 2019 DEPLOYED mychart-0.1.0 1.0 default
また以下のように履歴を確認することもできます。
c.f https://docs.helm.sh/helm/#helm-history
$ helm history hardy-grizzly
REVISION UPDATED STATUS CHART DESCRIPTION
1 Sat Feb 9 20:46:21 2019 SUPERSEDED mychart-0.1.0 Deletion complete
2 Sat Feb 9 20:47:09 2019 DEPLOYED mychart-0.1.0 Rollback to 1
--purge
フラグでreleaseも含めて完全に削除することができます。
$ helm delete --purge hardy-grizzly
release "hardy-grizzly" deleted
最後に
ちなみに、tiller
はv3からは無くなる予定のようです。
c.f https://github.com/helm/community/blob/master/helm-v3/000-helm-v3.md#summary
Tiller is gone, and there is only one functional component (helm)