Certified Kubernetes Application Developer (CKAD) #10 Kustomize: overlay パターン、環境別マニフェスト

#9 Helm ではチャートと values で同じアプリケーションを環境別にデプロイする方法を身につけました。Helm がテンプレートエンジンでマニフェストを刷り出すツールだとすれば、Kustomize は正反対のアプローチです。純粋な YAML をそのまま残し、その上に変形ルールだけを被せて 環境別マニフェストを作り出します。テンプレート構文や {{ }} のような置換マークが一切ないため、base マニフェストはそれ自体で kubectl apply が通る正常な YAML です。

Kustomize が CKAD で特に重要な理由は kubectl に内蔵 されている点です。別途バイナリをインストールせずに kubectl apply -kkubectl 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.yaml

base/kustomization.yaml は共通リソースを集めます。

# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - deployment.yaml
  - service.yaml

各 overlay の kustomization.yamlresources にファイルの代わりに 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 つの環境に同時に反映されます。

パッチ: 一部フィールドだけ上書き #

namePrefixreplicas のような専用フィールドで表現できない変更はパッチで処理します。パッチは 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.yaml

metadata.namekind で対象リソースを識別し、明示したフィールド (ここでは 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: info

target で対象を選び、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.yaml

dev 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 つの検査方式、initialDelaySecondsperiodSecondsfailureThreshold のようなタイミングパラメータ、そして試験によく出る「probe 設定が間違って Pod が再起動し続ける」タイプまで、実際に作りながら整理します。

X