Share on

投稿日:
更新日:

Kubernetes の Kustomize に入門する

はじめに

Kubernetes でアプリケーションを運用しているとマニフェストの管理が課題になってきます。

サービスの規模が拡大するにつれて、Deployment、Service、ConfigMap、Ingress といった管理対象のリソースは増え続けます。 さらに、開発環境・ステージング環境・本番環境といった複数のステージを運用している場合、ベースとなる設定は共通でありながら、レプリカ数やリソースの Request / Limit、環境変数、イメージタグ等は環境毎に微妙に異なる設定を管理する必要が出てきます。

このような状況で、環境毎にマニフェストを丸ごとコピーして管理してしまうと、共通部分の変更を全環境に反映する手間が増え、設定の不整合やオペレーションミスを招きやすくなります。

上の図のように、Kustomize を使わない場合は環境毎にほぼ同じマニフェストをコピーして管理することになり、共通部分に変更が入った際に全環境のファイルを手動で修正する必要があります。

Kustomize はこうしたマニフェスト管理の課題を解決するためのツールです。 今回のブログでは、Kustomize の基本概念から主要機能の使い方まで、実際のマニフェストを交えて紹介したいと思います。

Kustomize とは

Kustomize は Kubernetes のマニフェストをテンプレートを用いずにカスタマイズするためのツールです。 kubectl v1.14 以降では kubectl に統合されており、kubectl kustomizekubectl apply -k コマンドとしてそのまま利用することができます。

Kustomize の特徴

Kustomize には以下のような特徴があります。

テンプレートレス

  • Helm のようなテンプレートエンジンを使用せず、素の Kubernetes マニフェストをそのまま扱う

宣言的なオーバーレイ

  • ベースとなるマニフェストに対して、差分(パッチ)を宣言的に重ねることでカスタマイズを実現する

kubectl との統合

  • 追加のツールやインストールを必要とせず、kubectl のサブコマンドとして利用できる

YAML ネイティブ

  • Go テンプレートのような独自の構文を覚える必要がなく、純粋な YAML で記述できる

Helm との違い

Kubernetes のマニフェスト管理ツールとして Helm も広く利用されています。 Helm はパッケージマネージャーで、Kustomize とはアプローチが異なるため、ユースケースに応じて使い分けるのが一般的です。

KustomizeHelm
アプローチオーバーレイ方式(差分を重ねる)テンプレートエンジン方式(変数を埋め込む)
学習コスト低い(素の YAML + パッチ)やや高い(Go テンプレート構文の習得が必要)
パッケージング無し(ディレクトリ構成で管理)Chart としてパッケージング・配布が可能
依存管理無しChart 間の依存関係を定義可能
リリース管理無しリリースの履歴管理・ロールバックが可能
kubectl 統合kubectl apply -k で直接適用できるhelm install / helm upgrade コマンドを使用
ユースケース環境差分の管理、シンプルなカスタマイズ複雑なアプリケーションの配布・パッケージング

Helm はサードパーティの Chart を利用してアプリケーションをデプロイする場合や、複雑なテンプレートロジックが必要な場合に適しています。

一方の Kustomize は自前のマニフェストを環境毎に少しずつカスタマイズしたいケースにおいて、シンプルかつ直感的に利用できます。

両者は排他的ではなく、Kustomize と Helm を組み合わせて利用する構成(Kustomize on Helm)がよく見られます。

kustomize-on-helm.png

基本概念

Kustomize を理解する上で、basesoverlays を分離するという概念が重要になります。

kustomize-overview.png

bases

  • 各環境で共通となるマニフェストの定義を記述する
  • Deployment、Service、ConfigMap 等の基本的なリソース定義を配置する

overlays

  • 環境固有の差分を記述する
  • bases の設定を継承しつつ、レプリカ数、環境変数、リソースの制約値といった環境毎に異なる設定を上書き・追加する

以下は、bases と overlays がどのようにマージされ、環境毎のマニフェストが生成されるかを示しています。

bases のマニフェストをそのまま apply すれば本番環境のリソースが構築され、overlays の差分を適用することで開発環境やステージング環境に対応したリソースが生成されます。

ここで、何を bases に含め、何を overlays で上書きするかは開発者やチームの方針次第 です。 bases で定義していない項目を overlays に追加することも、bases で定義した項目を overlays で上書きすることもできます。

いずれの場合も、kustomization.yaml というファイルを軸に操作を行います。

ディレクトリ構成

Kustomize を利用する際の一般的なディレクトリ構成は以下のようになります。

  • bases/ ディレクトリには環境を問わず共通のマニフェストと kustomization.yaml を配置する
  • overlays/ ディレクトリの下に環境毎のサブディレクトリ(development/staging/production/)を用意し、それぞれの差分を管理する
  • 各ディレクトリには必ず kustomization.yaml が必要(Kustomize はこのファイルを読み込んでビルドする)

インストールと基本コマンド

インストール

Kustomize は kubectl v1.14 以降に統合されているため、kubectl を利用している場合は追加のインストールは不要です。

スタンドアロン版の Kustomize を利用する場合は、以下のコマンドでインストールできます。

基本コマンド

Kustomize の主なコマンドは build です。 kustomize build は、指定したディレクトリの kustomization.yaml を読み込み、最終的なマニフェストを stdio に出力します。

ビルド結果をクラスタに適用する場合は、パイプで kubectl apply に渡すか、kubectl apply -k を使用します。

build の対象となるのは、ファイルではなくディレクトリ です。 正確には、kustomization.yaml が配置されているディレクトリを指定します。

こちらの図では kustomize build から kubectl apply までのデータフローを示しています。

環境毎のマニフェスト管理

ここからは、実際に Kustomize を使って環境毎のマニフェスト管理を行う手順を紹介します。

bases の作成

まず、ベースとなるマニフェストを作成します。

  • kustomization.yaml

bases/kustomization.yaml では、管理対象のリソースを resources フィールドで指定します。

bases/kustomization.yaml

commonLabels を指定すると、管理対象の全リソースに共通のラベルが付与されます。

  • deployment.yaml
bases/deployment.yaml
  • service.yaml
bases/service.yaml

bases の build 結果

この時点で kustomize build を実行すると、bases の内容が出力されます。

kustomization.yaml で指定した commonLabels が全リソースのメタデータに反映されていることが確認できます。 この出力結果がそのまま kubectl apply に渡せるマニフェストになります。

overlays の作成

次に、環境毎の差分となる overlays を作成します。

ステージング環境

ステージング環境では、レプリカ数を 2 に増やし、リソースの Request / Limit を本番に近い値に調整します。

overlays/staging/kustomization.yaml

resources フィールドで bases ディレクトリを参照し、patches フィールドで差分となるパッチファイルを指定します。

overlays/staging/patches/replica.yaml

パッチファイルでは、apiVersionkindmetadata.name を bases のリソースと一致させる必要があります。 Kustomize はこれらのフィールドをキーとしてマージ対象のリソースを特定します。

ステージング環境のマニフェストを build してみます。

bases の設定を受け継ぎつつ、overlays で指定したレプリカ数やリソースの値が反映されていることが確認できます。

開発環境

開発環境では、レプリカ数を 1 のまま、リソースの制約値を最小限に設定します。

overlays/development/kustomization.yaml
overlays/development/patches/replica.yaml

build すると、開発環境用の設定が反映されたマニフェストが出力されます。

このように、bases を共通のベースとして維持しつつ、overlays で環境毎の差分だけを管理することで、マニフェストの重複を排除し、変更の追従を容易にすることができます。

クラスタへの適用

Kustomize で生成したマニフェストをクラスタに適用するには、以下のように実行します。

Kustomize の主要機能

ここまでは bases と overlays の基本的な使い方を紹介しました。 Kustomize には、マニフェストのカスタマイズを効率化するための機能が多数用意されています。

ここでは、実運用でよく利用される主要な機能を紹介します。

patches

patches は、既存のリソースに対して部分的な変更を適用するための機能です。 前述の overlays で使用した方法がこれに該当します。

Kustomize では、以下の 2 種類のパッチ方式がサポートされています。

Strategic Merge Patch

Strategic Merge Patch は、Kubernetes ネイティブのマージ戦略に従ってリソースをマージする方式です。 先ほどの例で使用したのがこの方式になります。

パッチファイルには、変更したいフィールドだけを記述します。 apiVersionkindmetadata.name でマージ対象のリソースを特定し、指定したフィールドが上書きされます。

  • strategic merge patch の例

JSON Patch(RFC 6902)

JSON Patch は、リソースに対する変更操作を op(操作)、path(対象パス)、value(値)の 3 要素で明示的に指定する方式です。 Strategic Merge Patch では表現しにくい、配列内の特定要素の変更や削除等に適しています。

  • kustomization.yaml での JSON Patch の指定

target でパッチ対象のリソースを指定し、patch フィールドに JSON Patch の操作を YAML 形式で記述します。

configMapGenerator

configMapGenerator は、kustomization.yaml 内で ConfigMap を宣言的に生成するための機能です。 ConfigMap のマニフェストファイルを別途作成する必要がなく、ファイルやリテラル値から直接 ConfigMap を生成できます。

ファイルから生成

kustomization.yaml

リテラル値から生成

kustomization.yaml

env ファイルから生成

kustomization.yaml

Kustomize の configMapGenerator で生成された ConfigMap には、デフォルトでコンテンツのハッシュ値がサフィックスとして付与されます。(例:app-config-k5m8h2f9) このハッシュサフィックスにより、ConfigMap の内容が変更された際に新しい名前の ConfigMap が生成され、Deployment のローリングアップデートが自動的にトリガされます。

ハッシュサフィックスを無効化したい場合は、generatorOptions で設定することができます。

kustomization.yaml

secretGenerator

secretGeneratorconfigMapGenerator と同様の使い方で Secret リソースを生成します。

kustomization.yaml

ファイルからの生成にも対応しています。

kustomization.yaml

GitOps 環境での Secret 管理

secretGenerator はリテラル値やファイルから Secret を生成できますが、GitOps で運用している場合、Secret の平文を Git リポジトリにコミットすることはセキュリティ上避ける必要があります。

この課題に対しては、以下のようなアプローチが一般的に採用されています。

アプローチ概要
Sealed Secretsクラスタ側の公開鍵で暗号化した SealedSecret リソースを Git に格納し、クラスタ内のコントローラが復号して Secret を生成する
External Secrets OperatorAWS Secrets Manager や Google Cloud Secret Manager 等の外部シークレットストアから Secret を動的に取得する
SOPS + KSOPSSOPS で暗号化したファイルを Git に格納し、Kustomize のプラグインとして復号する

いずれの方式でも、Kustomize の secretGenerator を直接使うのではなく、上記のツールが Secret リソースの生成を担う構成になります。 GitOps で Kustomize を利用する場合は、Secret の管理方針をチームで事前に決めておくことが重要です。

namespace

namespace フィールドを指定すると、管理対象の全リソースに対して Namespace が一括で設定されます。

overlays/staging/kustomization.yaml

これにより、環境毎に異なる Namespace へリソースをデプロイする構成が容易に実現できます。

namePrefix / nameSuffix

namePrefix および nameSuffix を使用すると、管理対象の全リソース名に対してプレフィクスやサフィックスを一括付与できます。

kustomization.yaml

上記の設定により、my-app という名前のリソースは staging-my-app-v2 に変換されます。 環境名やバージョンをリソース名に含めたい場合に便利です。

commonLabels / commonAnnotations

commonLabelscommonAnnotations は、管理対象の全リソースに共通のラベルやアノテーションを一括付与する機能です。

kustomization.yaml

commonLabels は、メタデータだけでなく、Deployment の spec.selector.matchLabels や Service の spec.selector にも自動的に反映されます。 この動作により、ラベルの一貫性が保たれる一方、既にデプロイ済みのリソースに対して commonLabels を変更すると selector の不整合が発生する可能性があるため注意が必要です。

images

images フィールドを使用すると、マニフェスト内のコンテナイメージを一括で変更できます。 Deployment や StatefulSet 等のリソースに記述されたイメージ名やタグを、パッチファイルを作成せずに書き換えることが可能です。

kustomization.yaml

上記の設定により、bases で nginx:1.23 と指定されているイメージが my-registry.example.com/nginx:1.23 に置き換えられます。

CI/CD パイプラインからイメージタグを動的に更新する場合にも、kustomize edit set image コマンドと組み合わせることで活用できます。

replicas

replicas フィールドを使用すると、パッチファイルを作成せずにレプリカ数を直接変更できます。

kustomization.yaml

name には対象の Deployment や StatefulSet の名前を指定し、count で所望するレプリカ数を設定します。

kustomization.yaml のフィールド一覧

ここまで紹介した機能を含め、kustomization.yaml で利用可能な主要フィールドを以下にまとめておきます。

フィールド説明
resources管理対象のマニフェストファイルや他の kustomization を参照
patchesStrategic Merge Patch または JSON Patch を適用
configMapGeneratorConfigMap をファイルやリテラル値から生成
secretGeneratorSecret をファイルやリテラル値から生成
namespace全リソースに Namespace を一括設定
namePrefix全リソース名にプレフィクスを一括付与
nameSuffix全リソース名にサフィックスを一括付与
commonLabels全リソースに共通ラベルを一括付与
commonAnnotations全リソースに共通アノテーションを一括付与
imagesコンテナイメージの名前・タグを一括変更
replicasレプリカ数を直接変更
generatorOptionsconfigMapGenerator / secretGenerator の動作オプション
replacementsリソース間で値を参照・置換

まとめ

今回のブログでは、Kustomize の基本概念から主要機能の使い方まで、実際のマニフェストを交えて紹介してみました。

Kustomize は、bases と overlays という仕組みでベースとなるマニフェストと環境固有の差分を分離し、マニフェストの重複や管理コストを削減してくれます。 テンプレートエンジンを使用しないため、素の Kubernetes マニフェストの知識がそのまま活かせる点は認知負荷の考慮という点で Pros だと思います。

また、patches、configMapGenerator、images といった機能を活用することで、環境毎のカスタマイズを柔軟に行うことができます。 kubectl v1.14 以降ではネイティブに統合されているため、追加のツールやインストールをすることなく、サブコマンドとしてすぐに利用することができます。

Kubernetes のマニフェスト管理で環境差分に課題を感じている場合は、まず小さな構成から Kustomize を導入してみると良いでしょう。

参考・引用