本記事には広告(アフィリエイトリンク)が含まれます。

Helm v4 基礎とChart作成 入門【CKAD第17回】

広告
広告

第17回スコープ・学習目標・今ここマップ

動作確認バージョン: K8s v1.35 / kubectl v1.35.0 / Helm v4.1.4 / kind v0.31.0 / kindest/node:v1.35.0 / Docker CE 29.4.3 / containerd 2.2.3 / AlmaLinux 10.1(kernel 6.12.0-124.55.3.el10_1)(2026-05-16 時点・k8s-ops 実機検証)

本回は Kubernetes 実践教科書 第1巻(CKAD 対応・全 19 回)の第17回です。第6部「パッケージ管理 + HTTPS 公開」の第1回(3 回中の 1 回目)として、Kubernetes のパッケージマネージャである Helm v4 を扱います。

第5部までで fanclub-api は Deployment / Service / StatefulSet / ConfigMap / Secret / Probe / ResourceQuota / RBAC / SecurityContext / NetworkPolicy という多数の Kubernetes リソースで構成されるようになり、それらは個別の YAML ファイルとして ~/fanclub-manifests/ に散在しています。

本回では、この「散在した生 YAML を kubectl apply する運用」が抱える課題を整理したうえで、Helm の 4 概念(Chart / Release / Repository / Values)、Chart の構造、テンプレート構文を学び、fanclub-api を 1 つの Helm Chart にパッケージ化します。

さらに helm install / helm upgrade / helm rollback / helm uninstall というリリースのフルサイクルを kind 実機で演習し、CKAD ドメイン D2「Application Deployment」(出題比率 20%)の Competency「Use the Helm package manager to deploy existing packages」を完全網羅します。

第16回からの継承状態確認

項目状態出典
kind クラスタkind-control-plane Ready(v1.35.0)Lead 実機観察
Helm未インストールcommand -v helm でヒットなし)→ 本回演習①で導入Lead 実機観察
Namespace 一覧default / kube-node-lease / kube-public / kube-system / local-path-storage(合計 5 個)ep16 完了状態
default ns のリソースfanclub-backend × 2 / fanclub-db-0 / node-logger / client Podep16 完了状態を継続
default ns の NetworkPolicy6 個(ep16 の default-deny-all を含む)ep16 完了状態
~/fanclub-manifests/個別 YAML が散在(fanclub-api 関連 + NetworkPolicy + 演習用)Lead 実機観察
k8s-ops VMAlmaLinux 10.1 minimal(which コマンドなし・command -v を使用)Lead 実機観察
Allocated CPU1550m / 2000m(77 %)Lead 実機観察

今ここマップ(第1巻 19 回中の現在位置):

第1部 コンテナとDocker
    第1回〜第4回  [完了]

第2部 Kubernetes基礎
    第5回〜第6回  [完了]

第3部 アプリリソース
    第7回〜第11回  [完了]

第4部 ワークロード戦略
    第12回〜第14回  [完了]

第5部 セキュリティ基礎
    第15回〜第16回  [完了]

第6部 パッケージ管理 + HTTPS公開(第17〜19回)
  ★ 第17回 Helm v4 基礎 + fanclub-api Helm Chart 作成  ← 今ここ(第6部第1回)
    第18回 Gateway API + Traefik + cert-manager で HTTPS 公開
    第19回 総合演習(第1巻完走)

第17回を終えると、以下を習得した状態になります。

  • Helm が Kubernetes のパッケージマネージャである役割を理解し、生 YAML を kubectl apply する運用が抱える課題(環境ごとの値の手書き変更・リソース間の整合管理・バージョン管理・ロールバックの困難さ)を、Helm がどう解決するかを説明できる
  • Helm の 4 概念(Chart / Release / Repository / Values)を理解し、それぞれの関係(Repository から Chart を取得 → Values を与えて install → Release が生まれる)を説明できる。「Chart = パッケージ」「Release = インストールした実体」という最も混同しやすい区別を明確にできる
  • Chart の構造(Chart.yaml / values.yaml / templates/ / _helpers.tpl)を理解し、fanclub-api を Chart 化できる。テンプレート構文({{ .Values }} / {{ .Release }} / {{ include }} / {{- if }})で値を外部化できる
  • helm install / helm upgrade / helm rollback / helm uninstall のフルサイクルを実施できる。helm history でリビジョンを確認し、安全に rollback できる。rollback が「リビジョン N に戻す操作だが履歴上は新リビジョンとして記録される」性質を説明できる
  • CKAD 試験 D2「Use the Helm package manager to deploy existing packages」Competency に対応できる。helm lint / helm template で Chart をデバッグでき、--set / -f による values 上書きを試験形式で書き起こせる

模擬アプリ進捗(第17回):本回の演習①では Helm v4.1.4 を k8s-ops VM にインストールし、helm create で Chart の雛形を生成して構造を確認します。演習②では fanclub-api の Backend をテンプレート化した Helm Chart を ~/fanclub-charts/fanclub-api/ に作成し、新 Namespace fanclubhelm install します。

演習③では values.yaml を変更して helm upgradehelm rollback で前の版に戻し、helm uninstall でクリーンアップするフルサイクルを実機で確認します。

設計上の注意:本回の Helm 演習は、default ns ではなく新 Namespace fanclub に対して実施します。default ns には ep16 で適用した default-deny-all を含む 6 個の NetworkPolicy と、生 kubectl apply で管理された既存 fanclub-api が稼働しています。

ここに Helm Chart で fanclub-api を helm install すると、既存リソースと名前が衝突したり、default-deny-all が新規 Pod の通信を遮断したりします。Helm のライフサイクル(install / upgrade / rollback / uninstall)を体験することが演習の主眼であるため、新 ns でクリーンに完結させます。default ns の既存リソース・NetworkPolicy には一切触れません。

また、本回の Chart は fanclub-api の Backend を中心に構成し、PostgreSQL DB は Chart スコープ外とします。Backend の Init Container wait-for-dbvalues.yamlinitContainer.enabled: false(デフォルト無効)でオフにできる設計にし、DB なしでも演習が成立するようにします。

Helm とは — Kubernetes のパッケージマネージャ

個別の YAML や演習に入る前に、本回の中心テーマである Helm の役割を整理します。Helm は「Kubernetes のパッケージマネージャ」と説明されますが、この一文だけでは何が嬉しいのかが伝わりません。まず、ここまで本シリーズで続けてきた「生 YAML を kubectl apply する運用」が、リソースが増えるにつれてどのような課題を抱えるかを具体的に見ていきます。

生 YAML を kubectl apply する運用の課題

第7回以降、fanclub-api を構成するリソースは 1 つずつ増えてきました。ep16 完了時点では、fanclub-api は Deployment / Service / StatefulSet / ConfigMap / Secret / ServiceAccount / Role / RoleBinding / NetworkPolicy という多数のリソースの集合です。

これらは ~/fanclub-manifests/ に個別の YAML ファイルとして置かれ、デプロイは kubectl apply -f ~/fanclub-manifests/ で行ってきました。この運用は学習段階では分かりやすいものの、リソース数が増え、環境が複数になり、変更を繰り返すようになると、次の 4 つの課題が表面化します。

課題生 YAML 運用での具体的な困りごと
環境ごとの値の手書き変更開発環境では replica 1・本番環境では replica 3、開発ではイメージタグ 0.1.0-dev・本番では 0.1.0 といった環境差分を、YAML ファイルを手で書き換えるか、環境ごとに YAML を別管理する。書き換え漏れや環境間の取り違えが起きやすい
リソース間の整合管理Deployment が参照する ConfigMap 名、Service が指す Pod のラベル、Secret のキー名などが複数の YAML にまたがって書かれている。1 箇所を変更すると関連する複数ファイルを同時に直す必要があり、整合が崩れやすい
バージョン管理「いま本番に出ているのはどの構成か」「前回のデプロイから何が変わったか」を、生 YAML 運用では Git のコミット履歴を追って人間が読み解くしかない。アプリ全体を 1 つの単位としてバージョン番号で管理する仕組みがない
ロールバックの困難さ新しい構成をデプロイして問題が起きたとき、前の状態に戻すには「前のコミットの YAML を取り出して apply し直す」必要がある。削除されたリソースの復元や、apply 順序の再現は手作業になり、緊急時ほどミスが出やすい

これらの課題は、リソースが 2〜3 個のうちは表面化しません。しかし fanclub-api のように 10 個以上のリソースで構成されるアプリを、開発・ステージング・本番の複数環境で運用し、機能追加のたびにデプロイを繰り返す状況になると、生 YAML 運用は管理コストが急に増えます。この状況を解決するために生まれたのが Helm です。

Helm = アプリを「パッケージ」として扱う仕組み

Helm は、Linux の apt / dnf(yum)や、Node.js の npm のような「パッケージマネージャ」の考え方を Kubernetes に持ち込んだツールです。AlmaLinux で dnf install nginx を実行すると、nginx 本体・設定ファイル・systemd ユニットなどがまとめて 1 つのパッケージとして導入され、dnf remove で一括削除でき、dnf upgrade でバージョンを上げられます。

Helm はこれと同じことを Kubernetes のリソース群に対して行います。

Helm が生 YAML 運用の 4 課題をどう解決するかを整理します。Helm はマニフェストをテンプレート化し、環境ごとに変わる値(replica 数・イメージタグ・リソース量など)を values.yaml という 1 つのファイルに外部化します。これにより、テンプレート本体は共通のまま、values.yaml を差し替えるだけで開発・本番の差分を吸収できます。複数のリソースを 1 つの Chart(パッケージ)にまとめるため、リソース間の整合はテンプレート側で一元管理できます。

Chart にはバージョン番号が付き、クラスタにインストールした実体(Release)はリビジョン履歴を持つため、「いまどの構成が出ているか」「前回から何が変わったか」を Helm 自身が追跡します。そして helm rollback 一発で前のリビジョンに戻せます。

生 YAML 運用の課題Helm による解決
環境ごとの値の手書き変更環境差分を values.yaml に外部化。テンプレートは共通・値だけ差し替える
リソース間の整合管理複数リソースを 1 Chart にまとめ、共通の値・ラベルをテンプレートで一元管理
バージョン管理Chart にバージョン番号・Release にリビジョン履歴。helm history で追跡
ロールバックの困難さhelm rollback <release> <revision> 一発で前の状態に戻せる

CKAD で問われる Helm のスキル

CKAD 試験の出題範囲には Helm が含まれます。ドメイン D2「Application Deployment」の Competency に「Use the Helm package manager to deploy existing packages(Helm パッケージマネージャを使って既存のパッケージをデプロイする)」が明記されています。ここで重要なのは「existing packages(既存のパッケージ)」という表現です。

CKAD で問われるのは、ゼロから複雑な Chart を設計する能力ではなく、配布されている Chart をリポジトリから取得し、helm install でデプロイし、--set-f で値を上書きし、必要なら helm upgrade / helm rollback でリリースを管理する、という「Helm の利用者」としての操作能力です。

とはいえ、Chart を「使う」だけでは Chart の構造やテンプレートの仕組みが理解できず、トラブルシューティング系の設問に対応できません。本回では、fanclub-api を題材に Chart を自分で 1 つ作る演習を通じて Chart の内部構造を理解し、そのうえで install / upgrade / rollback / uninstall という「利用者としての操作」を身につける構成にしています。

Chart を作る経験があると、既存 Chart を helm template で展開して中身を読む、values.yaml のどのキーを --set で上書きすればよいか判断する、といった試験での実務がしやすくなります。

Helm v4 の 4 概念 — Chart / Release / Repository / Values

Helm を扱ううえで土台になるのが、4 つの概念です。Chart / Release / Repository / Values の 4 つは Helm の公式ドキュメントでも最初に説明される基本用語で、この 4 つの関係を正確に押さえておくと、本回以降のコマンド操作がすべて「この 4 概念のどれを操作しているか」で理解できます。CKAD 試験でも、特に「Chart」と「Release」の区別は誤解の多いポイントです。

4 概念の定義

概念定義たとえると
ChartKubernetes マニフェストのテンプレート集(パッケージそのもの)。Chart.yaml + values.yaml + templates/ というディレクトリ構造を持つdnf でいう「rpm パッケージファイル」
ReleaseChart をクラスタにインストールした実体。名前が付き、リビジョン履歴を持つ。同じ Chart から名前を変えて複数の Release を作れる「インストール済みのアプリケーション」
RepositoryChart の配布元。HTTP サーバーや OCI レジストリ上に Chart を公開し、そこから取得できるdnf でいう「リポジトリ(ミラーサーバー)」
Valuesテンプレートに注入する設定値。Chart 同梱の values.yaml がデフォルト値で、--set / -f でインストール時に上書きできる「インストール時の設定オプション」

4 概念の関係を一文で言うと、「Repository から Chart を取得し、Values を与えて install すると、Release が生まれる」となります。この流れを図にすると次のようになります。

Helm の 4 概念図。Repository(Chart の配布元)から Chart を取得し、Values(設定値)を与えて helm install すると Release が生まれ Kubernetes クラスタへ反映される、という一連の流れを左から右へ示す。Repository・Chart・Values・Release の 4 概念の関係を 1 枚に整理している

Chart と Release の違い — 最も混同しやすい区別

4 概念のうち、新卒読者・CKAD 受験者がもっとも混同しやすいのが「Chart」と「Release」の区別です。両者の違いを明確にしておきます。

Chart はパッケージそのものです。ディスク上のディレクトリ(または .tgz アーカイブ)として存在し、まだクラスタには何も作っていない状態です。dnf でいえば「ダウンロードした rpm ファイル」に相当します。rpm ファイルがディスクにあるだけでは、アプリケーションはまだインストールされていません。

Release は Chart をクラスタにインストールした実体です。helm install を実行すると、Chart のテンプレートが Values で展開されて実際の Kubernetes リソース(Deployment / Service など)がクラスタに作られ、その一式に「Release 名」が付きます。dnf install 後の「インストール済みアプリ」に相当します。

この区別が重要なのは、1 つの Chart から、Release 名を変えて複数の Release を作れるからです。たとえば fanclub-api Chart を helm install fanclub-dev ./fanclub-apihelm install fanclub-staging ./fanclub-api の 2 回インストールすれば、同じ Chart から fanclub-devfanclub-staging という 2 つの独立した Release ができます。

それぞれが別々のリビジョン履歴を持ち、別々に upgrade / rollback できます。「Chart は設計図、Release は設計図から建てた個々の建物」と捉えると、この 1 対多の関係が理解しやすくなります。

観点ChartRelease
存在する場所ディスク(ディレクトリ / .tgz)クラスタ(実際の K8s リソース + Helm 管理情報)
名前Chart 名(Chart.yamlnameRelease 名(helm install 時に指定)
個数の関係1 つの Chart から……複数の Release を作れる
リビジョン履歴持たない持つ(helm history で確認)
確認コマンドhelm show chart <chart>helm list -n <ns>

Values は「テンプレートに注入する設定値」

Values は、Chart のテンプレートに注入される設定値です。Chart には values.yaml というファイルが同梱されており、これがデフォルト値です。テンプレート側では {{ .Values.replicaCount }} のように .Values 経由でこの値を参照します。

Values は install / upgrade のたびに上書きできます。上書きの方法は 2 通りあります。1 つは --set key=value でコマンドラインから 1 値ずつ指定する方法、もう 1 つは -f custom-values.yaml(または --values)で別の YAML ファイルを丸ごと渡す方法です。優先順位は「--set / -f での指定 > Chart 同梱の values.yaml」で、後から渡した値がデフォルトを上書きします。

これにより、Chart 本体は共通のまま、開発環境では -f values-dev.yaml、本番環境では -f values-prod.yaml といった環境差分を吸収できます。

Repository は Chart の配布元

Repository は Chart の配布元です。HTTP サーバー上に複数の Chart アーカイブとインデックスファイルを公開する形式と、OCI レジストリ(コンテナイメージと同じレジストリ)に Chart を格納する形式があります。helm repo add <name> <url> でリポジトリを登録し、helm repo update でインデックスを更新、helm search repo <keyword> で Chart を検索、helm install <release> <repo>/<chart> でリポジトリ上の Chart を直接インストールできます。

本回の演習では fanclub-api Chart を自分で作り、それをローカルディレクトリから直接インストールするため、Repository は使いません。ただし CKAD 試験では「指定のリポジトリを add して、その中の Chart を install せよ」という形式の設問が出るため、Repository の操作コマンドは H2「CKAD 試験頻出パターン」で整理します。

第18回以降で扱う Traefik / cert-manager も、それぞれの公式リポジトリから Chart を取得してインストールします。

Helm v4 と v3 の違い + Helm v4 インストール手順

本シリーズが採用する Helm のバージョンは v4.1.4 です。Helm はメジャーバージョンが v2 → v3 → v4 と進化してきました。実務では v3 系の情報がまだ多く流通しているため、v4 で何が変わったかと、v4 のインストール手順を整理します。

Helm v2 から v3 への大きな変化 — Tiller の廃止

Helm の歴史で最も大きな変化は、v2 から v3 への移行で起きました。Helm v2 には Tiller というサーバーサイドコンポーネントがありました。Tiller はクラスタ内に Pod として常駐し、helm クライアントからの指示を受けて実際にリソースを操作する役割でした。しかし Tiller はクラスタ全体に対する強い権限を持つため、Tiller の権限が広すぎることがセキュリティ上の弱点になっていました。

Helm v3 ではこの Tiller が廃止されました。v3 以降の Helm はクライアントのみで動作し、helm コマンドが直接 Kubernetes API Server と通信します。権限は helm を実行するユーザーの kubeconfig(RBAC の権限)にそのまま従うため、第15回で学んだ RBAC の考え方がそのまま Helm の権限制御になります。Release の情報(リビジョン履歴など)は、クラスタ内の Secret(または ConfigMap)として保存されます。

本回で使う Helm v4 もこの「Tiller なし・クライアントのみ」の構成を引き継いでいます。Helm v4 に Tiller は存在しません。これは CKAD 試験の誤解予防問題(理解度チェック問 5)でも問われる重要ポイントです。

Helm v3 から v4 への変更点

v3 から v4 への変更は、v2 → v3 の Tiller 廃止ほど劇的なものではなく、利用者から見た基本操作(helm install / upgrade / rollback / uninstall)はほぼ同じです。主な変更点を整理します。

変更点内容本回の演習への影響
OCI レジストリ統合の標準化v3 では実験的機能だった OCI レジストリ(コンテナイメージと同じレジストリに Chart を格納する方式)が v4 で標準機能になった本回はローカル Chart を扱うため直接の影響なし
Go モジュールパスの変更Helm を Go ライブラリとして組み込む際のモジュールパスが変更されたHelm を CLI として使う本回には影響なし
プラグイン API の変更Helm プラグインの仕組みが更新された本回はプラグインを使わないため影響なし
helm install のデフォルト動作の微修正一部のフラグのデフォルト値や出力フォーマットが見直されたコマンドの基本的な使い方は v3 と同じ

結論として、CKAD で問われる Helm の基本操作(Chart の構造・install / upgrade / rollback / uninstall・values 上書き・lint / template)は v3 と v4 で共通です。本回で学ぶ内容は、もし試験環境が v3 系であっても、ほぼそのまま通用します。

Helm v4 のインストール方法 — バイナリを直接取得する

Helm のインストールには複数の方法がありますが、本回では tar.gz バイナリを直接取得して配置する方法を使います。Helm 公式が提供する get_helm.sh というインストールスクリプトもありますが、このスクリプトは現時点で v3 系を取得する仕様のため、v4 を確実に入れるには使いません。バイナリを直接取得すれば、入れるバージョンを helm-v4.1.4 と明示でき、本シリーズのバージョンピン留め方針にも合致します。

取得元の URL は次のとおりです。本回の演習①では、主の取得元として Helm 公式の配布サーバー get.helm.sh を使います。

https://get.helm.sh/helm-v4.1.4-linux-amd64.tar.gz

本シリーズの検証環境では、k8s-ops VM の外向き通信は alma-proxy(Squid・whitelist 方式)を経由します。get.helm.sh が alma-proxy の whitelist に登録されていない場合は、上記 URL からの取得が失敗します。その場合の代替の取得元として、GitHub Releases を併記しておきます。

第5回で kind / kubectl のバイナリを GitHub Releases から取得した実績があり、Helm も GitHub のリリースページに同じ tar.gz が公開されています。

https://github.com/helm/helm/releases

上記ページの v4.1.4 のリリースから helm-v4.1.4-linux-amd64.tar.gz をダウンロードします。get.helm.sh と GitHub Releases のどちらの取得元でも、ダウンロードされる tar.gz の中身(helm バイナリ)は同一です。演習①では get.helm.sh を主の手順として記載し、whitelist 未登録時は GitHub Releases に切り替える前提で進めます。

やってみよう①: Helm v4 インストールと Chart 雛形の理解

演習①では、k8s-ops VM に Helm v4.1.4 をインストールし、helm create で Chart の雛形を生成して構造を確認します。所要時間の目安は 15 分です。この演習で Helm コマンドが手元で動く状態を作り、Chart のディレクトリ構造を実物で把握します。

Step 1: Helm v4.1.4 の tar.gz を取得する

まず、作業用のディレクトリに移動し、Helm のバイナリ tar.gz を取得します。実行コマンド:

$ cd ~
$ curl -fsSLO https://get.helm.sh/helm-v4.1.4-linux-amd64.tar.gz
$ ls -lh helm-v4.1.4-linux-amd64.tar.gz

期待される実行結果:

-rw-r--r--. 1 developer developer 17M May 16 10:22 helm-v4.1.4-linux-amd64.tar.gz

curl のオプションのうち -f は HTTP エラー時に失敗扱いにする指定、-sS は進捗バーを出さずエラーだけ表示する指定、-L はリダイレクト追従、-O は URL のファイル名でローカル保存する指定です。もし curl: (28) Connection timed out のようなエラーで取得できない場合、get.helm.sh が alma-proxy の whitelist に登録されていないことが考えられます。

その場合は GitHub Releases(https://github.com/helm/helm/releases)の v4.1.4 から helm-v4.1.4-linux-amd64.tar.gz を取得し、以降の Step を同じファイル名で進めてください。

Step 2: tar.gz を展開して helm バイナリを配置する

取得した tar.gz を展開し、中の helm バイナリを /usr/local/bin/ に配置します。展開すると linux-amd64/ というディレクトリができ、その中に helm バイナリが入っています。実行コマンド:

$ tar -xzf helm-v4.1.4-linux-amd64.tar.gz
$ ls linux-amd64/
$ sudo install -m 0755 linux-amd64/helm /usr/local/bin/helm

期待される実行結果(ls linux-amd64/ の出力):

LICENSE  README.md  helm

install -m 0755 は、ファイルをコピーしつつ実行権限(0755)を付与するコマンドです。/usr/local/bin/ は PATH に含まれるディレクトリのため、配置後はどこからでも helm コマンドを呼び出せます。

Step 3: helm version でインストールを確認する

Helm が PATH 上に配置されたことと、バージョンが v4.1.4 であることを確認します。実行コマンド:

$ command -v helm
$ helm version

期待される実行結果:

/usr/local/bin/helm
version.BuildInfo{Version:"v4.1.4", GitCommit:"...", GitTreeState:"clean", GoVersion:"go1.25"}

コマンドの所在確認に which ではなく command -v を使っている点に注意してください。k8s-ops VM は AlmaLinux 10.1 の minimal インストールで、which コマンドが入っていません。command -v はシェル組み込みのため追加インストール不要で、本シリーズではこちらを使います。helm version の出力に Version:"v4.1.4" が表示されれば、Helm v4 のインストールは完了です。

なお、Helm v3 まで helm version はサーバー(Tiller)側のバージョンも表示していましたが、v3 以降は Tiller がないためクライアント情報のみが出ます。

Step 4: helm create で Chart の雛形を生成する

helm create コマンドは、Chart の雛形を生成します。雛形には Helm が用意したサンプルのテンプレートと values.yaml が含まれており、Chart の構造を学ぶ教材になります。実行コマンド:

$ cd ~
$ helm create demo-chart

期待される実行結果:

Creating demo-chart

カレントディレクトリに demo-chart/ というディレクトリが作られます。このディレクトリ全体が 1 つの Chart です。

Step 5: 雛形の構造を確認する

生成された Chart の構造を find で確認します。実行コマンド:

$ find demo-chart -type f
$ find demo-chart -type d

期待される実行結果(ファイル一覧):

demo-chart/Chart.yaml
demo-chart/values.yaml
demo-chart/.helmignore
demo-chart/templates/deployment.yaml
demo-chart/templates/service.yaml
demo-chart/templates/serviceaccount.yaml
demo-chart/templates/ingress.yaml
demo-chart/templates/hpa.yaml
demo-chart/templates/_helpers.tpl
demo-chart/templates/NOTES.txt
demo-chart/templates/tests/test-connection.yaml

主要なファイル・ディレクトリの役割を整理します。

ファイル / ディレクトリ役割
Chart.yamlChart のメタデータ(名前・バージョン・説明など)
values.yamlテンプレートに注入するデフォルト値
templates/テンプレート化した K8s マニフェストを置くディレクトリ
templates/_helpers.tpl共通ヘルパーテンプレート。先頭が _ のファイルは K8s リソースとして出力されない
templates/NOTES.txtinstall 後にコンソールに表示される案内文(任意)
charts/依存する subchart を置くディレクトリ(本回演習では使わない)
.helmignoreChart のパッケージ化時に除外するファイルのパターン

helm create の雛形には Deployment / Service / Ingress / HPA など多くのテンプレートが含まれます。本回の演習②では、この雛形をそのまま使うのではなく、fanclub-api 専用の Chart をゼロから作ります。雛形は「Chart とはこういう構造のもの」を理解するための見本として確認します。

Step 6: helm lint と helm template で雛形を検証する

helm lint は Chart の構文エラーや推奨事項からの逸脱を検出するコマンドです。クラスタには一切触れず、Chart のファイルを静的に検査します。実行コマンド:

$ helm lint demo-chart

期待される実行結果:

==> Linting demo-chart
[INFO] Chart.yaml: icon is recommended

1 chart(s) linted, 0 chart(s) failed

[INFO] は推奨事項(icon の指定が推奨される、など)で、エラーではありません。0 chart(s) failed と表示されれば、Chart は構文上問題なくインストール可能な状態です。[ERROR] が出る場合は構文エラーがあり、修正しないと install できません。

次に helm template を実行します。これは Chart のテンプレートを Values で展開し、最終的に生成される K8s マニフェストをクラスタに適用せず標準出力に表示するコマンドです。テンプレートが期待どおりの YAML に展開されるかを目視確認するのに使います。実行コマンド:

$ helm template demo-release demo-chart | head -n 30

期待される実行結果(先頭部分の例):

---
# Source: demo-chart/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: demo-release-demo-chart
  labels:
    helm.sh/chart: demo-chart-0.1.0
    app.kubernetes.io/name: demo-chart
    app.kubernetes.io/instance: demo-release
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
---
# Source: demo-chart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: demo-release-demo-chart
...

出力を見ると、helm template の第 1 引数に渡した Release 名(demo-release)が metadata.name に展開され、# Source: コメントでどのテンプレートファイル由来かが分かるようになっています。helm template はクラスタに触れないため、kind クラスタが動いていなくても実行できます。これで演習①は完了です。Helm v4 が動き、Chart の構造と lint / template の使い方を確認できました。

Chart の構造 — Chart.yaml / values.yaml / templates/

演習①で Chart の雛形を確認しました。ここでは演習②で fanclub-api の Chart を自作するのに先立ち、Chart を構成する 3 要素(Chart.yaml / values.yaml / templates/)の役割を整理します。

Chart のディレクトリ構造

演習②で作る fanclub-api Chart の完成形のディレクトリ構造は次のようになります。

fanclub-api/
  Chart.yaml          # Chart のメタデータ(name / version / appVersion)
  values.yaml         # デフォルト値
  templates/          # テンプレート化したマニフェスト
    deployment.yaml
    service.yaml
    configmap.yaml
    secret.yaml
    serviceaccount.yaml
    _helpers.tpl      # 共通ヘルパー(ラベル等)
  charts/             # 依存 subchart(本演習では空)
  .helmignore

このディレクトリ全体が 1 つの Chart です。charts/ は他の Chart を依存関係として取り込むためのディレクトリですが、本回の fanclub-api Chart は単独で完結するため空のままにします。.helmignore は Chart を .tgz にパッケージ化するときに除外するファイルのパターン(.git や一時ファイルなど)を書くファイルで、.gitignore と同じ役割です。

Chart.yaml — Chart のメタデータ

Chart.yaml は Chart のメタデータを記述するファイルです。主要なフィールドを整理します。

フィールド意味fanclub-api Chart での値
apiVersionChart フォーマットのバージョン。Helm v3 / v4 では v2 を使うv2
nameChart の名前fanclub-api
descriptionChart の説明文fanclub-api backend Helm chart
typeChart の種別。application(アプリ)か library(ライブラリ)application
versionChart 自体のバージョン。Chart の構成を変えたら上げる1.0.0
appVersionChart が梱包するアプリケーションのバージョン"0.1.0"

ここで apiVersion という名前に注意してください。これは Kubernetes リソースの apiVersion とは別物で、「Chart ファイルフォーマットのバージョン」を表します。Helm v2 時代の Chart は apiVersion: v1、Helm v3 以降の Chart は apiVersion: v2 を使います。v2 フォーマットは Helm v3 と v4 で共通のため、本回の Chart はそのまま v3 環境でも使えます。

もう 1 つ重要なのが versionappVersion の違いです。version は「Chart(パッケージ)自体のバージョン」で、テンプレートや values.yaml の構成を変えたら上げます。appVersion は「Chart が梱包しているアプリケーション(fanclub-api)のバージョン」です。たとえばアプリのコードは変えずに Chart のテンプレートだけ修正した場合、version は上げますが appVersion は据え置く、という使い分けになります。

fanclub-api Chart では Chart version: 1.0.0・アプリ appVersion: "0.1.0" とし、appVersion はコンテナイメージのタグ(fanclub-backend:0.1.0)と揃えます。

values.yaml — デフォルト値の定義

values.yaml は、テンプレートに注入する設定値のデフォルトを定義する YAML ファイルです。テンプレート側からは {{ .Values.キー名 }} でこのファイルの値を参照します。values.yaml は階層構造を持てるため、たとえば次のように書くと、テンプレートからは {{ .Values.image.repository }}{{ .Values.image.tag }} で参照できます。

image:
  repository: fanclub-backend
  tag: "0.1.0"

values.yaml に書く値の選び方には設計判断があります。「環境やデプロイのたびに変わりうる値」「利用者が調整したい値」を values.yaml に出し、「Chart の内部実装で固定してよい値」はテンプレートに直書きします。fanclub-api Chart では replica 数・イメージ・リソース量・Service のポート・ConfigMap / Secret の中身を values.yaml に出し、ラベルの命名規則やリソースの kind などはテンプレート側で固定します。

templates/ — テンプレート化したマニフェスト

templates/ は、テンプレート化した Kubernetes マニフェストを置くディレクトリです。helm install 時、Helm はこのディレクトリ内の各ファイルを values.yaml の値で展開し、生成された YAML をクラスタに適用します。

templates/ 内のファイルには 2 種類あります。1 つは deployment.yaml / service.yaml のような、K8s リソースとして出力されるテンプレートファイルです。もう 1 つは、ファイル名の先頭が _(アンダースコア)のヘルパーファイルです。_helpers.tpl がその代表で、複数のテンプレートから呼び出す共通の部品(ラベルの定義など)を書きます。

先頭が _ のファイルは Helm が「K8s リソースとして出力しない」と判断するため、ヘルパーを置いてもクラスタに余計なリソースは作られません。

fanclub-api Chart の templates/ には、deployment.yaml / service.yaml / configmap.yaml / secret.yaml / serviceaccount.yaml の 5 つのテンプレートファイルと、_helpers.tpl の 1 つのヘルパーファイルを置きます。テンプレートに使う構文を次の H2 で整理してから、演習②で実際に書いていきます。

テンプレート構文 — Values / Release / 組込オブジェクト

Helm のテンプレートは、Go 言語の text/template という仕組みをベースにしています。テンプレートファイルは「素の YAML」に {{ ... }} という波カッコで囲まれたテンプレート式を埋め込んだものです。helm install / helm template 実行時に、Helm がこの {{ ... }} 部分を実際の値に置き換えて、最終的な YAML を生成します。本 H2 では、演習②で使うテンプレート構文を整理します。

.Values — values.yaml の値を参照する

最もよく使うのが .Values です。これは values.yaml(および --set / -f での上書き)の値を参照するオブジェクトです。たとえば values.yamlreplicaCount: 1 と書いてあれば、テンプレートで {{ .Values.replicaCount }} と書くと、展開時に 1 に置き換わります。階層構造の場合はドットでたどります。

テンプレート式参照する values.yaml の値
{{ .Values.replicaCount }}トップレベルの replicaCount
{{ .Values.image.repository }}image: 配下の repository
{{ .Values.resources.requests.cpu }}resources:requests: 配下の cpu

.Release — Release の組込オブジェクト

.Release は、helm install 時に Helm が自動で用意する組込オブジェクトで、その Release に関する情報を持ちます。values.yaml には書かれていませんが、テンプレートから参照できます。

テンプレート式意味
{{ .Release.Name }}helm install 時に指定した Release 名
{{ .Release.Namespace }}Release をインストールした Namespace
{{ .Release.Revision }}現在のリビジョン番号
{{ .Release.IsUpgrade }}upgrade 実行中なら true

.Release.Name は、リソース名を組み立てるのによく使われます。たとえばリソース名を {{ .Release.Name }}-fanclub-api のように組むと、同じ Chart を別の Release 名でインストールしてもリソース名が衝突しません。これが「1 つの Chart から複数の Release を作れる」仕組みを支えています。

.Chart — Chart の組込オブジェクト

.ChartChart.yaml の内容を参照する組込オブジェクトです。{{ .Chart.Name }} で Chart 名、{{ .Chart.Version }} で Chart バージョン、{{ .Chart.AppVersion }} でアプリのバージョン(Chart.yamlappVersion)を参照できます。これらはラベルに埋め込んで「このリソースはどの Chart のどのバージョンから作られたか」を記録するのに使います。

include — ヘルパーテンプレートの呼び出し

_helpers.tpl に定義した共通部品は、include 関数で呼び出します。たとえば _helpers.tplfanclub-api.labels という名前のラベル定義を書いておくと、各テンプレートから {{ include "fanclub-api.labels" . }} でその定義を埋め込めます。include の第 2 引数の .(ドット)は「現在のスコープ(.Values.Release を含むトップレベルの文脈)をヘルパーに渡す」という意味です。

ヘルパー側でも .Values などを使うため、この . を渡すのが定石です。

ヘルパーを使うと、全リソースに付ける共通ラベルを 1 箇所で定義でき、ラベルの命名規則を変えたいときに _helpers.tpl だけ直せばよくなります。「リソース間の整合管理」という生 YAML 運用の課題に対する Helm 側の解決策の 1 つです。

if — 条件分岐

{{- if 条件 }}{{- end }} で条件分岐を書けます。条件が真のときだけ、間に挟まれた部分が出力されます。fanclub-api Chart では Init Container wait-for-db を条件分岐で囲み、values.yamlinitContainer.enabledtrue のときだけ Init Container を出力する設計にします。

{{- if .Values.initContainer.enabled }}
      initContainers:
        - name: wait-for-db
          image: busybox:1.36
{{- end }}

ここで {{- のハイフン(-)に注目してください。{{- のハイフンは、そのテンプレート式の直前にある空白・改行を削除する記法です(whitespace chomping と呼びます)。テンプレートに {{ if }} を素で書くと、条件が偽でも {{ if }} が書かれていた行に空行が残り、生成される YAML に余計な空行が混ざります。{{- と書くことで直前の空白・改行が消え、YAML がきれいに整います。同様に -}} と書くと直後の空白・改行を削除します。

テンプレートの出力に余計な空行が出てインデントが崩れるときは、まずこの {{- / -}} の付け忘れを疑います。

パイプと関数 — quote / default / nindent

テンプレート式の中では、値を関数で加工できます。値と関数を |(パイプ)でつなぐと、Unix のパイプと同じく「左の値を右の関数に渡す」という意味になります。よく使う関数を整理します。

関数意味
quote値をダブルクオートで囲む。数値を文字列として出力したいときに使う{{ .Values.config.DB_PORT | quote }}
default値が空のときに既定値を使う{{ .Values.image.tag | default "latest" }}
nindent指定した桁数でインデントし、先頭に改行を入れる。複数行のブロックを埋め込むときに使う{{ include "fanclub-api.labels" . | nindent 4 }}
upper / lower大文字 / 小文字に変換する{{ .Values.env | upper }}

quote は、YAML で数値と文字列を区別したいときに使います。たとえばポート番号 5432 を ConfigMap の値として書くとき、quote を通さないと数値として扱われ、ConfigMap の data に書こうとするとエラーになることがあります(ConfigMap の data の値は文字列でなければなりません)。{{ .Values.config.DB_PORT | quote }} と書けば "5432" という文字列として出力されます。

nindentinclude と組み合わせて使うことが多く、ヘルパーが返す複数行のラベル定義を正しいインデントで埋め込むのに使います。これらの構文を踏まえて、演習②で fanclub-api Chart を実際に書いていきます。

やってみよう②: fanclub-api Chart を作成して helm install する

演習②では、fanclub-api の Backend を題材に Helm Chart をゼロから作り、新 Namespace fanclubhelm install します。所要時間の目安は 30 分です。本演習で作る Chart は、ここまで ~/fanclub-manifests/ に散在していた生 YAML を「テンプレート + values」の形に再構成したものです。

演習の前提(再掲):本演習は新 Namespace fanclub に対して実施します。default ns には ep16 の default-deny-all を含む 6 個の NetworkPolicy と既存 fanclub-api が稼働しているため、default ns には一切触れません。

Chart は fanclub-api の Backend(Deployment + Service + ConfigMap + Secret + ServiceAccount)を対象とし、PostgreSQL DB は Chart スコープ外です。Backend の Init Container wait-for-dbvalues.yamlinitContainer.enabled: false で無効化します。

fanclub-backend:0.1.0 の /health/live(MicroProfile Health)は DB 非依存で UP を返すため、DB なしでも Pod は起動します。

Step 1: Chart ディレクトリを作成する

Chart を置くディレクトリ ~/fanclub-charts/fanclub-api/ と、その配下の templates/ を作成します。実行コマンド:

$ mkdir -p ~/fanclub-charts/fanclub-api/templates
$ cd ~/fanclub-charts/fanclub-api
$ pwd

期待される実行結果:

/home/developer/fanclub-charts/fanclub-api

以降の Step では、このディレクトリを基準に Chart.yaml / values.yaml / templates/ 配下のファイルを作っていきます。

Step 2: Chart.yaml を作成する

~/fanclub-charts/fanclub-api/Chart.yaml を次の内容で作成します。

apiVersion: v2
name: fanclub-api
description: fanclub-api backend Helm chart
type: application
version: 1.0.0
appVersion: "0.1.0"

apiVersion: v2 は Helm v3 / v4 共通の Chart フォーマットです。version: 1.0.0 は Chart 自体のバージョン、appVersion: "0.1.0" は梱包するアプリ(fanclub-backend)のバージョンで、コンテナイメージのタグ 0.1.0 と揃えています。appVersion をダブルクオートで囲んでいるのは、0.1.0 を数値ではなく文字列として確実に扱わせるためです。

Step 3: values.yaml を作成する

~/fanclub-charts/fanclub-api/values.yaml を次の内容で作成します。これが Chart のデフォルト値です。

replicaCount: 1

image:
  repository: fanclub-backend
  tag: "0.1.0"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80
  targetPort: 8080

resources:
  requests:
    cpu: 100m
    memory: 256Mi
  limits:
    cpu: 1000m
    memory: 512Mi

initContainer:
  enabled: false

config:
  DB_HOST: fanclub-db
  DB_PORT: "5432"
  DB_NAME: fanclubdb
  JAVA_OPTS: "-XX:MaxRAMPercentage=75.0"

secret:
  DB_USER: fanclubuser
  DB_PASSWORD: fanclubpass

各キーの役割を整理します。replicaCount は Deployment の replica 数(演習③で 1 → 2 に変えます)。image はコンテナイメージのリポジトリ・タグ・pull ポリシー。service は Service の種別・公開ポート・転送先ポート。resources は Pod のリソース要求・上限。initContainer.enabled は Init Container の有効・無効で、ここでは false(無効)にしています。

config は ConfigMap に入れる非機密の設定値、secret は Secret に入れる機密値です。DB_HOST などは値として持っていますが、本演習では DB を Chart スコープ外にしているため、Backend が DB に接続しなくても /health/live は UP を返します。

resources.requests.cpu100m にしているのは、kind の単一ノード(2 vCPU)の制約に対応するためです。演習③で replicaCount を 2 に増やしたとき、default ns で稼働中の既存ワークロードと合わせても CPU 要求がノードの上限を超えないようにしています。本番クラスタでは Workload Node に余裕があるため、Backend の CPU 要求はアプリの実測値に基づいて 250m 以上に設定するのが一般的です。

Step 4: templates/_helpers.tpl を作成する

~/fanclub-charts/fanclub-api/templates/_helpers.tpl を作成します。ここには全リソース共通のラベルとセレクタラベルを定義します。

{{/*
共通名: Release 名 + Chart 名でリソース名を組み立てる
*/}}
{{- define "fanclub-api.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
セレクタラベル: Service の selector や Deployment の matchLabels に使う
*/}}
{{- define "fanclub-api.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

{{/*
共通ラベル: 全リソースの metadata.labels に使う
*/}}
{{- define "fanclub-api.labels" -}}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }}
{{ include "fanclub-api.selectorLabels" . }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}

{{- define "名前" -}}{{- end -}} でヘルパーを定義します。{{/* ... */}} はテンプレートのコメントで、出力には現れません。fanclub-api.fullname はリソース名を <Release名>-fanclub-api の形で組み立てるヘルパーで、trunc 63 で 63 文字(K8s のリソース名の上限)に切り詰め、末尾のハイフンを trimSuffix で除去します。

fanclub-api.selectorLabels は Pod を選ぶための最小限のラベル、fanclub-api.labels はそれに Chart 由来の情報を足した全リソース共通ラベルです。fanclub-api.labels の中で fanclub-api.selectorLabelsinclude しているのは、ラベルの定義を重複させないためです。

Step 5: configmap / secret / serviceaccount のテンプレートを作成する

templates/configmap.yaml を作成します。values.yamlconfig セクションの値を ConfigMap の data に展開します。

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "fanclub-api.fullname" . }}-config
  labels:
    {{- include "fanclub-api.labels" . | nindent 4 }}
data:
  DB_HOST: {{ .Values.config.DB_HOST | quote }}
  DB_PORT: {{ .Values.config.DB_PORT | quote }}
  DB_NAME: {{ .Values.config.DB_NAME | quote }}
  JAVA_OPTS: {{ .Values.config.JAVA_OPTS | quote }}

metadata.namefanclub-api.fullname ヘルパーで <Release名>-fanclub-api-config という名前に展開されます。labels 行の {{- include "fanclub-api.labels" . | nindent 4 }} は、ヘルパーが返す複数行のラベルを 4 桁インデントで埋め込みます。ConfigMap の data の値はすべて文字列でなければならないため、各値を quote で囲んでいます。

次に templates/secret.yaml を作成します。values.yamlsecret セクションの値を Secret に展開します。

apiVersion: v1
kind: Secret
metadata:
  name: {{ include "fanclub-api.fullname" . }}-secret
  labels:
    {{- include "fanclub-api.labels" . | nindent 4 }}
type: Opaque
stringData:
  DB_USER: {{ .Values.secret.DB_USER | quote }}
  DB_PASSWORD: {{ .Values.secret.DB_PASSWORD | quote }}

Secret の値は通常 base64 エンコードして data に書きますが、ここでは stringData を使っています。stringData はプレーンテキストで値を書けるフィールドで、Kubernetes が API Server 側で自動的に base64 エンコードして data に変換します。テンプレートで base64 エンコードを書く手間が省けるため、Chart では stringData を使うのが分かりやすい書き方です。

第10回で学んだとおり、Secret は base64 が暗号化ではない点に注意は必要ですが、本演習は学習用の値のため stringData でそのまま進めます。

次に templates/serviceaccount.yaml を作成します。fanclub-api Backend 専用の ServiceAccount を作ります。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ include "fanclub-api.fullname" . }}
  labels:
    {{- include "fanclub-api.labels" . | nindent 4 }}

第10回で学んだとおり、ServiceAccount を明示的に作って Pod に割り当てると、Pod が使う SA を default SA と分離でき、第15回の RBAC で権限を絞る際の起点になります。この ServiceAccount を Step 6 の Deployment テンプレートで Pod に割り当てます。

Step 6: templates/deployment.yaml を作成する

templates/deployment.yaml を作成します。これが Chart の中心となるテンプレートで、replica 数・イメージ・リソース・環境変数・Init Container の条件分岐をすべて含みます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "fanclub-api.fullname" . }}
  labels:
    {{- include "fanclub-api.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "fanclub-api.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "fanclub-api.selectorLabels" . | nindent 8 }}
    spec:
      serviceAccountName: {{ include "fanclub-api.fullname" . }}
      {{- if .Values.initContainer.enabled }}
      initContainers:
        - name: wait-for-db
          image: busybox:1.36
          command:
            - sh
            - -c
            - until nc -z {{ .Values.config.DB_HOST }} {{ .Values.config.DB_PORT }}; do sleep 2; done
      {{- end }}
      containers:
        - name: fanclub-backend
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.service.targetPort }}
          envFrom:
            - configMapRef:
                name: {{ include "fanclub-api.fullname" . }}-config
            - secretRef:
                name: {{ include "fanclub-api.fullname" . }}-secret
          resources:
            requests:
              cpu: {{ .Values.resources.requests.cpu }}
              memory: {{ .Values.resources.requests.memory }}
            limits:
              cpu: {{ .Values.resources.limits.cpu }}
              memory: {{ .Values.resources.limits.memory }}
          livenessProbe:
            httpGet:
              path: /health/live
              port: http
            initialDelaySeconds: 20
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /health/ready
              port: http
            initialDelaySeconds: 10
            periodSeconds: 5

このテンプレートの要点を整理します。replicas: {{ .Values.replicaCount }} で replica 数を values.yaml から取ります。image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" はイメージ名とタグを : で連結しています。

{{- if .Values.initContainer.enabled }}{{- end }} で Init Container 全体を囲み、values.yamlinitContainer.enabledfalse のため、本演習では initContainers: ブロックは出力されません。{{- のハイフンで、条件が偽のときに空行が残らないようにしています。

envFrom で ConfigMap と Secret を丸ごと環境変数として読み込み、Probe は第12回で設計した /health/live / /health/ready をそのまま使っています。

Step 7: templates/service.yaml を作成する

templates/service.yaml を作成します。Backend Pod を ClusterIP で公開します。

apiVersion: v1
kind: Service
metadata:
  name: {{ include "fanclub-api.fullname" . }}
  labels:
    {{- include "fanclub-api.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "fanclub-api.selectorLabels" . | nindent 4 }}

Service の selector には fanclub-api.selectorLabels ヘルパーを使い、Deployment の Pod テンプレートに付けたラベルと同じラベルを指定しています。両方が同じヘルパーから生成されるため、ラベルがずれて Service が Pod を見つけられない、というミスが起きません。targetPort: http は、Deployment テンプレートの portsname: http と付けたポートを名前で参照しています。

これでテンプレートのファイルは 6 つそろいました。

Step 8: helm lint と helm template で検証する

install の前に、Chart を検証します。まず helm lint で構文チェックします。実行コマンド:

$ cd ~/fanclub-charts
$ helm lint ./fanclub-api

期待される実行結果:

==> Linting ./fanclub-api
[INFO] Chart.yaml: icon is recommended

1 chart(s) linted, 0 chart(s) failed

次に helm template で、テンプレートが期待どおりの YAML に展開されるか確認します。実行コマンド:

$ helm template fanclub-api ./fanclub-api | head -n 25

期待される実行結果(先頭部分の例):

---
# Source: fanclub-api/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: fanclub-api-fanclub-api
  labels:
    helm.sh/chart: fanclub-api-1.0.0
    app.kubernetes.io/name: fanclub-api
    app.kubernetes.io/instance: fanclub-api
    app.kubernetes.io/version: "0.1.0"
    app.kubernetes.io/managed-by: Helm
---
# Source: fanclub-api/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: fanclub-api-fanclub-api-config
...

リソース名が fanclub-api-fanclub-api<Release名>-<Chart名>)になっているのは、Release 名と Chart 名がどちらも fanclub-api のためです。ラベルにも Chart バージョン fanclub-api-1.0.0 やアプリバージョン "0.1.0" が展開されており、テンプレートとヘルパーが期待どおり動いていることが確認できます。

Init Container は initContainer.enabled: false のため、Deployment テンプレートに initContainers: ブロックは現れません。

Step 9: helm install で fanclub Namespace にデプロイする

Chart を新 Namespace fanclub にインストールします。--create-namespace フラグを付けると、指定した Namespace が存在しなければ Helm が作成します。実行コマンド:

$ helm install fanclub-api ./fanclub-api -n fanclub --create-namespace

期待される実行結果:

NAME: fanclub-api
LAST DEPLOYED: Sat May 16 11:05:42 2026
NAMESPACE: fanclub
STATUS: deployed
REVISION: 1
TEST SUITE: None

STATUS: deployedREVISION: 1 が表示されれば、install は成功です。helm install の引数は「helm install <Release名> <Chart>」の順で、ここでは Release 名 fanclub-api・Chart にローカルディレクトリ ./fanclub-api を指定しています。-n fanclub でインストール先 Namespace を指定しています。

Release と作成されたリソースを確認します。実行コマンド:

$ helm list -n fanclub
$ kubectl get all -n fanclub

期待される実行結果(helm list の出力):

NAME         NAMESPACE  REVISION  UPDATED                  STATUS    CHART              APP VERSION
fanclub-api  fanclub    1         2026-05-16 11:05:42 ...  deployed  fanclub-api-1.0.0  0.1.0

期待される実行結果(kubectl get all -n fanclub の出力):

NAME                                          READY   STATUS    RESTARTS   AGE
pod/fanclub-api-fanclub-api-7d9c8f6b54-x2k8p   1/1     Running   0          45s

NAME                              TYPE        CLUSTER-IP      PORT(S)   AGE
service/fanclub-api-fanclub-api   ClusterIP   10.96.214.31    80/TCP    45s

NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/fanclub-api-fanclub-api   1/1     1            1           45s

NAME                                                DESIRED   CURRENT   READY   AGE
replicaset.apps/fanclub-api-fanclub-api-7d9c8f6b54   1         1         1       45s

Pod が 1/1 Running になっていれば、Chart のテンプレートが正しく展開され、Deployment / Service / ReplicaSet がクラスタに作られたことが確認できます。helm listREVISION 1 は、この Release のリビジョンが 1 であることを示します。これで演習②は完了です。散在していた fanclub-api の生 YAML が、1 つの Helm Chart としてパッケージ化され、helm install 一発でデプロイできる状態になりました。

次の演習③で、この Release を upgrade / rollback / uninstall します。

helm のライフサイクル — install / upgrade / rollback / uninstall

演習②で Release を作りました。Release はここから upgrade / rollback / uninstall というライフサイクルを辿ります。演習③に入る前に、この 4 操作とリビジョンの関係を整理します。

4 操作とリビジョンの対応

操作コマンドリビジョンの動き
installhelm install <release> <chart> -n <ns>リビジョン 1 が生まれる
upgradehelm upgrade <release> <chart> -n <ns>リビジョンが +1 される
rollbackhelm rollback <release> <revision> -n <ns>戻し先の内容で新しいリビジョンが +1 される
uninstallhelm uninstall <release> -n <ns>Release が削除される(履歴も消える)
historyhelm history <release> -n <ns>リビジョン一覧を表示する(リビジョンは変えない)
helm のリビジョン履歴図。install でリビジョン 1 が生まれ、helm upgrade(replicaCount を 2 に変更)でリビジョン 2、helm rollback でリビジョン 1 の内容に戻してもリビジョン 3 として新規記録される、という横一直線の流れを示す。リビジョン番号は常に増加し、現在版のリビジョン 3 を緑、過去版のリビジョン 1・2 を青で表す

install — Release を生み出す

helm install は Chart をクラスタにインストールし、Release を生み出します。このとき Release のリビジョンは 1 になります。Helm は Release の情報(どの Chart のどのバージョンを、どの Values で入れたか)を、対象 Namespace の Secret として保存します。演習②でこの操作を済ませました。

upgrade — Release を更新する

helm upgrade は、既存の Release を新しい Chart 内容や Values で更新します。upgrade のたびにリビジョンが 1 ずつ増えます。リビジョン 1 の Release を upgrade するとリビジョン 2 になり、もう一度 upgrade するとリビジョン 3、というように進みます。Helm は新旧のリビジョンの差分を計算し、変わったリソースだけを更新します。values.yaml を変更してから upgrade すれば、その変更が Release に反映されます。

なお helm upgrade には --install(短縮 -i)というフラグがあり、helm upgrade --install と書くと「Release がなければ install、あれば upgrade」という動きになります。CI / CD パイプラインでは、初回も 2 回目以降も同じコマンドで済むこの書き方がよく使われます。

rollback — 前のリビジョンに戻す

helm rollback <release> <revision> は、Release を指定したリビジョンの内容に戻します。ここで重要なのが、rollback してもリビジョン番号は減らず、増えるという性質です。たとえばリビジョン 3 の Release を helm rollback fanclub-api 1 でリビジョン 1 の内容に戻すと、その「リビジョン 1 と同じ内容」はリビジョン 4として記録されます。

リビジョン番号は「何回目の状態変更か」を表すカウンタで、常に増え続けます。

この性質を図にすると次のようになります。

helm install   →  リビジョン 1(replicaCount: 1)
helm upgrade   →  リビジョン 2(replicaCount: 2)
helm rollback 1 →  リビジョン 3(中身はリビジョン 1 = replicaCount: 1)

リビジョン:   1 ──→ 2 ──→ 3
内容:        rc1   rc2   rc1(リビジョン1をコピーした版)

「リビジョン 1 に戻したのにリビジョン 3 になる」のは直感に反しますが、こうすることで「いつ rollback したか」も履歴に残り、後から helm history で操作の流れを追えます。rollback の <revision> 引数は「戻し先のリビジョン番号」であり、「これから付くリビジョン番号」ではない点を覚えておいてください。これを取り違えると、意図しない版に戻す事故につながります(H2「現場ヒヤリハット」①で扱います)。

uninstall — Release を削除する

helm uninstall <release> は、Release を削除します。その Release が作ったリソース(Deployment / Service など)がクラスタから削除され、Release の情報も消えます。uninstall した Release は helm rollback で復活できません。uninstall でリビジョン履歴も削除されるため、戻し先のリビジョンが存在しなくなるからです。

例外として、helm uninstall --keep-history--keep-history フラグを付けると、リソースは削除しつつリビジョン履歴だけ残せます。この場合は後から helm rollback で復活できます。ただしデフォルトの helm uninstall は履歴も消すため、「uninstall = 取り消せない最終操作」と捉えて運用するのが安全です。

helm history — リビジョン履歴を確認する

helm history <release> は、Release のリビジョン履歴を一覧表示します。各リビジョンが「いつ・どういう操作で・どの Chart バージョンになったか」を表で出します。helm rollback する前には必ず helm history で戻し先のリビジョン番号を確認するのが鉄則です。helm history はあくまで「確認」のコマンドで、リビジョンを変更したりはしません。演習③でこの一連の流れを実機で確認します。

やってみよう③: upgrade / rollback / uninstall フルサイクル

演習③では、演習②で作った fanclub-api Release を upgrade / rollback / uninstall して、Helm のライフサイクルを一周します。所要時間の目安は 25 分です。values.yamlreplicaCount を変更して upgrade し、helm history でリビジョンを確認し、rollback で戻し、最後に uninstall と Namespace 削除でクリーンアップします。

Step 1: values.yaml の replicaCount を 1 から 2 に変更する

Chart の values.yaml を編集し、先頭の replicaCount1 から 2 に変更します。実行コマンド(変更後の確認):

$ cd ~/fanclub-charts/fanclub-api
$ head -n 1 values.yaml

期待される実行結果:

replicaCount: 2

テキストエディタで values.yaml を開き、replicaCount: 1 の行を replicaCount: 2 に書き換えます。他の値は変更しません。この変更を upgrade で Release に反映します。

Step 2: helm upgrade でリビジョン 2 にする

変更した Chart で Release を upgrade します。実行コマンド:

$ cd ~/fanclub-charts
$ helm upgrade fanclub-api ./fanclub-api -n fanclub

期待される実行結果:

NAME: fanclub-api
LAST DEPLOYED: Sat May 16 11:18:09 2026
NAMESPACE: fanclub
STATUS: deployed
REVISION: 2
TEST SUITE: None

REVISION: 2 になりました。helm upgrade はリビジョンを 1 増やします。values.yamlreplicaCount を 2 に変えたため、Deployment の replica 数が 2 に更新されます。

Step 3: Pod が 2 つになったことを確認する

upgrade で replica 数が 2 になり、Pod が 2 つになったことを確認します。実行コマンド:

$ kubectl get pods -n fanclub

期待される実行結果:

NAME                                       READY   STATUS    RESTARTS   AGE
fanclub-api-fanclub-api-7d9c8f6b54-x2k8p   1/1     Running   0          13m
fanclub-api-fanclub-api-7d9c8f6b54-q7m4d   1/1     Running   0          50s

Pod が 2 つになり、両方とも 1/1 Running です。新しい方の Pod(q7m4d)の AGE が短く、upgrade で増えた Pod だと分かります。Helm が values.yaml の変更を読み取り、Deployment の replica 数を 2 に更新したことが確認できました。

Step 4: helm history でリビジョン 1・2 を確認する

helm history で、ここまでのリビジョン履歴を確認します。実行コマンド:

$ helm history fanclub-api -n fanclub

期待される実行結果:

REVISION  UPDATED                   STATUS      CHART              APP VERSION  DESCRIPTION
1         Sat May 16 11:05:42 2026  superseded  fanclub-api-1.0.0  0.1.0        Install complete
2         Sat May 16 11:18:09 2026  deployed    fanclub-api-1.0.0  0.1.0        Upgrade complete

リビジョン 1 と 2 が表示されました。STATUS 列を見ると、リビジョン 1 は superseded(後続のリビジョンに置き換えられた・過去の版)、リビジョン 2 は deployed(現在クラスタに出ている版)です。リビジョン 1 は replicaCount: 1 の状態、リビジョン 2 は replicaCount: 2 の状態を保持しています。DESCRIPTION 列でどの操作で生まれたリビジョンかも分かります。

Step 5: helm rollback でリビジョン 1 に戻す

Release をリビジョン 1(replicaCount: 1 の状態)に戻します。helm rollback の引数には戻し先のリビジョン番号を渡します。実行コマンド:

$ helm rollback fanclub-api 1 -n fanclub

期待される実行結果:

Rollback was a success! Happy Helming!

上記は Helm が出力する公式メッセージで、半角の感嘆符を含みますが、これは実機の出力をそのまま掲載しています。helm rollback fanclub-api 1 は「Release fanclub-api をリビジョン 1 の内容に戻す」という指示です。ここで戻し先として渡した 1 は、Step 4 の helm history で確認したリビジョン番号です。rollback の前に helm history でリビジョン番号を確認するのが鉄則です。

Step 6: history で 3 リビジョン・Pod が 1 つに戻ったことを確認する

rollback 後のリビジョン履歴と Pod 数を確認します。実行コマンド:

$ helm history fanclub-api -n fanclub
$ kubectl get pods -n fanclub

期待される実行結果(helm history の出力):

REVISION  UPDATED                   STATUS      CHART              APP VERSION  DESCRIPTION
1         Sat May 16 11:05:42 2026  superseded  fanclub-api-1.0.0  0.1.0        Install complete
2         Sat May 16 11:18:09 2026  superseded  fanclub-api-1.0.0  0.1.0        Upgrade complete
3         Sat May 16 11:24:31 2026  deployed    fanclub-api-1.0.0  0.1.0        Rollback to 1

期待される実行結果(kubectl get pods の出力):

NAME                                       READY   STATUS    RESTARTS   AGE
fanclub-api-fanclub-api-7d9c8f6b54-x2k8p   1/1     Running   0          19m

ここが本演習の山場です。helm history を見ると、リビジョンが 1・2・3 の 3 つになっています。helm rollback fanclub-api 1 でリビジョン 1 に戻したのに、履歴にはリビジョン 3 が増えています。これが「rollback してもリビジョン番号は減らず増える」性質です。リビジョン 3 の DESCRIPTIONRollback to 1 で、「リビジョン 1 の内容に戻した版」だと分かります。

リビジョン 3 の中身は replicaCount: 1 のため、kubectl get pods の出力では Pod が 1 つに戻っています。helm history のリビジョン番号と helm rollback の引数(戻し先)の関係をここで実機で確認できました。

Step 7: uninstall と Namespace 削除でクリーンアップする

演習で作った Release と Namespace をクリーンアップします。実行コマンド:

$ helm uninstall fanclub-api -n fanclub
$ kubectl delete namespace fanclub

期待される実行結果:

release "fanclub-api" uninstalled
namespace "fanclub" deleted

クリーンアップを確認します。実行コマンド:

$ helm list -n fanclub
$ kubectl get namespace

期待される実行結果:

NAME  NAMESPACE  REVISION  UPDATED  STATUS  CHART  APP VERSION

NAME                 STATUS   AGE
default              Active   12d
kube-node-lease      Active   12d
kube-public          Active   12d
kube-system          Active   12d
local-path-storage   Active   12d

helm list -n fanclub の出力が見出し行だけになり、Release fanclub-api が消えました。kubectl get namespace からも fanclub が消え、ep16 完了時点の 5 Namespace に戻りました。helm uninstall はデフォルトでリビジョン履歴も削除するため、この Release はもう helm rollback で復活できません。

これで演習③は完了し、Helm のライフサイクル(install → upgrade → rollback → uninstall)を一周しました。default ns の既存 fanclub-api と 6 個の NetworkPolicy には一切触れず、新 ns fanclub でクリーンに演習を完結できました。

CKAD 試験頻出パターン — Helm の速攻操作

本回で扱った Helm が、CKAD 試験でどう問われるかを整理します。CKAD は実技試験で、制限時間内に多くの設問を解く必要があるため、Helm の操作も「速攻で書ける」状態にしておくことが得点につながります。

頻出パターン 4 選

#設問のキーワード解答コマンド
1「指定のリポジトリから既存 Chart を install せよ」helm repo add <name> <url>helm repo updatehelm install <release> <repo>/<chart>
2「Chart のテンプレート展開結果を確認せよ」helm template <release> <chart> または helm install ... --dry-run
3「Release を前のリビジョンに戻せ」helm history <release> でリビジョン確認 → helm rollback <release> <rev>
4「values を上書きして install せよ」helm install <release> <chart> --set key=value または -f custom-values.yaml

パターン 1 は CKAD で最頻出の形式です。「existing packages(既存のパッケージ)をデプロイする」という Competency そのもので、リポジトリの add → update → install の 3 ステップを覚えておきます。パターン 4 の値の上書きでは、設問が「replica 数を 3 にして install せよ」のように具体的な値を指定してくることが多く、その場合は --set replicaCount=3 のように --set で直接指定するのが速いです。

速攻コマンド早見表

やりたいことコマンド
リポジトリを登録helm repo add bitnami https://...
リポジトリのインデックス更新helm repo update
Chart を検索helm search repo <keyword>
Chart をインストールhelm install <release> <chart> -n <ns>
値を上書きしてインストールhelm install <release> <chart> --set key=value
適用せず展開だけ確認helm template <release> <chart>
Release 一覧helm list -n <ns>(全 ns なら -A
リビジョン履歴helm history <release> -n <ns>
前の版に戻すhelm rollback <release> <rev> -n <ns>
現在の Values を確認helm get values <release> -n <ns>
Release を削除helm uninstall <release> -n <ns>

CKAD 試験では kubernetes.io のドキュメントに加えて helm.sh/docs も参照が許可されています。Chart の values.yaml のどのキーを --set で上書きすればよいか迷ったときは、試験中に helm.sh/docs を開いて確認できます。

間違えやすい落とし穴 3 選

試験で時間と得点を失いやすい落とし穴を 3 つ整理します。

  • rollback のリビジョン取り違えhelm rollback の引数は「戻し先のリビジョン番号」です。helm history を見ずに番号を当てずっぽうで指定すると、意図しない版に戻します。rollback の前に必ず helm history でリビジョン一覧を確認します
  • --set の指定の迷子--set で上書きできるのは values.yaml に存在するキーです。階層は --set image.tag=0.2.0 のようにドットでつなぎます。キー名を間違えても Helm はエラーを出さず、ただ無視されることがあるため、helm get values で実際に反映された値を確認します
  • Namespace 指定漏れhelm install / upgrade / rollback / uninstall / list / history はすべて Namespace スコープです。-n <ns> を付け忘れると、意図しない Namespace(多くは default)を対象に操作してしまいます。試験では設問が指定する Namespace を -n で必ず明示します

現場ヒヤリハット 2 件

本回で扱った Helm が、本番運用中にどのような事故を引き起こすかを 2 件取り上げます。それぞれ「背景・事故・根本原因・解決策・本番ガードレール」の 5 点セットで整理します。どちらも Helm 運用で頻発する事故で、本回で学んだ「rollback 前の helm history 確認」と「helm get values での値確認」が、そのまま事故防止策になります。

ヒヤリハット ①: helm rollback のリビジョン取り違えで本番障害

背景:本番クラスタで運用しているアプリの Helm Release で、新機能を含む helm upgrade を実施したところ、upgrade 後のバージョンに不具合が見つかった。担当者は「直前の安定版に戻す」と判断し、helm rollback を実行することにした。このアプリはリリース頻度が高く、Release のリビジョンは既に 20 を超えていた。担当者は「直前の版に戻す」というつもりで helm rollback <release> 1 を実行した。

事故helm rollback <release> 1 は「リビジョン 1 の内容に戻す」という指示のため、Release が最初のインストール時点(リビジョン 1)の構成に戻ってしまった。リビジョン 1 は数ヶ月前の古い構成で、当時のイメージタグ・古い values.yaml・当時はまだ存在しなかった ConfigMap キーの状態だった。アプリは数ヶ月前の古いバージョンで起動し、その間に追加された機能や設定がすべて消えた。

DB スキーマは新しいまま、アプリだけ古い版に戻ったため、アプリが新しいスキーマを解釈できず起動エラーになり、本番サービスが停止した。担当者は「直前の安定版(リビジョン 21)」に戻したつもりだったが、実際には「最初の版(リビジョン 1)」に戻していた。

根本原因helm rollback の第 2 引数は「戻し先のリビジョン番号」であり、「1 = 1 つ前」という意味ではない。担当者は「rollback 1 で 1 つ前に戻る」と誤解していた。「直前の安定版」に戻したいなら、helm history でリビジョン一覧を確認し、安定版のリビジョン番号(この例ならリビジョン 21)を正確に指定する必要があった。helm history を確認せずに番号を思い込みで指定したことが直接の原因。

なお、引数を省略した helm rollback <release> は「1 つ前のリビジョン」に戻す動きになるが、担当者はこの仕様も把握していなかった。

解決策:緊急対応として、改めて helm history <release> でリビジョン一覧を確認し、不具合のあった upgrade の 1 つ前にあたる安定版のリビジョン番号を特定した。そのうえで helm rollback <release> <安定版のリビジョン番号> を実行し、正しい安定版に戻してサービスを復旧させた。

事後改善として、rollback 手順を「① 必ず helm history でリビジョン一覧を出力する ② 戻し先のリビジョン番号を出力から確認する ③ 確認した番号で helm rollback を実行する」の 3 ステップに固定し、手順書に明記した。

本番ガードレール

  • helm rollback の前には必ず helm history <release> -n <ns> を実行し、戻し先のリビジョン番号を出力で確認してから rollback する。番号の思い込みでの指定を手順書で禁止する
  • helm rollback の第 2 引数は「戻し先のリビジョン番号」であり「N 個前」ではない、という仕様をチーム内で周知する。1 つ前に戻したいだけなら、リビジョン番号を省略した helm rollback <release> を使う
  • 本番の rollback は、まず helm rollback <release> <rev> --dry-run で戻し先の内容を確認してから本実行する。--dry-run なら実際には変更されない
  • アプリと DB スキーマが連動するシステムでは、アプリだけを古い版に rollback するとスキーマ不整合で起動できないことがある。rollback の影響範囲(DB マイグレーションを含むか)を手順書のチェック項目にする
  • リリース頻度が高くリビジョン番号が大きいアプリでは、安定版のリビジョン番号を変更管理票やデプロイ記録に残し、緊急時に「どのリビジョンが安定版か」をすぐ参照できるようにする

ヒヤリハット ②: –set 上書きの繰り返しで設定が迷子になる

背景:本番クラスタで運用している Helm Release に対して、複数の担当者がそれぞれの判断で helm upgrade を実施していた。あるときは「replica 数を増やす」ために helm upgrade <release> <chart> --set replicaCount=5、別のときは「イメージタグを上げる」ために helm upgrade <release> <chart> --set image.tag=1.3.0 というように、毎回 --set でその時に変えたい値だけを指定して upgrade していた。

values.yaml 自体は Git で管理されていたが、--set での上書きは Git には反映されていなかった。

事故:ある担当者が「リソース上限を上げる」ために helm upgrade <release> <chart> --set resources.limits.memory=1Gi を実行したところ、本番の Pod の replica 数が 5 から 1 に減り、サービスが過負荷でレスポンス遅延を起こした。原因を調べると、--set はそのコマンドで指定した値「だけ」を上書きするのではなく、「指定しなかった値は Chart の values.yaml のデフォルトに戻る」動きだった。

過去に --set replicaCount=5 で 5 にしていた replica 数は、今回の upgrade で --set replicaCount を指定しなかったため、Chart の values.yaml のデフォルト値(replicaCount: 1)に戻ってしまった。複数担当者が --set をその場限りで使い続けた結果、「いま本番にどの値が効いているか」が誰にも分からない状態になっていた。

根本原因helm upgrade は、デフォルトでは前回の --set 上書きを引き継がない。upgrade のたびに「Chart の values.yaml + そのコマンドの --set」で Values 全体が再計算される。--set で指定しなかった値は前回の値を保持するのではなく、Chart のデフォルトに戻る。担当者は --set が「差分だけを当てる」ものだと誤解していた。

さらに、--set での変更が Git の values.yaml に書き戻されていなかったため、過去にどの値を --set で変えたかの記録がどこにも残っていなかった。

解決策:緊急対応として、helm get values <release> で「現在その Release に効いている Values」を出力し、本来あるべき replica 数を確認したうえで、正しい値で再 upgrade してサービスを復旧させた。事後改善として、本番の Helm 運用を「環境ごとの値はすべて values-prod.yaml に書き、Git で管理する。

upgrade は helm upgrade <release> <chart> -f values-prod.yaml で常に同じファイルを渡す」という方式に統一した。--set はコマンドラインでの一時的な上書きに限り、本番の恒久的な設定変更には使わないルールにした。なお、前回の --set を引き継ぎたい場合は --reuse-values フラグがあるが、これも値の出所が見えにくくなるため本番では使わない方針とした。

本番ガードレール

  • 本番の恒久的な設定は、環境ごとの values-<env>.yaml ファイルに書いて Git で管理する。helm upgrade は常に -f values-<env>.yaml でそのファイルを渡し、設定の出所を 1 箇所に固定する
  • --set は CLI での一時的な上書き(検証時など)に限定し、本番の恒久的な設定変更には使わない。--set で変えた値は次の upgrade で Chart のデフォルトに戻る、という仕様を周知する
  • upgrade の前に helm get values <release> -n <ns> で「現在その Release に効いている Values」を確認する。--all を付けると Chart のデフォルトを含む全 Values が見える
  • 本番の Helm 操作を ArgoCD などの GitOps ツールに任せ、Values の変更を必ず Git のコミットとして記録する。GitOps 化により「本番に効いている設定 = Git の状態」を保証できる(GitOps は第2巻 CKA で扱う内容のため、本巻内のリンクはありません)
  • upgrade のレビュー時に「--set での個別上書きが使われていないか」「values.yaml と実際の Release の Values に差分がないか」をチェック項目にする

2 件のヒヤリハットに共通するのは「Helm の Release は履歴と Values という状態を持つため、その状態を確認せずに操作すると意図しない結果になる」という性質です。helm rollback の前には helm history でリビジョンを確認し、helm upgrade の前後には helm get values で実際に効いている値を確認する。この「操作の前に状態を確認する」習慣が、本番の Helm 運用の肝になります。

Helm は生 YAML 運用より管理しやすい一方、リビジョンや Values という新しい状態を持つぶん、その状態を正しく読む力が必要になります。

ep17 完了後の模擬アプリ状態と ep18 への橋渡し

本回で、第6部「パッケージ管理 + HTTPS 公開」の最初の回として Helm を扱いました。fanclub-api は Helm Chart としてパッケージ化され、helm install 一発でデプロイできる状態になりました。

ep17 完了後のクラスタ状態

リソース状態
kind クラスタkind-control-plane Ready(v1.35.0)
Helm新規インストール(v4.1.4・/usr/local/bin/helm・演習①)
Namespace 一覧default / kube-node-lease / kube-public / kube-system / local-path-storage(合計 5 個・ep16 完了状態と同一)
演習用 Namespace fanclubuninstall + 削除済(演習③ Step 7・クラスタには残らない)
default ns の fanclub-apiep16 完了状態のまま(生 YAML 管理・本回の Helm 演習では一切触れていない)
default ns の NetworkPolicy6 個(ep16 から継続・本回では触れていない)
Helm Chart ~/fanclub-charts/fanclub-api/新規作成・手元に残す(Chart.yaml / values.yaml / templates/ 6 ファイル・Chart version 1.0.0)
~/demo-chart/演習①で生成した雛形(学習用・任意で削除可)

演習②・③で使った Namespace fanclub は、演習③ Step 7 で helm uninstallkubectl delete namespace を実行したため、クラスタには残っていません。default ns の既存 fanclub-api(生 kubectl apply 管理)と 6 個の NetworkPolicy は ep16 完了状態のままで、本回の Helm 演習の影響を受けていません。本回の演習は新 ns でクリーンに完結し、ep18 にきれいな状態を引き継ぎます。

Helm Chart ディレクトリは削除せず手元に残す

本回の成果物のうち、~/fanclub-charts/fanclub-api/ の Helm Chart ディレクトリは削除せず手元に残してください。このディレクトリには Chart.yaml / values.yaml と、templates/ 配下の 6 ファイル(deployment.yaml / service.yaml / configmap.yaml / secret.yaml / serviceaccount.yaml / _helpers.tpl)が入っており、fanclub-api を「テンプレート + values」の形でパッケージ化した第1巻の重要な成果物です。

模擬アプリの進捗としては「fanclub-api の Helm Chart 化完了(Chart version 1.0.0)」という状態になります。

このディレクトリを残すのは、次の ep18 でこの Chart を拡張するためです。ep18「Gateway API + Traefik + cert-manager で HTTPS 公開」では、本回で作った fanclub-api Chart の templates/ に、Gateway / HTTPRoute のテンプレートを追加していきます。fanclub-api をブラウザから HTTPS でアクセスできるようにする構成を、本回の Chart の上に積み増す形で進めます。

本回の演習③で Release を uninstall したのは「クラスタ上の Release」を消しただけで、ディスク上の Chart ディレクトリ(テンプレートのソース)はそのまま残ります。ep18 はこの Chart ディレクトリを起点にするため、~/fanclub-charts/fanclub-api/ は消さずに保管しておきます。

ep18 への橋渡し

第6部の 3 回(ep17〜ep19)のうち、本回で 1 回目を終えました。本回で fanclub-api は Helm Chart としてパッケージ化され、環境差分を values.yaml で吸収し、helm install / upgrade / rollback でリリース管理できる状態になりました。ただし、現時点では fanclub-api の Backend は ClusterIP Service で公開されているだけで、クラスタの外(ブラウザ)からアクセスする経路がありません。

次の ep18「Gateway API + Traefik + cert-manager で HTTPS 公開」では、本回で作った Helm Chart に Gateway API のリソース(Gateway / HTTPRoute)を追加し、Traefik を Gateway 実装として導入、cert-manager で TLS 証明書を発行して、fanclub-api をブラウザから https://fanclub.local で HTTPS アクセスできるようにします。第1巻完走マイルストーンである「読者がブラウザから CRUD 操作で動作を確認できる」状態に向けて、外部公開と HTTPS 化を進めます。

理解度チェック・第17回まとめ・次回予告・シリーズ一覧

理解度チェック(○×形式・9 問)

問 1:Helm の Chart は、K8s クラスタにインストールされた実体を指す。

問 2helm upgrade は、Release のリビジョン番号を 1 増やす。

問 3helm rollback でリビジョン 1 に戻すと、履歴上のリビジョン番号も 1 に戻る。

問 4values.yaml の値は、--set-f でインストール時に上書きできる。

問 5:Helm v4 は、Tiller というサーバーサイドコンポーネントを必要とする。

問 6helm template は、Chart をクラスタに適用せずにテンプレートの展開結果を表示する。

問 7helm lint は、Chart の構文エラーを検出する。

問 8:1 つの Chart から、異なる Release 名で複数回インストールできる。

問 9:デフォルトの helm uninstall をした Release は、helm rollback で復活できない。

解答

解答解説
問 1×Chart は K8s マニフェストのテンプレート集(パッケージそのもの)で、ディスク上のディレクトリ / .tgz として存在する。クラスタにインストールした実体は Release。両者の区別は CKAD 頻出
問 2helm upgrade はリビジョンを 1 増やす。リビジョン 1 を upgrade するとリビジョン 2 になる。リビジョンは状態変更の回数を表すカウンタ
問 3×rollback してもリビジョン番号は減らず増える。リビジョン 1 に戻す操作は「リビジョン 1 と同じ内容の新しいリビジョン」として記録される。本回演習③ Step 6 でリビジョン 1 に戻してリビジョン 3 になることを確認した
問 4values.yaml のデフォルト値は --set key=value(1 値ずつ)や -f custom-values.yaml(ファイル丸ごと)で上書きできる。優先順位は --set / -f > Chart 同梱の values.yaml
問 5×Tiller は Helm v2 のサーバーサイドコンポーネントで、v3 で廃止された。Helm v3 / v4 はクライアントのみで動作し、helm コマンドが直接 API Server と通信する。Helm v4 に Tiller は存在しない
問 6helm template は Chart のテンプレートを Values で展開し、生成される YAML を標準出力に表示する。クラスタには一切適用しないため、kind クラスタが動いていなくても実行できる
問 7helm lint は Chart の構文エラーや推奨事項からの逸脱を静的に検査する。[ERROR] があると install できない。[INFO] は推奨事項でエラーではない
問 8Chart は設計図で、Release はそこから作った実体。helm install fanclub-dev ./fanclub-apihelm install fanclub-staging ./fanclub-api のように Release 名を変えれば、1 つの Chart から複数の独立した Release を作れる
問 9デフォルトの helm uninstall はリビジョン履歴も削除するため、戻し先が存在せず helm rollback で復活できない。helm uninstall --keep-history で履歴を残せば rollback で復活できる

第17回まとめ

第17回では以下を実施しました。

  • Helm が Kubernetes のパッケージマネージャである役割を整理した。生 YAML を kubectl apply する運用が抱える 4 課題(環境ごとの値の手書き変更・リソース間の整合管理・バージョン管理・ロールバックの困難さ)と、Helm がテンプレート化・values.yaml での値の外部化・Release のリビジョン管理でそれぞれを解決する構造を明確にした。CKAD D2 で問われるのは「既存パッケージのデプロイ」という Helm 利用者としての操作能力であることを整理した
  • Helm の 4 概念(Chart / Release / Repository / Values)を整理した。「Repository から Chart を取得し、Values を与えて install すると Release が生まれる」という関係を図で示し、特に混同しやすい「Chart = パッケージそのもの」「Release = クラスタにインストールした実体」の区別と、1 つの Chart から複数の Release を作れる 1 対多の関係を明確にした
  • Helm v4 と v3 の違いを整理した。v2 → v3 で Tiller(サーバーサイドコンポーネント)が廃止され、v3 / v4 はクライアントのみで動作すること、v3 → v4 の変更(OCI 統合の標準化等)は利用者の基本操作にはほぼ影響しないことを確認した。Helm v4 のインストールはバイナリ tar.gz を直接取得する方式で行い、取得元として get.helm.sh を主・GitHub Releases を whitelist 未登録時の代替として併記した
  • 演習①で Helm v4.1.4 を k8s-ops VM にインストールし、helm version で v4.1.4 を確認した。helm create で Chart の雛形を生成し、Chart.yaml / values.yaml / templates/ / _helpers.tpl / .helmignore の構造を find で確認した。helm lint での構文チェックと helm template でのテンプレート展開を体験した
  • Chart の構造(Chart.yaml のメタデータ・values.yaml のデフォルト値・templates/ のテンプレート)を整理した。Chart.yamlapiVersion: v2 が Chart フォーマットのバージョンであること、version(Chart 自体のバージョン)と appVersion(梱包するアプリのバージョン)の使い分けを明確にした
  • テンプレート構文を整理した。.Valuesvalues.yaml の値)・.Release(Release 名 / Namespace 等)・.Chart(Chart のメタデータ)の組込オブジェクト、include によるヘルパー呼び出し、{{- if }} による条件分岐、quote / default / nindent のパイプ関数を示した。{{- のハイフンが直前の空白・改行を削除する記法(whitespace chomping)であることを補足した
  • 演習②で fanclub-api の Backend を題材に Helm Chart をゼロから作成した。Chart.yaml / values.yamltemplates/ 配下の 6 ファイル(deployment.yaml / service.yaml / configmap.yaml / secret.yaml / serviceaccount.yaml / _helpers.tpl)をテンプレート構文で記述し、helm lint / helm template で検証したうえで、新 Namespace fanclubhelm install ... --create-namespace でデプロイした。Init Container は initContainer.enabled: false で無効化し、DB を Chart スコープ外にした
  • helm のライフサイクル(install / upgrade / rollback / uninstall)とリビジョンの関係を整理した。install でリビジョン 1 が生まれ、upgrade でリビジョンが +1、rollback は戻し先の内容で新リビジョン +1、uninstall は Release とリビジョン履歴を削除すること、rollback してもリビジョン番号は減らず増える性質を明確にした
  • 演習③で fanclub-api Release のフルサイクルを実機で一周した。values.yamlreplicaCount を 1 → 2 に変えて helm upgrade(リビジョン 2)、helm history でリビジョンを確認、helm rollback fanclub-api 1 でリビジョン 1 に戻す(リビジョン 3 として記録)、helm uninstall + kubectl delete namespace でクリーンアップした。default ns の既存リソース・NetworkPolicy には一切触れず新 ns で完結させた
  • CKAD 試験 D2 の Helm 頻出パターン 4 選(既存 Chart の install / テンプレート展開確認 / 前の版への rollback / values 上書き)を解答コマンドとともに整理し、速攻コマンド早見表と落とし穴 3 選(rollback のリビジョン取り違え / --set の指定迷子 / Namespace 指定漏れ)を試験対策として示した
  • 現場ヒヤリハットを 2 件扱った。helm rollback のリビジョン番号を「N 個前」と誤解して最初の版に戻し本番障害を起こした事例、--set の繰り返しで指定しなかった値が Chart デフォルトに戻り設定が迷子になった事例を、5 点セット(背景・事故・根本原因・解決策・本番ガードレール)で整理した。「操作の前に helm history / helm get values で状態を確認する」習慣の重要性を再確認した
  • fanclub-api を Helm Chart 化(Chart version 1.0.0)した。~/fanclub-charts/fanclub-api/ の Chart ディレクトリは削除せず手元に残し、ep18 で Gateway / HTTPRoute テンプレートを追加する起点とすることを明示した

次回予告

第18回「Gateway API + Traefik + cert-manager で HTTPS 公開」では、本回で作った fanclub-api の Helm Chart に Gateway API のリソース(Gateway / HTTPRoute)を追加します。Gateway 実装として Traefik を導入し、cert-manager で TLS 証明書を発行して、fanclub-api をブラウザから https://fanclub.local で HTTPS アクセスできるようにします。

Gateway API は CKAD / CKA で 2026 年から出題範囲に入った新しいリソースで、従来の Ingress に代わる Kubernetes 標準のトラフィック制御 API です。本回の Helm Chart を起点に、外部公開と HTTPS 化を進め、第1巻完走マイルストーン「読者がブラウザから CRUD 操作で動作を確認できる」状態に近づきます。

シリーズ一覧

第1部:コンテナと Docker

第2部:Kubernetes 基礎

第3部:アプリリソース

第4部:ワークロード戦略

第5部:セキュリティ基礎

第6部:パッケージ管理 + HTTPS 公開

広告
kubernetes
スポンサーリンク