はじめに
みなさんは、Kubernetesクラスタへアプリケーションやミドルウェアをインストールする際に、どのような方法で行っていますか?
Kubernetesには「kubectl」という公式のコマンドツールがあります。YAMLでKubernetesリソースの定義を書き、それをkubectl applyコマンドでインストールしている、という方も多いかと思います。
また、kubectlにも統合されている「Kustomize」や、Kubernetes向けパッケージマネージャの「Helm」を使っているという方もいらっしゃるでしょう。
今回は、これらのツールでは賄いきれないほどの複雑な環境へのデプロイに便利な「Helmfile」というツールを紹介します。
今回の対象読者
今回の内容は「著名なツールを選択したが、そのツールを実行するまでの手順やスクリプトが煩雑」という課題を抱えている方には、ぜひ本記事を通してHelmfileを試してみていただきたいと思います。
Helmfileは、公開情報からわかる範囲でも2018年4月~2020年12月現在までに16の企業・組織の本番環境で使われてきた実績のあるツールです。なお、ユーザー事例に関する詳細は、公式ドキュメントの「USERS」を参照してください。
特にツールについて課題や移行のモチベーションがない状態でも、他社の本番環境におけるKubernetesへのデプロイがどのように行われているかを参考にするきっかけとしても、本記事を活用いただけるとうれしいです。
Helmfile のインストール
それでは早速、Helmfileを試してみましょう。Helmfileを利用するにあたって、まずは最低限HelmfileとHelm 3をインストールする必要があります。
macOS の場合はHomebrewを利用すると、両方まとめてインストールすることができます。
01 | $ brew install helmfile |
05 | ==> Installing dependencies for helmfile: helm |
06 | ==> Installing helmfile dependency: helm |
07 | ==> Pouring helm-3.4.1.catalina.bottle.tar.gz |
09 | Bash completion has been installed to: |
10 | /usr/local/etc/bash_completion.d |
12 | zsh completions have been installed to: |
13 | /usr/local/share/zsh/site-functions |
15 | 🍺 /usr/local/Cellar/helm/3.4.1: 57 files, 42.3MB |
16 | ==> Installing helmfile |
17 | ==> Pouring helmfile-0.135.0.catalina.bottle.tar.gz |
18 | 🍺 /usr/local/Cellar/helmfile/0.135.0: 5 files, 43.4MB |
21 | Bash completion has been installed to: |
22 | /usr/local/etc/bash_completion.d |
24 | zsh completions have been installed to: |
25 | /usr/local/share/zsh/site-functions |
Helmfileの基本的な使い方
Helmfileは基本的にhelmfile.yaml
というYAMLファイルにHelmfileが定める仕様に沿って「アプリケーション郡の期待状態(Desired State)」を記述し、目的に応じたHelmfileのコマンドを実行するという2ステップで利用します。
2020年12月時点で、Helmfileには17のコマンドが存在しますが、代表的なものは以下の2つです。
helmfile apply
helmfile template
apply
はアプリケーションがまだクラスタに存在しない場合はインストールし、そうでなければアップデートします。一方、template
はapply
によりインストールされる全Kubernetesリソースのマニフェストを出力します。
helmfile applyの実行例
それでは、helmfile apply
を試してみましょう。ここでは参考のため、helm
を使ってpodinfoをfrontend
およびbackend
の2つのReleaseとしてインストールする例で説明します。
Helmfileを利用しない場合は、以下のような手順になります。今回インストールしたいのはflagger
というChart Registryからダウンロードできるpodinfo
というChartで、それぞれfrontend
とbackend
という名前を持つReleaseとしてインストールしています。
03 | helm upgrade --install --wait frontend \ |
09 | helm upgrade --install --wait backend \ |
11 | --set hpa.enabled=true \ |
Helmfileを利用する場合は、まず以下のようなhelmfile.yaml
を作成します。
08 | chart: flagger/podinfo |
14 | chart: flagger/podinfo |
helmfile apply
を実行すると、helmfile.yaml
の内容に従って2つのReleaseが作成されます。
apply
を実行すると、以下のようなログが出力されます。
02 | "flagger" has been added to your repositories |
04 | Comparing release=frontend, chart=flagger/podinfo |
05 | Comparing release=backend, chart=flagger/podinfo |
08 | Release was not present in Helm. Diff will show entire contents as new. |
11 | test, backend-podinfo, ConfigMap (v1) has been added: |
13 | + # Source: podinfo/templates/configmap.yaml |
17 | + name: backend-podinfo |
26 | + http-client-timeout: 1m |
27 | + http-server-timeout: 30s |
28 | + http-server-shutdown-timeout: 5s |
29 | test, backend-podinfo, Deployment (apps) has been added: |
31 | + # Source: podinfo/templates/deployment.yaml |
39 | + app: frontend-podinfo |
41 | Upgrading release=frontend, chart=flagger/podinfo |
42 | Upgrading release=backend, chart=flagger/podinfo |
43 | Release "backend" does not exist. Installing it now. |
45 | LAST DEPLOYED: Sun Nov 29 08:39:42 2020 |
50 | podinfo backend deployed! |
52 | Listing releases matching ^backend$ |
53 | Release "frontend" does not exist. Installing it now. |
55 | LAST DEPLOYED: Sun Nov 29 08:39:42 2020 |
60 | podinfo frontend deployed! |
62 | Listing releases matching ^frontend$ |
63 | frontend test 1 2020-11-29 08:39:42.663356 +0900 JST deployed podinfo-5.0.0 5.0.0 |
65 | backend test 1 2020-11-29 08:39:42.668443 +0900 JST deployed podinfo-5.0.0 5.0.0 |
69 | backend flagger/podinfo 5.0.0 |
70 | frontend flagger/podinfo 5.0.0 |
最初にAdding repo flagger $URL
で利用するChart Repositoryを登録し、次にComparing release=$NAME
、chart=$CHART
で対象のReleaseへの更新内容を決定するために差分チェックを行っています。
最後にUpgrading release=$NAME
、chart=$CHART
が出力されているタイミングでhelm upgrade --install
コマンドが実行され、対象Releaseが作成・更新されています。
helmfile templateの実行例
helmfile apply
を実行すると、ミドルウェアやアプリケーション一式をまとめてインストール・更新可能なことがわかりました。このコマンドは筆者としても便利だと感じていて、本番環境へのデプロイをこのコマンドで行っている組織もまた多いようです。
しかし、要件によってはhelmfile apply
が適さないこともあります。例えば「デプロイ前にkubeeval
などでマニフェストの正しさを検証したい」といった場合、kubeeval
の入力はhelmfile.yaml
ではなくKubernetesマニフェストであるため困ります。
またArgoCDでGitOpsを実装したいという場合、ArgoCDがサポートする入力はKubernetesマニフェスト、kustomize、Helm Chartの3つしかなく、こちらもhelmfile.yaml
はサポートしていないため、一見すると対応できないように思えます。
これらの理由でKubernetesマニフェストが必要な場合はhelmfile template
を利用すると良いでしょう。helmfile template
は、インストール対象の全マニフェストを標準出力等に書き出すコマンドです。
kubeeval
と組み合わせる場合は、helmfile template
の結果を以下のようにkubeeval
の入力とすることができます。
1 | $ helmfile template --include-crds > all.yaml |
ArgoCDと組み合わせる場合は、ArgoCDのConfig Management Pluginという機能からhelmfile template
を呼び出すと良いでしょう。
例として、ArgoCD自体もHelmfileでインストールする場合は、以下のようなhelmfile.yaml
で必要なConfig Management Pluginの設定が可能です。
07 | repository: chatwork/argocd-helmfile |
12 | configManagementPlugins: | |
15 | command: ["/bin/sh", "-c"] |
16 | # ARGOCD_APP_NAMESPACE is one of the standard envvars |
18 | args: ["helmfile --state-values-set ns=$ARGOCD_APP_NAMESPACE -f helmfile.yaml template --include-crds | sed -e '1,/---/d' | sed -e '/WARNING: This chart is deprecated/d' | sed -e 's|apiregistration.k8s.io/v1beta1|apiregistration.k8s.io/v1|g' > manifests.yaml"] |
20 | command: ["/bin/sh", "-c"] |
21 | args: ["cat manifests.yaml"] |
Config Management Pluginについての詳細は、ArgoCDの公式ドキュメントを参照してください。
Helmfileの便利機能
Helmfileには、シェルスクリプト等で気軽に実装することが難しいような便利な機能もいくつか用意されています。
kubectl
、helm
、kustomize
のいずれを使うにしても、単一のツールではできないことをカバーするために、頑張ってシェルスクリプトやCIの設定ファイルでラップする…ということは現実的によくあることだと思います。
基本的に、Helmfileはこれらのツールを補完することをゴールにしているため、他のツールには見られない便利な機能が用意されていることがあります。
筆者の独断と偏見でピックアップすると、以下の機能がおススメです。
- Kustomize統合(#Kustomize-統合)
- Terraformサポート(#Terraform-サポート)
Kustomize統合
Kustomize統合には大きく2つの機能があります。ひとつは「Helmfileを使っ Helm Chart以外のものをデプロイする」ものです。kustomizeでは難しいような動的な設定を記述したり、マニフェストをChartに書き直したり、その逆を行ったりする必要はなく、すべてをHelmfileでひとまとめにデプロイできます。
例えば、特定のCRDのみHelmを使わず、ただのマニフェストで管理し、ミドルウェア類はHelm Chart、自社アプリケーションはKustomizeで管理したい、というような複雑な(しかし経験上はよくある)要件があったとしても、Helmfileであれば以下のような設定を記述するだけで済みます。
03 | # CRDの例: ./crds/*.yaml にCRDのマニフェストが保存されている場合 |
08 | # ミドルウェアの例: fluentd は Chart でインストール |
13 | # アプリケーションの例: web アプリは kustomize でインストール |
16 | # path/to/kustomiation/kustomization.yaml の親ディレクトリを chart に指定すると、 |
17 | # それを Chart に自動変換する…という仕様になっています |
18 | chart: ./path/to/kustomization |
もうひとつの機能は「Chartをインストール前に修正する」ものです。kustomizeには入力となったマニフェストに一定の変更を加える(例えば、特定のラベルを全リソースに付与する)機能がありますが、helmにはその機能はありません(Chart側でそのような設定をサポートする必要があります)。
Helmfileを利用すると、Chartをkustomizeで修正後にインストールできるようになります。
仮に、先ほど紹介したpodinfo
のインストール前にteam=myteam
というラベルとargocd.argoproj.io/sync-wave=5
というアノテーションを付与する場合は、以下のように記述してhelmfile apply
やhelmfile template
を実行するだけです。
03 | chart: flagger/podinfo |
06 | kind: AnnotationsTransformer |
08 | name: notImportantHere |
10 | argocd.argoproj.io/sync-wave: "5" |
12 | - path: metadata/annotations |
15 | kind: LabelTransformer |
17 | name: notImportantHere |
21 | - path: metadata/labels |
Helm Chart側で「--set labels[0]="foo=bar"のChart Value経由でラベルを付与する」といった機能がサポートされていれば良いのですが、このような機能はHelm / Chartのどちらでも標準化されていないためあまり期待はできず、経験上もそのような機能がないChartは多く存在します。
Helm Chartをフォーク、機能追加した上で本家に取り込んでもらったり、もしくは独自に保守していくという選択肢もありますが、そこまで手間をかけたくないという場合は、このKustomize連携機能が役立つと思います。
Terraformサポート
AWSリソースなどを含むインフラの管理にTerraform
を使っており、Terraform
で構築したKubernetesクラスタに別途kubectl
等でアプリケーションをインストールしている、という方はいますか?
HelmfileのTerraformサポートを利用すると、その2ステップを集約できるかもしれません。具体的には、terraform-provider-helmfileというTerraformカスタムプロバイダを利用するとTerraformからHelmfileを実行できます。
例えば、以下のようなtfファイルを記述すると、Kubernetesクラスタを構築後にHelmfileでアプリケーション一式をインストール、という一連の手順やスクリプトはterraform apply
コマンド一発に集約できます。
1 | resource "helmfile_release_set" "mystack" { |
2 | content = file("./helmfile.yaml") |
terraform-provider-helmfileの便利な機能のひとつに「バイナリのバージョン管理」があります。CI上でHelmfileやHelmなどを実行する場合、CIパイプラインで使う仮想マシンイメージやコンテナイメージに含まれるHelmfileやHelmを定期的にアップデートする運用がどうしても発生してしまいますが、本機能を使うとTerraformの設定ファイルを数行変更するだけで済みます。
例えば、Helmfile 0.135.0とHelm 3.4.1を使って前述のmystack
をデプロイする場合は、以下のようにversion
とhelm_version
をTerraformの設定ファイルに記述します。
1 | resource "helmfile_release_set" "mystack" { |
2 | content = file("./helmfile.yaml") |
おわりに
今回は、Helmfileを使ってKubernetesマニフェスト、Kustomization、Helm Chartなどから構成されるアプリケーション一式を効率的に管理する方法を紹介しました。
皆さんの環境でもKubernetesへのデプロイパイプラインが複雑化していたり、スクリプトの保守が難しくなってきたり、といった問題が起きていたら、ぜひHelmfileを試してみてください。