helmfileの構成と利用について
2024-09-16
#目次
#はじめに
今回は、 helmfileの構成と利用について紹介します。
helmfileの構成はどのようにするのが良いでしょうか。
helmfileの公式サイトにベストプラクティスの例がありますが、いろんな書き方ができてしまうため、悩みどころでした。
いくつかのプロジェクトでhelmfileを使ってきた経験から、公式のベストプラクティスを参考に、より使いやすい構成を考えてみました。
また、よく利用するhelmfileの機能についても説明します。
#helmとは
Helm は、Kubernetes アプリケーションの管理を支援します。Helm チャートは、最も複雑な Kubernetes アプリケーションの定義、インストール、およびアップグレードを支援します。
チャートは簡単に作成、バージョン管理、共有、公開できるので、Helm の使用を開始し、コピー & ペーストはやめましょう。
Helm は CNCF の Graduated プロジェクトであり、 Helm コミュニティによって管理されています。
出典:Helm
公式サイトの説明の通りですが、Kubernetesを使う上で、helmは非常に便利なツールです。
helmのチャートは、公開されているものが多く、Artifact Hubなどで検索することができます。
postgres, redis, nginx, prometheus, grafanaなど、よく使うアプリケーションのチャートが公開されているため、自分でマニフェストを一から用意する必要がありませんので、非常に便利です。
helmをこれから使い始めようという方は、さくらインターネットさんの以下の記事が参考になります。
事実上の標準ツールとなっているKubernetes向けデプロイツール「Helm」入門 | さくらのナレッジ
#helmfileとは
Helmfile is a declarative spec for deploying helm charts. It lets you...
- Keep a directory of chart value files and maintain changes in version control.
- Apply CI/CD to configuration changes.
- Periodically sync to avoid skew in environments.
To avoid upgrades for each iteration of helm, the helmfile executable delegates to helm - as a result, helm must be installed.
公式の説明では、helmfileはhelm chartをデプロイするためのdeclarative spec
であると説明されています。
declarative spec
というのを、日本語でどう訳すかは難しいですが、helmではどのバージョンのチャートを使うか、どのようなvaluesを指定するかなど、細かく指定していく必要があります。helmfileでは、それらをファイルに宣言して、helmfileコマンドでデプロイすることができます。terraformでも宣言的という言葉が使われますが、terraformがインフラを宣言するのに対して、helm,helmfileはk8sのリソースを宣言するという風に捉えると理解しやすいかもしれません。
helmfileで宣言した情報はファイルに保存できるので、バージョン管理がしやすく、CI/CDにも適しています。Gitで管理して、チームのメンバーと共有することができます。
また、開発環境や本番環境など、環境ごとに異なるvaluesを指定したい場合にも、helmfileは有効です。
#なぜhelmを使うのか
- 公開されているhelm chartを使いたい
- secretの管理が楽
- マニフェストをapplyする前に差分チェックしたい
#なぜhelmfileを使うのか
- k8s全体のリソースを宣言的に管理したい
- 環境ごとに異なる設定を管理するため
- kubeContextの切り替え
- values, secretsの切り替え
- secret keyの切り替え
- values, secretsからテンプレートを使って最終的なvaluesを生成する
似たようなツールに、kustomizeがあります。kustomizeは、主にk8sのマニフェストを管理するためのツールですが、helm chartは扱えません。kustomizeを以前のプロジェクトで使っていましたが、CRDのリソースを扱うのが難しかったり、helm chartは別で管理する必要があり、課題がありました。
ただ、kustomizeは、オーバーレイしてマニフェストを上書きしていくので、helmのようなテンプレートよりは理解・習得しやすいように思います。
#helmfileの構成
それでは、helmfileの構成について説明します。
いくつか要件があります。
- できるだけDRY(Don't Repeat Yourself)にしたい
- values, secretsを環境ごとに分けられる
- values, secretsを1箇所にまとめて見通しを良くしたい
- values, secretsを相対パスで管理したい
以下のような構成にしました。後述にて、各ファイルの説明をします。
├── charts
│ └── <your app>
├── bases.yaml
├── environments.yaml
├── templates.yaml
├── helmfile.yaml
└── releases
└── <your app>
├── config
│ ├── default-secrets.yaml
│ ├── default-values.yaml
│ ├── stage-secrets.yaml
│ ├── stage-values.yaml
│ ├── prod-secrets.yaml
│ ├── prod-values.yaml
│ └── values.yaml.gotmpl
└── helmfile.yaml
<your app>
は、placeholderです。適宜変更してください。
#各ファイルの説明
-
charts/
自分で作るhelm chartを管理するディレクトリです。
以下のコマンドでhelmのchartを作成します。
helm create <your app>
- bases.yaml
bases:
- ../../environments.yaml
- ../../templates.yaml
basesでは、environments.yamlとtemplates.yamlを読み込むようにしています。
これらは、すべてのリリースで共通の設定です。
./releases/**/helmfile.yaml
から読み込むため、相対パスであることに注意してください。
- environments.yaml
環境ごとの定義を記述します。
environments:
default:
kubeContext: default
stage:
kubeContext: stage-ctx
prod:
kubeContext: prod-ctx
---
environments:
{{ .Environment.Name }}:
kubeContext: "{{ .Environment.KubeContext }}"
missingFileHandler: Debug
secrets:
- ./config/{{ .Environment.Name }}-secrets.yaml
values:
- ./config/{{ .Environment.Name }}-values.yaml
この記述はenvironments
が複数あり、少し奇妙に見えるかもしれませんが、yamlを---
で分割しているため、それぞれ別々のyamlとして読み込まれます。
helmfileは複数のyamlを段階的に読み込むので、最初のenvironments
を読み込んだ後、次のenvironments
を読み込んでいます。
そのため、後続では、Environment.Name
などを参照可能となり、environments
の上書きをしています。
この動作は、helmfileを実行するときに、--debug
をつけるとどのようにyamlが階層化して読み込まれているか理解できると思います。
この程度であれば、ベタ書きで環境ごとに定義しても良いかもしれませんが、helmfile のベストプラクティスガイドで指摘されているように、できるだけDRY(Don't Repeat Yourself)にすることが望ましいです。繰り返しの記述が増えると、書き損じなどによってミスが発生しやすくなります。
values, secretsの指定は、./config
から始まっていますが、これは./releases/**/helmfile.yaml
からの相対パスであることに注意してください。
- helmfile.yaml
bases:
- ./environments.yaml
- ./templates.yaml
---
helmfiles:
- ./releases/**/helmfile.yaml
このhelmfile.yamlはエントリーポイントとなるファイルです。
helmfileで-f
オプションをつけずに実行すると、このファイルが読み込まれます。
helmfiles
でglobパターンを指定しているので、すべてのhelmfile.yamlが読み込まれます。
- templates.yaml
templates:
default:
# This prevents helmfile exiting when it encounters a missing file
# Valid values are "Error", "Warn", "Info", "Debug". The default is "Error"
# Use "Debug" to make missing files errors invisible at the default log level(--log-level=INFO)
missingFileHandler: Debug
valuesTemplate:
- ./config/values.yaml.gotmpl
default
テンプレートを定義します。
- releases/
k8sにインストールするリリースを管理するディレクトリです。
- releases/
/helmfile.yaml
{{ readFile "../../bases.yaml" }}
---
releases:
- name: <your app>
chart: ../../charts/<your app>
namespace: <your namespace>
version: 0.1.0
inherit:
- template: default
readFileを使って、bases.yamlを読み込んでいます。
また、defaultのテンプレートを継承することでテンプレートが実行されるようになります。
- releases/<your app>/config
values, secretsを管理するディレクトリです。
-
{{環境名}}-secrets.yaml
環境ごとの秘密情報を記述します。たとえば、DBのパスワードなどです。
helm secrets encrypt
で暗号化して管理します。 -
{{環境名}}-values.yaml
環境ごとのvaluesを記述します。
-
values.yaml.gotmpl
valuesをテンプレートとして記述します。
{{環境名}}-secrets.yaml
,{{環境名}}-values.yaml
を入力として、valuesを生成します。
ここで生成されたvaluesとchartのvaluesがマージされて、最終的なvaluesが生成されます。
#helmfileの主な利用方法
#helmfileのインストール
asdfまたは、miseをつかってhelmfileをインストールします。
.tool-versions
に以下のように記述しておくと、プロジェクトごとにhelmfileのバージョンを固定できます。また、周辺のツールも同様にインストールしておくと良いでしょう。
- .tool-versions
helm 3.14
helmfile 0.164.0
sops 3.8.1
age 1.1.1
kubectl 1.28
kubectx 0.9
k9s 0.27
jq 1.7.1
direnv 2.34.0
miseを使ってインストールします。
mise install
#helmfileの初期化
初期化するとhelm plugin(diff, secrets, etc...)がインストールされます。
helmfile init
#helmfileの実行
- 差分チェック
helmfile diff
- 同期
helmfile sync
syncを実行すると、helmfile.yamlに記述されているリソース全てが同期されます。後述のapplyとは異なり、差分の有無をチェックしません。
たいていの場合は、applyを使うことが多いです。
syncを利用するシーンとしては、CRDを使ったリソースを作成するときなど、applyだとCRDが存在しないとエラーになるため、syncを使います。
具体的には、kube-prometheus-stack
では初回にsyncを使います。
- Apply
差分を検出して、差分のある部分だけを適用します。
helmfile apply
- リリースの削除
helmfile destroy
個別のリリースを指定して実行することもできます。
helmfile -f releases/<your app>/helmfile.yaml destroy
- 環境を指定する
環境を指定して実行することもできます。未指定だとdefault
が適用されます。
helmfile -e prod apply
- build
build
は、helmfileのテンプレートで生成されるhelmに渡す前の情報が出力されます。
主にデバッグ用途で使います。意図したvaluesになっているかなどを確認するときに使います。
--debug
オプションをつけると、各段階ごとのビルド情報が出力されるのでデバッグに役立ちます。
helmfile build
buildで出力される情報の例を以下に示します。
filepath: helmfile.yaml
helmBinary: helm
kustomizeBinary: kustomize
environments:
prod:
values:
- ./config/prod-values.yaml
secrets:
- ./config/prod-secrets.yaml
kubeContext: <kube context>
missingFileHandler: Debug
bases:
- ../../environments.yaml
- ../../templates.yaml
releases:
- chart: ../../charts/<your app>
version: 0.1.0
missingFileHandler: Debug
name: <your app>
namespace: <your namespace>
values:
- ./config/values.yaml.gotmpl
valuesTemplate:
- ./config/values.yaml.gotmpl
templates:
default:
missingFileHandler: Debug
valuesTemplate:
- ./config/values.yaml.gotmpl
renderedvalues:
image:
pullPolicy: IfNotPresent
repository: nginx
tag: latest
- template
template
は、helmfileが生成する最終的なマニフェストを出力します。実際にどのようなマニフェストが全体的に生成されるか確認するときに使ったりします。
helmfile template
主な利用方法はこれくらいですが、他にもコマンドやオプションがあるので、helmfileの公式サイトを参照してください。
#秘密情報の管理について
この記事では扱いませんが、helm secretsを使って、秘密情報を暗号化して管理することができます。
helm secretsについては、別記事で紹介しようと思います。
#参考リンク
#まとめ
今回は、helmfileの構成と利用について紹介しました。
helmfileの構成についてベストプラクティスを参考に、より使いやすい構成を考えてみました。
また主な利用方法についても説明しました。
秘密情報の扱いは別の記事で紹介できればと思います。