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を利用すると、両方まとめてインストールすることができます。

$ brew install helmfile
...
(中略)
...
==> Installing dependencies for helmfile: helm
==> Installing helmfile dependency: helm
==> Pouring helm-3.4.1.catalina.bottle.tar.gz
==> Caveats
Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completions have been installed to:
  /usr/local/share/zsh/site-functions
==> Summary
🍺  /usr/local/Cellar/helm/3.4.1: 57 files, 42.3MB
==> Installing helmfile
==> Pouring helmfile-0.135.0.catalina.bottle.tar.gz
🍺  /usr/local/Cellar/helmfile/0.135.0: 5 files, 43.4MB
==> Caveats
==> helm
Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

zsh completions have been installed to:
  /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としてインストールしています。

helm repo add flagger https://flagger.app

helm upgrade --install --wait frontend \
--namespace test \
--set replicaCount=2 \
--set backend=http://backend-podinfo:9898/echo \
flagger/podinfo

helm upgrade --install --wait backend \
--namespace test \
--set hpa.enabled=true \
flagger/podinfo

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

repositories:
- name: flagger
  url: https://flagger.app

releases:
- name: frontend
  namespace: test
  chart: flagger/podinfo
  values:
  - replicaCount: 2
    backend: http://backend-podinfo:9898/echo
- name: backend
  namespace: test
  chart: flagger/podinfo
  values:
  - hpa:
      enabled: true

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

helmfile apply

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

Adding repo flagger https://flagger.app
"flagger" has been added to your repositories

Comparing release=frontend, chart=flagger/podinfo
Comparing release=backend, chart=flagger/podinfo
********************

	Release was not present in Helm.  Diff will show entire contents as new.

********************
test, backend-podinfo, ConfigMap (v1) has been added:
-
+ # Source: podinfo/templates/configmap.yaml
+ apiVersion: v1
+ kind: ConfigMap
+ metadata:
+   name: backend-podinfo
+   labels:
+     app: podinfo
+     chart: podinfo-5.0.0
+     release: backend
+     heritage: Helm
+ data:
+   config.yaml: |-
+     # http settings
+     http-client-timeout: 1m
+     http-server-timeout: 30s
+     http-server-shutdown-timeout: 5s
test, backend-podinfo, Deployment (apps) has been added:
-
+ # Source: podinfo/templates/deployment.yaml
+ apiVersion: apps/v1
+ kind: Deployment
...
中略
...
+       name: http
+   selector:
+     app: frontend-podinfo

Upgrading release=frontend, chart=flagger/podinfo
Upgrading release=backend, chart=flagger/podinfo
Release "backend" does not exist. Installing it now.
NAME: backend
LAST DEPLOYED: Sun Nov 29 08:39:42 2020
NAMESPACE: test
STATUS: deployed
REVISION: 1
NOTES:
podinfo backend deployed!

Listing releases matching ^backend$
Release "frontend" does not exist. Installing it now.
NAME: frontend
LAST DEPLOYED: Sun Nov 29 08:39:42 2020
NAMESPACE: test
STATUS: deployed
REVISION: 1
NOTES:
podinfo frontend deployed!

Listing releases matching ^frontend$
frontend	test     	1       	2020-11-29 08:39:42.663356 +0900 JST	deployed	podinfo-5.0.0	5.0.0

backend	test     	1       	2020-11-29 08:39:42.668443 +0900 JST	deployed	podinfo-5.0.0	5.0.0

UPDATED RELEASES:
NAME       CHART             VERSION
backend    flagger/podinfo     5.0.0
frontend   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の入力とすることができます。

$ helmfile template --include-crds > all.yaml

$ kubeval all.yaml

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

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

- name: argocd
  chart: argo/argo-cd
  values:
  - global:
      # See https://hub.docker.com/r/chatwork/argocd-helmfile
      image:
        repository: chatwork/argocd-helmfile
        tag: latest
      # See https://github.com/argoproj/argo-helm/blob/master/charts/argo-cd/values.yaml#L521-L523
      config:
        # See https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/argocd-cm.yaml#L214
        configManagementPlugins: |
          - name: helmfile
            init:
              command: ["/bin/sh", "-c"]
              # ARGOCD_APP_NAMESPACE is one of the standard envvars
              # See https://argoproj.github.io/argo-cd/user-guide/build-environment/
              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"]
            generate:
              command: ["/bin/sh", "-c"]
              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であれば以下のような設定を記述するだけで済みます。

releases:
#
# CRDの例: ./crds/*.yaml にCRDのマニフェストが保存されている場合
#
- name: crds
  chart: ./crds
#
# ミドルウェアの例: fluentd は Chart でインストール
#
- name: fluentd
  chart: stable/fluentd
#
# アプリケーションの例: web アプリは kustomize でインストール
#
- name: myapp
  # path/to/kustomiation/kustomization.yaml の親ディレクトリを chart に指定すると、
  # それを Chart に自動変換する…という仕様になっています
  chart: ./path/to/kustomization

もうひとつの機能は「Chartをインストール前に修正する」ものです。kustomizeには入力となったマニフェストに一定の変更を加える(例えば、特定のラベルを全リソースに付与する)機能がありますが、helmにはその機能はありません(Chart側でそのような設定をサポートする必要があります)。

Helmfileを利用すると、Chartをkustomizeで修正後にインストールできるようになります。

仮に、先ほど紹介したpodinfoのインストール前にteam=myteamというラベルとargocd.argoproj.io/sync-wave=5というアノテーションを付与する場合は、以下のように記述してhelmfile applyhelmfile templateを実行するだけです。

releases:
- name: podinfo
  chart: flagger/podinfo
  transformers:
  - apiVersion: builtin
    kind: AnnotationsTransformer
    metadata:
      name: notImportantHere
    annotations:
      argocd.argoproj.io/sync-wave: "5"
    fieldSpecs:
    - path: metadata/annotations
      create: true
  - apiVersion: builtin
    kind: LabelTransformer
    metadata:
      name: notImportantHere
    labels:
      team: "myteam"
    fieldSpecs:
    - path: metadata/labels
      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コマンド一発に集約できます。

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

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

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

resource "helmfile_release_set" "mystack" {
    content = file("./helmfile.yaml")
    version = "0.135.0"
    helm_version = "3.4.1"
}

おわりに

今回は、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メルマガ会員のサービス内容を見る

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