1.この記事を書こうと思った背景
Helmwave なるものを Twitter で見かけた。
Helmwave の README.md にはこのように書かれている。
Helmwave is helm3-native tool
for deploy your Helm Charts.HelmWave is like docker-compose for helm.
Helmwave は、Helm チャートを展開するための helm3 ネイティブツールです。 HelmWave は docker-compose のようなものです helm 用に作成します。
出所:helmwave/helmwave: 🌊 Helmwave is true release manager (邦訳は Google 翻訳より)
よさそうなので、公式ドキュメントの Getting Started などを参考に Helmwave に入門する。
2.前提
2-1.ところで、Helm とは?
ぼくは、Helm 及び Helm Charts の理解も浅いのでこの場で深めておく。まず、Helm については公式ドキュメント にこのように書かれている。
The package manager for Kubernetes. Helm is the best way to find, share, and use software built for Kubernetes.
Kubernetes のパッケージマネージャー。 Helm は、Kubernetes 用に構築されたソフトウェアを検索、共有、および使用するための最良の方法です。
パッケージマネージャー というと APT を想起するけれども、まさに Helm を APT や NPM などと対比して解説しているブログもある。(例:Helm の概要と Chart(チャート)の作り方 - Qiita)
2-2.Helm Charts とは?
続いて、Helm Charts だが、これは Helm におけるパッケージ のことを指し、Helm Charts はひとつにかぎらず、複数の Kubernetes リソースをまとめることもあるという。
Helm uses a packaging format called charts. A chart is a collection of files that describe a related set of Kubernetes resources.
Helm は、チャートと呼ばれるパッケージ形式を使用しています。 グラフは、関連する Kubernetes リソースのセットを説明するファイルのコレクションです。
2-2.Helm Charts を宣言的に扱いたい
Kubernetes リソースを Helm Charts というパッケージ単位で操作できることはとても魅力的だが、いざ操作するとなると Imperative(命令的 ≒ コマンドを叩いていく) に扱わざるを得ないことに気がつく。たとえば、今回 Helmwave でデプロイする redis を helm コマンドで、my-namespace という namespace にデプロイする場合、このようになる。
$ kubectl create ns my-namespace
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm install redis-a bitnami/redis -n my-namespace
参考:redis 16.9.3 · bitnami/bitnami
そういうわけで、Helm Charts を使う場合も Kubernetes リソースを Declarative(宣言的) に、言い換えるとするならば、できるだけリソース定義をコマンドベースではなく、yaml に寄せたいということで Helmfile や今回取り上げる Helmwave のようなデプロイツールが出てきたとみている。
※ Imperative(命令的) と Declarative(宣言的) の選択は二者択一というわけではない
両者をどちらかひとつだけ!というより、グラデーションがかっているように、どちらに比重を置くか?というかんじに考えるべきだと思っている。どちらがいい?わるい?もまたケースバイケースであり、ここでは、Helmwave を使って Helm Charts を Declarative(宣言的) にできるだけ扱ってみるぞ!というスタンスとしたい。
※ 手前味噌だが、Imperative(命令的) に Kubernetes リソースを操作する必要があったケースの一例
2-3.Helmfile と Helmwave の類似点と相違点
類似点
- Helm Charts の宣言的なデプロイツール
相違点
- Helmfile では必要とされていた kubectl や helm コマンドは Helmwave では「必須」ではない
kubectl logsのような kubectl コマンドからデプロイの様子を見たい場合はkubectlは必要- ただし、helmwave でも status コマンドや up コマンドの
--kubedogというオプションでデプロイの様子を追うことは可能
それでは Helmwave をさわってみよう。
3.Helmwave をローカルでさわってみる
3-1.環境情報
$ grep VERSION= /etc/os-release
VERSION="20.04.4 LTS (Focal Fossa)"
$ helmwave --version
helmwave version 0.19.3
3-2.Helmwave をインストールする
📥 Installation - Helmwave にしたがってやるだけ
$ export VERSION=0.19.3
$ wget -c https://github.com/helmwave/helmwave/releases/download/v$VERSION/helmwave_${VERSION}_linux_amd64.tar.gz -O - | tar -xz
$ sudo mv helmwave /usr/local/bin/
$ helmwave version
0.19.3
3-3.Helmwave をローカルで動かす
3-3-1.releases.yml と helmwave.yml.tpl の 2 つのファイルを用意
- releases.yml
releases:
- name: redis-a
- name: redis-b
- helmwave.yml.tpl
- helmwave.yml.tpl は Templating(Go templates) を使うこともできる
version: 0.19.3
repositories:
- name: bitnami
url: https://charts.bitnami.com/bitnami
.options: &options
namespace: my-namespace
wait: true # ハマリポイント
timeout: 300s # ハマリポイント
create_namespace: true
releases:
- name: redis-a
<<: *options
chart:
name: bitnami/redis
namespace: my-namespace
- name: redis-b
<<: *options
chart:
name: bitnami/redis
namespace: my-namespace
# Templating(Go templates)を使う場合
version: 0.19.3
repositories:
- name: bitnami
url: https://charts.bitnami.com/bitnami
.options: &options
namespace: my-namespace
wait: true
timeout: 300s
create_namespace: true
releases:
{{- with readFile "releases.yml" | fromYaml | get "releases" }}
{{ range $v := . }}
- name: {{ $v | get "name" }}
tags: [{{ $v | get "name" }}]
namespace: my-namespace
chart:
name: bitnami/redis
<<: *options
{{ end }}
{{- end }}
3-3-2.helmwave.yml.tpl で helmwave.yml を生成する
$ helmwave yml
[🙃 aka INFO]: 📄 YML is ready!
build plan with next command: helmwave build -f helmwave.yml
3-3-3.helmwave.yml を使って Helmwave が内部で使う planfile を生成する
- 以下、3 つの書き方はどれも同じことをやっている
$ helmwave build
–tpl オプションでテンプレートファイルを指定し、–file, -f オプションで出力するファイルを指定する。
$ helmwave build --tpl helmwave.yml.tpl --file helmwave.yml
–yml オプションは --tpl helmwave.yml.tpl --file helmwave.yml を指定してくれる。
$ helmwave build --yml
[🙃 aka INFO]: 📄 YML is ready!
build plan with next command: helmwave build -f helmwave.yml
[🙃 aka INFO]: Building releases...
[🙃 aka INFO]: Building graphs...
[🙃 aka INFO]: Depends On:
┌────────────────┐
│ redis-a@my-... │
└────────────────┘
┌────────────────┐
│ redis-b@my-... │
└────────────────┘
[🙃 aka INFO]: Building values...
[🙃 aka INFO]: no values provided
release: redis-b@my-namespace
[🙃 aka INFO]: no values provided
release: redis-a@my-namespace
[🙃 aka INFO]: Building repositories...
[🙃 aka INFO]: 🗄 repo has been added to the plan
repository: bitnami
[🙃 aka INFO]: ❎ repository already exists with the same configuration, skipping
repository: bitnami
[🙃 aka INFO]: Building registries...
[🙃 aka INFO]: Building manifests...
[🙃 aka INFO]: skipping updating dependencies for remote chart
release: redis-b@my-namespace
[🙃 aka INFO]: skipping updating dependencies for remote chart
release: redis-a@my-namespace
[🙃 aka INFO]: ✅ manifest done
release: redis-a@my-namespace
[🙃 aka INFO]: ✅ manifest done
release: redis-b@my-namespace
[🙃 aka INFO]: 🏗 Plan
releases:
- redis-a@my-namespace
- redis-b@my-namespace
repositories:
- bitnami
registries:
-
[🙃 aka INFO]: 🆚 Diff manifests in the kubernetes cluster
[🙈 aka WARNING]: I cant get release from k8s: failed to get release redis-a@my-namespace: release: not found
[🙈 aka WARNING]: I cant get release from k8s: failed to get release redis-b@my-namespace: release: not found
[🙃 aka INFO]: 🏗 Planfile is ready!
deploy it with next command: helmwave up --plandir .helmwave/
3-3-4.helmwave build コマンドを実行すると .helmwave ディレクトリ配下に planfile と manifest が生成されることが確認できる
$ tree .helmwave/
.helmwave/
├── manifest
│ ├── [email protected]
│ └── [email protected]
└── planfile
1 directory, 3 files
3-3-5.いよいよ、リリース(Helm Charts のインスタンス)をデプロイ
$ helmwave up --plandir .helmwave/
[🙃 aka INFO]: 🏗 Plan
registries:
-
releases:
- redis-a@my-namespace
- redis-b@my-namespace
repositories:
- bitnami
[🙃 aka INFO]: 🗄 Sync repositories...
[🙃 aka INFO]: ❎ repository already exists with the same configuration, skipping
repository: bitnami
[🙃 aka INFO]: 🗄 Sync registries...
[🙃 aka INFO]: 🛥 Sync releases...
[🙃 aka INFO]: 🛥 deploying...
release: redis-b@my-namespace
[🙃 aka INFO]: 🛥 deploying...
release: redis-a@my-namespace
[🙃 aka INFO]: ✅
release: redis-a@my-namespace
[🙃 aka INFO]: ✅
release: redis-b@my-namespace
[🙃 aka INFO]: Success 2 / 2
3-3-6.リリース(Helm Charts のインスタンス)がデプロイできた
$ helmwave list
[🙃 aka INFO]: Should be 2 releases
NAME | NAMESPACE | REVISION | UPDATED | STATUS | CHART | VERSION
----------+--------------+----------+--------------------------------+----------+-------+----------
redis-a | my-namespace | 1 | 2022-05-13 20:23:15.966148 | deployed | redis | 16.9.3
| | | +0900 JST | | |
redis-b | my-namespace | 1 | 2022-05-13 20:23:15.966021 | deployed | redis | 16.9.3
| | | +0900 JST | | |
$ helmwave ls
[🙃 aka INFO]: Should be 2 releases
NAME | NAMESPACE | REVISION | UPDATED | STATUS | CHART | VERSION
----------+--------------+----------+--------------------------------+----------+-------+----------
redis-a | my-namespace | 1 | 2022-05-13 20:23:15.966148 | deployed | redis | 16.9.3
| | | +0900 JST | | |
redis-b | my-namespace | 1 | 2022-05-13 20:23:15.966021 | deployed | redis | 16.9.3
| | | +0900 JST | | |
$ helmwave status
[🙃 aka INFO]: General status of redis-a@my-namespace
status: deployed
revision: 1
name: redis-a
namespace: my-namespace
chart: redis-16.9.3
last deployed: 2022-05-13 20:23:15.966148 +0900 JST
[🙃 aka INFO]: General status of redis-b@my-namespace
name: redis-b
namespace: my-namespace
chart: redis-16.9.3
last deployed: 2022-05-13 20:23:15.966021 +0900 JST
status: deployed
revision: 1
3-3-7.あとかたづけ
$ helmwave down
[🙃 aka INFO]: ✅ redis-a@my-namespace uninstalled!
[🙃 aka INFO]: ✅ redis-b@my-namespace uninstalled!
$ helmwave ls
[🙃 aka INFO]: Should be 2 releases
[💩 aka ERROR]: Failed to list. Skipping.
release: redis-a@my-namespace
error: release: not found
[💩 aka ERROR]: Failed to list. Skipping.
release: redis-b@my-namespace
error: release: not found
NAME | NAMESPACE | REVISION | UPDATED | STATUS | CHART | VERSION
-------+-----------+----------+---------+--------+-------+----------
$ helmwave status
[💩 aka ERROR]: Failed to get status: failed to get status of release redis-a@my-namespace: release: not found
release: redis-a@my-namespace
[💩 aka ERROR]: Failed to get status: failed to get status of release redis-b@my-namespace: release: not found
release: redis-b@my-namespace
3-4.Helmwave をローカルで動かす上での個人的なハマりポイント
3-4-1.ローカルで helmwave build コマンドを実行したら、“failed to install “@”: context deadline exceeded” というエラーメッセージが出た
エラーログの抜粋は以下のとおり。
[🤬 aka FATAL]: one of goroutines in waitgroup sent error: 2 errors occurred:
* failed to install "redis-b@my-namespace": context deadline exceeded
* failed to install "redis-a@my-namespace": context deadline exceeded
kubectl get events コマンドでもエラーログを追うことができる
$ kubectl get ev -A --watch
# エラーログ抜粋
my-namespace 36m Warning Unhealthy pod/redis-a-replicas-2 Readiness probe errored: rpc error: code = NotFound desc = failed to exec in container: failed to find container "略" in store: not found
my-namespace 36m Warning Unhealthy pod/redis-a-replicas-2 Liveness probe errored: rpc error: code = NotFound desc = failed to exec in container: failed to find container "略" in store: not found
my-namespace 24m Normal Scheduled pod/redis-a-replicas-2 Successfully assigned my-namespace/redis-a-replicas-2 to kind-control-plane
解決策は、helmwave.yml.tpl に “wait” オプションと “timeout” オプション を書くということだった。どうも Helmwave 側で build コマンドの処理を待つ必要があるらしい。
3-4-2.helmwave build コマンドを実行したら “I cant get release from k8s: failed to get release <リリース名>: release: not found” という WARNING が出た
[🙈 aka WARNING]: I cant get release from k8s: failed to get release redis-a@my-namespace: release: not found
[🙈 aka WARNING]: I cant get release from k8s: failed to get release redis-b@my-namespace: release: not found
すでにリリースがある状態で build すると WARNING が表示されなかったので、リリースがない初回のみ表示される?
4.Helmwave を GitHub Actions 上でさわってみる
今度は Actions 上でさわってみた。使い方はローカルの場合とだいたい同じようなかんじ
name: Playground
on:
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Create k8s Kind Cluster # kind を使う必要がある
uses: helm/[email protected]
- uses: helmwave/[email protected]
name: Install helmwave
with:
version: "0.19.3"
- name: templating helmwave.yml.tpl
run: helmwave yml
- name: plan
#run: helmwave build --yml
run: helmwave build --yml --diff-mode=local
- name: deploy
run: helmwave up --plandir .helmwave/ --kubedog
4-1.Helmwave を GitHub Actions 上でさわってみた際のハマリポイント
- ハマりポイントは、kind のような Actions 上で Kubernetes リソースにアクセス できるようにするという点
- 以下のワークフローでは、
helm/[email protected]を使っている helmwave っていらないんじゃないの!?と思った。ローカルでは必要なしだったのに。Actions の環境とローカルとでは環境差分がある??- ローカルでも kind のような Kubernetes リソース を用意する必要がある
- 以下のワークフローでは、
※ helm/[email protected] を使わない場合のワークフローの実行結果のログ抜粋
[🤬 aka FATAL]: I can't check if release is installed
release: redis-b@my-namespace
error: Kubernetes cluster unreachable: Get "http://localhost:8080/version": dial tcp [::1]:8080: connect: connection refused
参考:helm/[email protected] を使わない場合のワークフローの実行結果
※ Helmwave を使って Helm Charts をデプロイする前に helm/[email protected] でクラスターを立てておくと問題なくデプロイできた。
参考:helm/[email protected] を使う場合のワークフローの実行結果
5.Helmwave を触ってみた感想
- ハマリポイントがいくつかあったが、最低限必要なことは
helmwave自体のインストールとreleases.ymlとhelmwave. yml.tplの 2 つのファイルだけというのは魅力的。とはいえ、後述するシークレットの扱いなど実運用に耐えられるだけの作り込みをするとなるとvaules-secret.yamlのようなシークレットを扱うファイルが必要など結局、、笑- 小話)
vaules-secret.yamlはvaules-secret.ymlだとファイルが読み込まれないようにみえた - シークレットの扱い方が v0.18 から v0.19 で変更が大きい。Helmwave を使う際にはどのバージョンを使っているか?また、そのバージョンのドキュメントを参照しているか?注意したほうがよさそう
- 小話)
- Helmwave を触っていくなかで、manifest の lint action を知ることができたので探求していきたい
6.更新履歴
2022/05/31
ローカルでは kind のような Helm Charts のデプロイ先としての Kubernetes クラスターを立てておく必要はないと思っていたが、それは間違いだった。むしろ、Helm Charts のデプロイ先として、kind のような Kubernetes クラスターを立てておく必要があった。
したがって、4-1.Helmwave を GitHub Actions 上でさわってみた際のハマリポイント にて、ローカルでも kind のような Kubernetes リソース を用意する必要がある であると更新した。
7.参考資料
- Helmwave のコマンドの使い方は、公式ドキュメントの cli リファレンスのページが参考になった
- Helmwave を Actions 上で実行したときのログ
- template with isInstalled FATAL · Issue #146 · helmwave/helmwave