HelmfileでKubernetesマニフェストやKustomization、Helm Chartなどで構成されるアプリケーションを効率的に管理する

2020年12月22日(火)
九岡 佑介(くおか・ゆうすけ)

はじめに

みなさんは、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
02...
03(中略)
04...
05==> Installing dependencies for helmfile: helm
06==> Installing helmfile dependency: helm
07==> Pouring helm-3.4.1.catalina.bottle.tar.gz
08==> Caveats
09Bash completion has been installed to:
10  /usr/local/etc/bash_completion.d
11 
12zsh completions have been installed to:
13  /usr/local/share/zsh/site-functions
14==> Summary
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
19==> Caveats
20==> helm
21Bash completion has been installed to:
22  /usr/local/etc/bash_completion.d
23 
24zsh 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はアプリケーションがまだクラスタに存在しない場合はインストールし、そうでなければアップデートします。一方、templateapplyによりインストールされる全Kubernetesリソースのマニフェストを出力します。

helmfile applyの実行例

それでは、helmfile applyを試してみましょう。ここでは参考のため、helmを使ってpodinfofrontendおよびbackendの2つのReleaseとしてインストールする例で説明します。

Helmfileを利用しない場合は、以下のような手順になります。今回インストールしたいのはflaggerというChart RegistryからダウンロードできるpodinfoというChartで、それぞれfrontendbackendという名前を持つReleaseとしてインストールしています。

01helm repo add flagger https://flagger.app
02 
03helm upgrade --install --wait frontend \
04--namespace test \
05--set replicaCount=2 \
07flagger/podinfo
08 
09helm upgrade --install --wait backend \
10--namespace test \
11--set hpa.enabled=true \
12flagger/podinfo

Helmfileを利用する場合は、まず以下のようなhelmfile.yamlを作成します。

01repositories:
02- name: flagger
04 
05releases:
06- name: frontend
07  namespace: test
08  chart: flagger/podinfo
09  values:
10  - replicaCount: 2
12- name: backend
13  namespace: test
14  chart: flagger/podinfo
15  values:
16  - hpa:
17      enabled: true

helmfile applyを実行すると、helmfile.yamlの内容に従って2つのReleaseが作成されます。

1helmfile apply

applyを実行すると、以下のようなログが出力されます。

01Adding repo flagger https://flagger.app
02"flagger" has been added to your repositories
03 
04Comparing release=frontend, chart=flagger/podinfo
05Comparing release=backend, chart=flagger/podinfo
06********************
07 
08    Release was not present in Helm.  Diff will show entire contents as new.
09 
10********************
11test, backend-podinfo, ConfigMap (v1) has been added:
12-
13+ # Source: podinfo/templates/configmap.yaml
14+ apiVersion: v1
15+ kind: ConfigMap
16+ metadata:
17+   name: backend-podinfo
18+   labels:
19+     app: podinfo
20+     chart: podinfo-5.0.0
21+     release: backend
22+     heritage: Helm
23+ data:
24+   config.yaml: |-
25+     # http settings
26+     http-client-timeout: 1m
27+     http-server-timeout: 30s
28+     http-server-shutdown-timeout: 5s
29test, backend-podinfo, Deployment (apps) has been added:
30-
31+ # Source: podinfo/templates/deployment.yaml
32+ apiVersion: apps/v1
33+ kind: Deployment
34...
35中略
36...
37+       name: http
38+   selector:
39+     app: frontend-podinfo
40 
41Upgrading release=frontend, chart=flagger/podinfo
42Upgrading release=backend, chart=flagger/podinfo
43Release "backend" does not exist. Installing it now.
44NAME: backend
45LAST DEPLOYED: Sun Nov 29 08:39:42 2020
46NAMESPACE: test
47STATUS: deployed
48REVISION: 1
49NOTES:
50podinfo backend deployed!
51 
52Listing releases matching ^backend$
53Release "frontend" does not exist. Installing it now.
54NAME: frontend
55LAST DEPLOYED: Sun Nov 29 08:39:42 2020
56NAMESPACE: test
57STATUS: deployed
58REVISION: 1
59NOTES:
60podinfo frontend deployed!
61 
62Listing releases matching ^frontend$
63frontend    test        1           2020-11-29 08:39:42.663356 +0900 JST    deployed    podinfo-5.0.0   5.0.0
64 
65backend test        1           2020-11-29 08:39:42.668443 +0900 JST    deployed    podinfo-5.0.0   5.0.0
66 
67UPDATED RELEASES:
68NAME       CHART             VERSION
69backend    flagger/podinfo     5.0.0
70frontend   flagger/podinfo     5.0.0

最初にAdding repo flagger $URLで利用するChart Repositoryを登録し、次にComparing release=$NAMEchart=$CHARTで対象のReleaseへの更新内容を決定するために差分チェックを行っています。

最後にUpgrading release=$NAMEchart=$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
2 
3$ kubeval all.yaml

ArgoCDと組み合わせる場合は、ArgoCDのConfig Management Pluginという機能からhelmfile templateを呼び出すと良いでしょう。

例として、ArgoCD自体もHelmfileでインストールする場合は、以下のようなhelmfile.yamlで必要なConfig Management Pluginの設定が可能です。

01- name: argocd
02  chart: argo/argo-cd
03  values:
04  - global:
06      image:
07        repository: chatwork/argocd-helmfile
08        tag: latest
10      config:
12        configManagementPlugins: |
13          - name: helmfile
14            init:
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"]
19            generate:
20              command: ["/bin/sh", "-c"]
21              args: ["cat manifests.yaml"]

Config Management Pluginについての詳細は、ArgoCDの公式ドキュメントを参照してください。

Helmfileの便利機能

Helmfileには、シェルスクリプト等で気軽に実装することが難しいような便利な機能もいくつか用意されています。

kubectlhelmkustomizeのいずれを使うにしても、単一のツールではできないことをカバーするために、頑張ってシェルスクリプトやCIの設定ファイルでラップする…ということは現実的によくあることだと思います。

基本的に、Helmfileはこれらのツールを補完することをゴールにしているため、他のツールには見られない便利な機能が用意されていることがあります。

筆者の独断と偏見でピックアップすると、以下の機能がおススメです。

  • Kustomize統合(#Kustomize-統合)
  • Terraformサポート(#Terraform-サポート)

Kustomize統合

Kustomize統合には大きく2つの機能があります。ひとつは「Helmfileを使っ Helm Chart以外のものをデプロイする」ものです。kustomizeでは難しいような動的な設定を記述したり、マニフェストをChartに書き直したり、その逆を行ったりする必要はなく、すべてをHelmfileでひとまとめにデプロイできます。

例えば、特定のCRDのみHelmを使わず、ただのマニフェストで管理し、ミドルウェア類はHelm Chart、自社アプリケーションはKustomizeで管理したい、というような複雑な(しかし経験上はよくある)要件があったとしても、Helmfileであれば以下のような設定を記述するだけで済みます。

01releases:
02#
03# CRDの例: ./crds/*.yaml にCRDのマニフェストが保存されている場合
04#
05- name: crds
06  chart: ./crds
07#
08# ミドルウェアの例: fluentd は Chart でインストール
09#
10- name: fluentd
11  chart: stable/fluentd
12#
13# アプリケーションの例: web アプリは kustomize でインストール
14#
15- name: myapp
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 applyhelmfile templateを実行するだけです。

01releases:
02- name: podinfo
03  chart: flagger/podinfo
04  transformers:
05  - apiVersion: builtin
06    kind: AnnotationsTransformer
07    metadata:
08      name: notImportantHere
09    annotations:
10      argocd.argoproj.io/sync-wave: "5"
11    fieldSpecs:
12    - path: metadata/annotations
13      create: true
14  - apiVersion: builtin
15    kind: LabelTransformer
16    metadata:
17      name: notImportantHere
18    labels:
19      team: "myteam"
20    fieldSpecs:
21    - path: metadata/labels
22      create: true

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コマンド一発に集約できます。

1resource "helmfile_release_set" "mystack" {
2    content = file("./helmfile.yaml")
3}

terraform-provider-helmfileの便利な機能のひとつに「バイナリのバージョン管理」があります。CI上でHelmfileやHelmなどを実行する場合、CIパイプラインで使う仮想マシンイメージやコンテナイメージに含まれるHelmfileやHelmを定期的にアップデートする運用がどうしても発生してしまいますが、本機能を使うとTerraformの設定ファイルを数行変更するだけで済みます。

例えば、Helmfile 0.135.0とHelm 3.4.1を使って前述のmystackをデプロイする場合は、以下のようにversionhelm_versionをTerraformの設定ファイルに記述します。

1resource "helmfile_release_set" "mystack" {
2    content = file("./helmfile.yaml")
3    version = "0.135.0"
4    helm_version = "3.4.1"
5}

おわりに

今回は、Helmfileを使ってKubernetesマニフェスト、Kustomization、Helm Chartなどから構成されるアプリケーション一式を効率的に管理する方法を紹介しました。

皆さんの環境でもKubernetesへのデプロイパイプラインが複雑化していたり、スクリプトの保守が難しくなってきたり、といった問題が起きていたら、ぜひHelmfileを試してみてください。

著者
九岡 佑介(くおか・ゆうすけ)
ゼットラボ株式会社
AWS Container Hero。本業はゼットラボ株式会社でKubernetes as a Serviceの研究開発。副業として数社でAWSやコンテナ、Kubernetesを活用するためのサポートも。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています