Certified Kubernetes Application Developer (CKAD) #10 Kustomize: overlay パターン、環境別マニフェスト
#9 Helm ではチャートと values で同じアプリケーションを環境別にデプロイする方法を身につけました。Helm がテンプレートエンジンでマニフェストを刷り出すツールだとすれば、Kustomize は正反対のアプローチです。純粋な YAML をそのまま残し、その上に変形ルールだけを被せて 環境別マニフェストを作り出します。テンプレート構文や {{ }} のような置換マークが一切ないため、base マニフェストはそれ自体で kubectl apply が通る正常な YAML です。
Kustomize が CKAD で特に重要な理由は kubectl に内蔵 されている点です。別途バイナリをインストールせずに kubectl apply -k、kubectl kustomize ですぐ使えるため、試験環境で追加のセットアップが要りません。今回の記事では kustomization.yaml の中核フィールド、base/overlays 構造、パッチと生成器、そしてビルド・適用の流れを実技の視点で整理します。
Kustomize が解く問題 #
同じアプリケーションを dev・staging・prod にデプロイするとき、環境ごとに違うのはたいてい一部のフィールドだけです。replica 数、イメージタグ、ネームスペース、ConfigMap の値くらいが異なり、残りの構造は同一です。この差を扱う方法は 2 つに分かれます。
- コピーしてから修正。環境別にマニフェストを丸ごと複製すると、共通部分を直すたびにすべての複製を追いかけて直す必要があります。漏れがそのまま事故につながります。
- 変形ルールの分離。共通マニフェスト (base) を 1 セットだけ置き、環境別の差は小さなパッチ (overlay) だけで記述します。共通部分は base 一箇所だけで管理されます。
Kustomize は後者です。base をそのまま残し、overlay がその上に変形を被せるため、環境間の重複が消えます。
kustomization.yaml の中核フィールド #
Kustomize のすべての動作は kustomization.yaml ファイル 1 つに宣言されます。このファイルがあるディレクトリがビルド単位です。よく使うフィールドを先に整理します。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# 1) 入力リソース (YAML ファイルまたは別の kustomize ディレクトリ)
resources:
- deployment.yaml
- service.yaml
# 2) すべてのリソースにネームスペースを一括指定
namespace: my-app
# 3) 名前の前後に接頭辞/接尾辞を付与
namePrefix: dev-
nameSuffix: -v1
# 4) すべてのリソースにラベル/アノテーションを共通付与
commonLabels:
app: web
env: dev
commonAnnotations:
team: platform
# 5) イメージタグ/名前を差し替え (マニフェストを触らずに)
images:
- name: nginx
newName: nginx
newTag: "1.27"
# 6) Deployment などの replica 数を差し替え
replicas:
- name: web
count: 4各フィールドの役割は次のとおりです。
| フィールド | 役割 |
|---|---|
resources | ビルドに含めるマニフェストまたは下位 kustomize ディレクトリ |
namespace | 対象リソース全体にネームスペースを適用 |
namePrefix / nameSuffix | リソース名に接頭辞・接尾辞を付与 (参照も併せて更新) |
commonLabels | すべてのリソースの metadata.labels と selector にラベルを追加 |
commonAnnotations | すべてのリソースにアノテーションを追加 |
images | コンテナイメージの名前・タグをビルド時点で差し替え |
replicas | 指定したワークロードの replica 数を差し替え |
commonLabels は単にラベルを付けるだけでなく、Deployment の selector.matchLabels と Pod テンプレートのラベルまで併せて揃えてくれます。そのため selector を手で直すときに生じる不一致の事故を防いでくれます。
base と overlays 構造 #
実務と試験で最もよくある形は、base ディレクトリ 1 つと環境別 overlay ディレクトリに分ける構造です。
myapp/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ └── service.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ └── replica-patch.yaml
└── prod/
├── kustomization.yaml
└── replica-patch.yamlbase/kustomization.yaml は共通リソースを集めます。
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml各 overlay の kustomization.yaml は resources にファイルの代わりに base ディレクトリのパス を書きます。すると base のすべてのリソースを引き込んだうえで、同じファイルに書かれた変形ルールとパッチをその上に被せます。
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base # base を丸ごと参照
namespace: prod
namePrefix: prod-
replicas:
- name: web
count: 6こうしておくと base は 1 セットだけ維持され、dev・prod はそれぞれ必要な差だけを宣言します。base の deployment.yaml を直せば 2 つの環境に同時に反映されます。
パッチ: 一部フィールドだけ上書き #
namePrefix や replicas のような専用フィールドで表現できない変更はパッチで処理します。パッチは base の特定フィールドだけを選んで上書きする小さな断片です。2 つの方式があります。
patchesStrategicMerge (戦略的マージ) #
元と同じ形の部分 YAML を書くと、Kustomize が同じキーを見つけてマージします。人が読みやすいため最もよく使われます。
# overlays/prod/resource-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web # どのリソースをパッチするか識別
spec:
template:
spec:
containers:
- name: web
resources:
limits:
memory: 512Mi# overlays/prod/kustomization.yaml の一部
patchesStrategicMerge:
- resource-patch.yamlmetadata.name と kind で対象リソースを識別し、明示したフィールド (ここでは resources.limits.memory) だけが base の上に被ります。残りのフィールドは base の値をそのまま維持します。
patches (JSON6902) #
配列要素を狙い撃ちで追加・削除したり、特定パスの値を精密に変えたりするときは JSON6902 パッチが適しています。op (add・replace・remove) と path で動作を指定します。
# overlays/prod/kustomization.yaml の一部
patches:
- target:
kind: Deployment
name: web
patch: |-
- op: replace
path: /spec/replicas
value: 6
- op: add
path: /spec/template/spec/containers/0/env/-
value:
name: LOG_LEVEL
value: infotarget で対象を選び、patch の中に演算のリストを書きます。path の /- は配列の末尾に追加せよという表記です。戦略的マージでは表現しにくい精密な操作に使います。
生成器: ConfigMap と Secret の自動生成 #
Kustomize は ConfigMap と Secret をマニフェストで直接書かずに 生成器 で作ることができます。生成器の中核的な価値は 内容ハッシュ接尾辞 です。
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=info
- TIMEOUT=30
files:
- app.properties # ファイルの内容をそのまま ConfigMap に積載
secretGenerator:
- name: app-secret
literals:
- PASSWORD=s3cr3t生成器で作った ConfigMap は app-config-7h8d9f2k4m のように 内容から計算したハッシュが名前の後ろに付きます。内容が変わるとハッシュが変わって名前が変わり、これを参照する Deployment の Pod テンプレートも新しい名前を指すよう自動的に更新されます。その結果、ConfigMap の値を変えると Pod が自動的にローリングアップデート されます。
これは手で書いた ConfigMap の宿命的な問題を解決します。ConfigMap だけ変えると既存の Pod は変更を知らないまま古い値で動き続けますが、生成器は名前変更で強制ローリングを誘発するからです。ハッシュ接尾辞を切りたい場合は次を追加します。
generatorOptions:
disableNameSuffixHash: trueビルドと適用 #
Kustomize の出力は kubectl kustomize で事前に確認できます。クラスタに何も適用せず 最終マージ結果の YAML だけを標準出力に 吐き出します。
# ビルド結果を出力のみ (適用しない)
k kustomize overlays/prod
# ファイルに保存して検討
k kustomize overlays/prod > /tmp/prod-rendered.yaml検討が終わったら -k フラグですぐ適用します。ディレクトリのパス (kustomization.yaml がある場所) を引数に渡します。
# overlay をビルドしてクラスタに適用
k apply -k overlays/prod
# 適用前に変更内容を比較
k diff -k overlays/prod
# 削除も同じく -k で
k delete -k overlays/prod試験では常に k kustomize で先に結果を確認してから k apply -k する順序を勧めます。パッチが意図どおりにマージされたか、namePrefix が selector の参照まで更新したかを、適用前に目で検証できるからです。
Helm との違い #
#9 Helm と Kustomize は同じ問題を別の方式で解きます。Helm は テンプレートに変数を置換 してマニフェストを生成し、Kustomize は 完成した YAML の上にオーバーレイで変形 を被せます。Helm はパッケージング・配布・ロールバック・依存関係まで含むパッケージマネージャーであり、Kustomize はマニフェスト変形に集中した軽量なツールです。この 2 つのツールは排他的ではないため、Helm チャートの出力を Kustomize でもう一度変形する組み合わせも可能です。
全体の例: base + dev overlay #
ここまでの要素をまとめて base 1 セットと dev overlay 1 つを完成させてみます。
まず base です。
# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
envFrom:
- configMapRef:
name: app-config# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yamldev overlay は base を参照しながら、namePrefix の付与、replica 数のパッチ、ConfigMap の生成をまとめて宣言します。
# overlays/dev/replica-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 2# overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: dev
namePrefix: dev-
commonLabels:
env: dev
patchesStrategicMerge:
- replica-patch.yaml
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=debug
- TIMEOUT=10これでビルド結果を確認して適用します。
# マージ結果を確認
k kustomize overlays/dev
# 適用
k apply -k overlays/devビルド結果では Deployment 名が dev-web、ConfigMap 名が dev-app-config-<ハッシュ> に変わり、envFrom の参照も同じハッシュ名を指すよう自動更新されます。replica はパッチで 2 になり、すべてのリソースに env: dev ラベルが付きます。base マニフェストは 1 行も直接直していません。
試験ポイント #
- kubectl 内蔵。Kustomize は別途インストールなしで
k apply -k <ディレクトリ>、k kustomize <ディレクトリ>ですぐ使えます。-kの引数はファイルではなく kustomization.yaml がある ディレクトリ です。 - ビルドプレビュー。
k kustomize <ディレクトリ>はクラスタを触らずに最終マージ YAML を出力します。適用前に検証する習慣をつけます。 - resources が base を指す。overlay の
resourcesに base ディレクトリのパスを入れると base 全体を引き込んだうえで変形を被せます。 - patchesStrategicMerge vs patches。同じ形で一部フィールドを上書きすれば戦略的マージ、配列要素を狙い撃ちで add・remove・replace すれば JSON6902 です。
- 生成器のハッシュローリング。configMapGenerator・secretGenerator は内容ハッシュを名前に付け、値が変わると Pod が自動ローリングします。防ぐには
disableNameSuffixHash: trueを使います。 - commonLabels は selector まで更新する。ラベルを手で付けるときと違い selector の不一致が生じません。
まとめ #
この記事で押さえたこと:
- Kustomize はテンプレートなしのオーバーレイ方式。base の純粋な YAML をそのまま残し、変形ルールだけを被せて環境別マニフェストを作ります。
- kustomization.yaml の中核フィールド。resources、namespace、namePrefix・nameSuffix、commonLabels・commonAnnotations、images、replicas。
- base/overlays 構造。base を 1 セット置き、overlay が base を参照して環境別の差だけを宣言します。
- パッチの 2 種類。patchesStrategicMerge (部分 YAML マージ) と patches (JSON6902 精密操作)。
- 生成器。configMapGenerator・secretGenerator のハッシュ接尾辞により、値の変更時に自動ローリングします。
- ビルド・適用。
k kustomizeで事前に見てk apply -kで適用します。
次へ: Probes #
デプロイツールの束 (Helm・Kustomize) を終えました。次はデプロイしたアプリケーションが生きているか、トラフィックを受ける準備ができたかを Kubernetes に伝える信号に移ります。
#11 Probes: liveness、readiness、startup (exec/HTTP/TCP) では、3 種類の probe の役割の違い、exec・HTTP・TCP の 3 つの検査方式、initialDelaySeconds・periodSeconds・failureThreshold のようなタイミングパラメータ、そして試験によく出る「probe 設定が間違って Pod が再起動し続ける」タイプまで、実際に作りながら整理します。