Kustomize入門:テンプレートなしでKubernetes設定をカスタマイズ
はじめに:Kubernetes設定の複雑性とKustomizeの登場
Kubernetesは現代のクラウドネイティブアプリケーション開発において不可欠なプラットフォームですが、その強力さの裏には設定の複雑さが潜んでいます。Deployment、Service、ConfigMap、Secret、Ingressといった多種多様なリソースを組み合わせることでアプリケーションを定義しますが、これらのYAMLファイルは環境(開発、ステージング、本番など)、チーム、あるいはデプロイされるたびに微妙に異なる場合があります。
このような状況で、Kubernetesの設定管理には以下のような課題が浮上します。
- 環境ごとの差分管理: 同じアプリケーションであっても、開発環境ではリソースが少なく、本番環境ではレプリカ数が多い、異なるイメージタグを使用するといった違いが生じます。これらの差分をどのように効率的かつ安全に管理するかが問題となります。
- 設定の一貫性: 複数の環境で設定が分散し、手作業で変更が加えられると、設定の一貫性が失われ、いわゆる「設定のずれ(Configuration Drift)」が発生しやすくなります。
- 再利用性と抽象化: 共通の設定パターンをどのように再利用し、特定の環境に特化した部分を抽象化するかは、大規模なプロジェクトにおいて特に重要です。
- メンテナンス性: 設定ファイルが肥大化したり、変更が困難になったりすると、メンテナンスコストが増大します。
これらの課題に対処するため、これまで様々なツールや手法が提案されてきました。代表的なものとしては、GoテンプレートやJinja2のような汎用テンプレートエンジン、HelmのようなKubernetes専用のパッケージマネージャー、Jsonnetのようなプログラマブルな設定生成ツールなどがあります。
これらのツールは、テンプレートを使用することで設定の柔軟性や再利用性を高めることができます。しかし、テンプレートには以下のような側面もあります。
- 学習曲線: 新しいテンプレート言語やその構文を学ぶ必要があります。
- デバッグの複雑さ: 生成されるYAMLを見るまで最終的な設定がどうなるか分かりにくく、デバッグが困難になることがあります。
- コード生成の課題: テンプレートはあくまでテキストを生成するため、複雑なロジックを記述しようとすると、かえって可読性や保守性が低下する可能性があります。
そこで登場したのが、今回焦点を当てるKustomizeです。Kustomizeは、テンプレートを使用せずに既存のKubernetes YAML設定をカスタマイズすることを目的としています。そのアプローチは、パッチ適用やマージといった宣言的な手法に依拠しており、設定の透明性と管理のシンプルさを重視しています。Kustomizeは、Kubernetesの公式ツールであるkubectl
にも統合されており、その利用はますます一般的になっています。
本記事では、Kustomizeの基本的な概念から始め、主要な機能、実践的なワークフロー、そして他のツールとの比較まで、約5000語にわたって詳細に解説していきます。Kustomizeを通じて、より効率的で堅牢なKubernetes設定管理を実現するための一歩を踏み出しましょう。
1. Kustomizeとは何か?:宣言的カスタマイズの核心
Kustomizeは、Kubernetesリソースを「テンプレートなしで」カスタマイズするためのツールです。ここでいう「テンプレートなし」とは、Helmチャートのように特定の変数を埋め込んで最終的なYAMLを生成するのではなく、既存のYAMLファイルに対して変更を「上書き」または「追加」するアプローチを取ることを意味します。このアプローチは宣言的カスタマイズと呼ばれます。
1.1. 宣言的カスタマイズの理念
Kustomizeのコアとなる理念は、「既存のYAMLファイルをそのままベースとし、それに対する差分(パッチ)を宣言的に記述することで、目的の環境設定を実現する」というものです。これにより、以下のような利点が得られます。
- 可読性と透明性: 生成されるYAMLがどのように見えるかを想像する必要がありません。ベースとなるYAMLと、それに適用される差分パッチを直接見れば、最終的な設定が明確に理解できます。
- 非侵襲性(Non-invasive): 元のベース設定ファイルに手を加えることなく、新しい設定を適用できます。これにより、ベースのYAMLを複数の異なるカスタマイズで再利用することが容易になります。
- シンプルな差分管理: 環境ごとの差分がYAMLファイルとして明示的に記述されるため、Gitのようなバージョン管理システムとの相性が良く、変更履歴の追跡やコードレビューが容易になります。
- Kubernetesネイティブ: KubernetesのネイティブなYAML形式を直接操作するため、Kubernetesの概念や構造に自然にフィットします。
1.2. BaseとOverlayの概念
Kustomizeの最も重要な概念は「Base(ベース)」と「Overlay(オーバーレイ)」です。
-
Base(ベース):
アプリケーションの共通的な設定を定義するYAMLファイルの集合体です。これは、特定の環境に依存しない、アプリケーションの基本的なデプロイメント、サービス、コンフィグマップなどを記述します。Baseは、その名の通り、すべての環境設定の出発点となります。 -
Overlay(オーバーレイ):
特定の環境(例:開発環境、本番環境)に特有の差分設定を定義するYAMLファイルの集合体です。OverlayはBaseを参照し、Baseの既存リソースに対して、パッチの適用、プロパティの変更、リソースの追加、名前の変更などを行います。Overlayによって、Baseの設定が特定の環境向けに「カスタマイズ」されます。
このBaseとOverlayの構造は、共通設定を一度記述すれば、それを複数の環境で再利用し、それぞれの環境で必要な変更だけをOverlayとして記述できるという効率的な設定管理を可能にします。
1.3. kustomization.yaml
の役割
Kustomizeの中心となるファイルは、各ディレクトリに配置されるkustomization.yaml
です。このファイルは、そのディレクトリ(またはそのサブディレクトリ)にあるKubernetesリソースをどのようにカスタマイズするかをKustomizeに指示するマニフェストファイルです。
kustomization.yaml
には、主に以下のような情報が記述されます。
resources
: Kustomizeが操作するKubernetesリソースファイルへのパスリスト。Baseディレクトリでは、そのアプリケーションのすべてのリソースファイルが列挙されます。Overlayディレクトリでは、Baseディレクトリへの相対パスが記述されます(Kustomize v3以降、OverlayでBaseを参照する際もresources
を使用するのが一般的です。以前はbases
というフィールドがありましたが、現在は非推奨です)。patches
: 特定のリソースに対する変更(パッチ)を定義するYAMLファイルへのパスリスト。commonLabels
/commonAnnotations
: すべてのリソースに共通して追加したいラベルやアノテーションを定義します。namePrefix
/nameSuffix
: すべてのリソース名に共通してプレフィックスやサフィックスを追加します。images
: コンテナイメージのタグやレジストリを変更します。configMapGenerator
/secretGenerator
: ConfigMapやSecretを動的に生成します。
kustomization.yaml
は、設定のレシピのようなものです。Kustomizeを実行すると、このレシピに従って、指定されたリソースファイルが読み込まれ、パッチが適用され、様々な変換処理が実行され、最終的なKubernetes YAMLが出力されます。
1.4. Kustomizeの実行フロー
Kustomizeを実行する際には、通常、kustomize build <path/to/overlay>
(またはkubectl apply -k <path/to/overlay>
)コマンドを使用します。
kustomization.yaml
の読み込み: 指定されたパスのkustomization.yaml
ファイルが読み込まれます。- Baseのロード:
resources
フィールド(またはbases
フィールド)に指定されたBaseディレクトリのkustomization.yaml
が読み込まれ、そのBaseが持つリソースがロードされます。 - リソースの収集: Baseリソースと、Overlayに直接含まれる追加リソースが収集されます。
- 変換処理の適用:
commonLabels
、namePrefix
、images
などの組み込みの変換処理が適用されます。 - パッチの適用:
patchesStrategicMerge
やpatchesJson6902
で指定されたパッチが、対象のリソースに適用されます。 - ジェネレータの実行:
configMapGenerator
やsecretGenerator
で定義されたConfigMapやSecretが生成されます。 - 最終YAMLの出力: すべての処理が完了した後の、最終的なKubernetesリソースのYAMLが出力されます。このYAMLは、
kubectl apply -f -
を使って直接クラスターに適用できます。
Kustomizeのこうした宣言的かつ非侵襲的なアプローチは、特に複数の環境で同じアプリケーションをデプロイする際や、既存のオープンソースプロジェクトのKubernetesマニフェストをカスタマイズする際に、その真価を発揮します。
2. Kustomizeを始める:インストールと基本的な使い方
Kustomizeは、kubectl
コマンドに統合されているため、最新のkubectl
を使用していれば、追加のインストールなしで基本的なKustomize機能を利用できます。しかし、スタンドアロン版のKustomize CLIを使用することもできます。
2.1. kubectl
への統合
kubectl
のバージョン1.14以降では、Kustomizeの機能がkubectl apply -k
コマンドとして統合されています。これは最も手軽にKustomizeを利用する方法です。
“`bash
kubectlのバージョン確認
kubectl version –short
Kustomizeのヘルプを表示
kubectl kustomize –help
または
kubectl apply -k –help
“`
kubectl apply -k
を使うことで、Kustomizeビルドと適用を一つのコマンドで実行できます。
2.2. スタンドアロンとしての利用
Kustomizeは単独のCLIツールとしても利用可能です。スタンドアロン版は、kubectl
のバージョンに依存せずに最新のKustomize機能を利用したい場合や、ビルド結果をファイルに出力して他のツールと連携させたい場合に便利です。
インストール方法(例:Linux/macOS):
“`bash
最新版のKustomizeのリリースURLを確認 (例: https://github.com/kubernetes-sigs/kustomize/releases)
最新のバージョン番号に置き換えてください (例: kustomize/v5.0.0/kustomize_v5.0.0_linux_amd64.tar.gz)
curl -s “https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh” | bash
あるいは直接ダウンロード
curl -sL “https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2fv5.0.0/kustomize_v5.0.0_linux_amd64.tar.gz” | tar xz
実行可能ファイルをPATHの通ったディレクトリに移動
sudo mv kustomize /usr/local/bin/
バージョン確認
kustomize version
“`
Windowsの場合も、GitHubのリリースページからバイナリをダウンロードし、PATHに追加することで利用できます。
2.3. 最初の kustomization.yaml
を作成する
それでは、実際にKustomizeを使ってみましょう。まずは簡単なNginxのデプロイメントとサービスを定義し、それをKustomizeで管理する準備をします。
プロジェクトのディレクトリ構造を以下のように設定します。
kustomize-demo/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
│ └── kustomization.yaml
└── prod/
└── kustomization.yaml
base/deployment.yaml
:
“`yaml
kustomize-demo/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
– name: nginx
image: nginx:1.21.0
ports:
– containerPort: 80
“`
base/service.yaml
:
“`yaml
kustomize-demo/base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
app: nginx
spec:
selector:
app: nginx
ports:
– protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
“`
base/kustomization.yaml
:
Baseディレクトリのkustomization.yaml
には、管理するリソースのリストを記述します。
“`yaml
kustomize-demo/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
– deployment.yaml
– service.yaml
“`
これでBaseの設定は完了です。
Baseをビルドしてみる:
kustomize-demo
ディレクトリのルートで以下のコマンドを実行します。
bash
kustomize build base/
または、kubectl
統合版の場合:
bash
kubectl kustomize base/
これにより、deployment.yaml
とservice.yaml
の内容が結合され、標準出力に表示されます。
“`yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
– image: nginx:1.21.0
name: nginx
ports:
– containerPort: 80
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx
name: nginx-service
spec:
ports:
– port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: ClusterIP
“`
出力されたYAMLは、そのままKubernetesクラスターに適用できます。
bash
kubectl apply -f - < base/
この段階ではまだカスタマイズは行われていませんが、Kustomizeがどのようにリソースを収集し、結合するかを確認できました。次に、このBaseをカスタマイズするためのOverlayを作成します。
3. Overlayの作成:環境ごとのカスタマイズ
Kustomizeの真価は、Baseに対してOverlayを適用することで、環境固有のカスタマイズを効率的に行う点にあります。ここでは、開発環境(dev
)と本番環境(prod
)のOverlayを作成し、それぞれ異なる設定を適用してみましょう。
3.1. 開発環境(dev)のOverlay
開発環境では、通常、リソースは少なめに設定されます。ここでは、レプリカ数を1に保ち、イメージタグを最新版(nginx:latest
)に変更してみます。
overlays/dev/kustomization.yaml
:
“`yaml
kustomize-demo/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases: # または resources: と書いても良い (Kustomize v3以降)
– ../../base
レプリカ数を変更するためのパッチ
patchesStrategicMerge:
– deployment-patch.yaml
イメージを変更
images:
– name: nginx
newTag: latest
リソースに共通のラベルを追加
commonLabels:
env: dev
“`
overlays/dev/deployment-patch.yaml
:
このパッチファイルは、base/deployment.yaml
に対してspec.replicas
を上書きするためのものです。KustomizeはYAMLマージパッチ(Strategic Merge Patch)という機能を使って、既存のYAML構造に部分的な変更を適用します。パッチファイルでは、変更したい部分だけを記述します。
“`yaml
kustomize-demo/overlays/dev/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
“`
開発環境向けにビルド:
kustomize-demo
ディレクトリのルートで、以下のコマンドを実行します。
bash
kustomize build overlays/dev/
または、kubectl
統合版の場合:
bash
kubectl kustomize overlays/dev/
出力されたYAMLを確認すると、以下の変更が適用されているはずです。
nginx-deployment
のspec.replicas
が1
になっている。nginx
コンテナのimage
がnginx:latest
になっている。- すべてのリソース(DeploymentとService)に
env: dev
ラベルが追加されている。
3.2. 本番環境(prod)のOverlay
次に、本番環境のOverlayを作成します。本番環境では、レプリカ数を3にし、イメージタグを安定版(nginx:1.22.0
など具体的なバージョン)に変更し、さらにClusterIP
サービスをLoadBalancer
サービスに変更してみましょう。
overlays/prod/kustomization.yaml
:
“`yaml
kustomize-demo/overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
– ../../base
レプリカ数変更とサービスタイプ変更のパッチ
patchesStrategicMerge:
– deployment-patch.yaml
– service-patch.yaml
イメージを変更
images:
– name: nginx
newTag: 1.22.0 # 本番環境では特定の安定バージョンを使用
リソースに共通のラベルを追加
commonLabels:
env: prod
名前プレフィックスを追加(リソース名がprod-nginx-deploymentのようになる)
namePrefix: prod-
“`
overlays/prod/deployment-patch.yaml
:
“`yaml
kustomize-demo/overlays/prod/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
“`
overlays/prod/service-patch.yaml
:
“`yaml
kustomize-demo/overlays/prod/service-patch.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: LoadBalancer # サービスタイプをLoadBalancerに変更
“`
本番環境向けにビルド:
kustomize-demo
ディレクトリのルートで、以下のコマンドを実行します。
bash
kustomize build overlays/prod/
または、kubectl
統合版の場合:
bash
kubectl kustomize overlays/prod/
出力されたYAMLを確認すると、以下の変更が適用されているはずです。
nginx-deployment
のspec.replicas
が3
になっている。nginx
コンテナのimage
がnginx:1.22.0
になっている。- すべてのリソース(DeploymentとService)に
env: prod
ラベルが追加されている。 nginx-service
のspec.type
がLoadBalancer
になっている。- すべてのリソース名に
prod-
というプレフィックスが追加され、prod-nginx-deployment
やprod-nginx-service
のようになっている。
このように、KustomizeはBaseを共有しつつ、各環境のkustomization.yaml
と対応するパッチファイルを記述するだけで、複雑な環境差分を簡潔に管理できます。これがKustomizeの最も基本的な、そして強力な使い方です。
4. Kustomizeの主要機能:詳細な解説と実践例
Kustomizeは、先述のBaseとOverlayの概念を支えるために、様々な強力な機能を提供しています。ここでは、それらの主要機能を具体的な例とともに詳しく解説します。
4.1. 名前変更(Name Prefix/Suffix)
特定の環境でリソース名を変更したい場合に便利です。特に、複数の環境を同じKubernetesクラスター内にデプロイする際のリソース名衝突を避けるために使われます。
namePrefix
: すべてのリソース名の先頭に指定した文字列を追加します。nameSuffix
: すべてのリソース名の末尾に指定した文字列を追加します。
例: prod
環境でprod-
というプレフィックスを付ける。
“`yaml
overlays/prod/kustomization.yaml (抜粋)
namePrefix: prod-
“`
これにより、Baseでnginx-deployment
だったリソースはprod-nginx-deployment
に、nginx-service
はprod-nginx-service
になります。Kustomizeは、リソース定義内のセレクタやコンテナ名、ボリューム名など、関連する参照も自動的に更新しようとします。ただし、ConfigMapやSecretが別のリソースでボリュームとして参照されている場合、名前が変更されると参照が壊れる可能性があるため注意が必要です。その場合は、パッチを使って参照箇所も更新する必要があります。
4.2. ラベルとアノテーション(Labels/Annotations)
リソースに共通のラベルやアノテーションを追加・上書きする機能です。環境の識別子、監視エージェントの設定、Gitコミットハッシュなど、様々なメタデータを付与するのに役立ちます。
commonLabels
: すべてのリソースに適用されるラベル。commonAnnotations
: すべてのリソースに適用されるアノテーション。
例: dev
環境にenv: dev
ラベルを追加。
“`yaml
overlays/dev/kustomization.yaml (抜粋)
commonLabels:
env: dev
app.kubernetes.io/instance: myapp-dev
“`
これにより、Baseのすべてのリソースに上記のラベルが追加されます。もしBaseに同じキーのラベルが存在した場合、OverlayのcommonLabels
が上書きします。
4.3. ネームスペース(Namespace)
デプロイ先となるKubernetesのネームスペースを変更したい場合に指定します。
namespace
: すべてのリソースがデプロイされるネームスペースを指定します。
例: prod
環境をproduction
ネームスペースにデプロイする。
“`yaml
overlays/prod/kustomization.yaml (抜粋)
namespace: production
“`
これにより、Kustomizeはすべてのリソースのmetadata.namespace
フィールドをproduction
に設定します。もしリソースにnamespace
フィールドが存在しない場合でも追加されます。
4.4. イメージの変更(Images)
デプロイされるコンテナイメージのバージョンやレジストリを変更する最も一般的なカスタマイズの一つです。
images
: イメージの名前(コンテナ名)と、新しいタグまたはレジストリを指定します。
例: Nginxイメージのタグを変更。
“`yaml
overlays/prod/kustomization.yaml (抜粋)
images:
– name: nginx # コンテナのimageフィールドに指定されている名前
newTag: 1.22.0 # 新しいタグ
– name: my-custom-image # 別のイメージの場合
newName: registry.example.com/my-app # 新しいレジストリとイメージ名
newTag: v2.0
“`
name
フィールドは、コンテナのimage
フィールドで指定されているイメージ名を指定します。newName
とnewTag
を組み合わせることで、完全なイメージ名を変更できます。Kustomizeは、指定されたイメージ名を持つすべてのコンテナのイメージを自動的に更新します。
4.5. リソースジェネレータ(Generators)
ConfigMapやSecretをファイルやリテラル値から動的に生成する機能です。これらのリソースをYAMLファイルとして直接管理する代わりに、Kustomizeに生成させることで、ファイルの内容の変更に応じて自動的にハッシュ値を含む名前が生成され、デプロイメントのロールアウトトリガーとして機能させることができます。これは特に設定の変更に伴うアプリケーションの再デプロイメントにおいて非常に便利です。
configMapGenerator
: ConfigMapを生成します。secretGenerator
: Secretを生成します。
例: ConfigMapを生成し、Deploymentから参照する。
まず、BaseにConfigMapの参照を記述します(ここではConfigMap自体は定義しない)。
base/deployment.yaml
(修正):
“`yaml
kustomize-demo/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
– name: nginx
image: nginx:1.21.0
ports:
– containerPort: 80
env:
– name: MY_MESSAGE
valueFrom:
configMapKeyRef:
name: app-config # 生成されるConfigMapの名前
key: message.txt
volumes:
– name: config-volume
configMap:
name: app-config # 生成されるConfigMapの名前
“`
次に、OverlayでConfigMapを生成します。
overlays/dev/kustomization.yaml
(修正):
“`yaml
kustomize-demo/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
– ../../base
patchesStrategicMerge:
– deployment-patch.yaml
images:
– name: nginx
newTag: latest
commonLabels:
env: dev
ConfigMapを生成
configMapGenerator:
– name: app-config # 生成されるConfigMapの名前
files:
– config/dev_message.txt # ファイルから内容を読み込む
literals:
– APP_ENV=development # リテラル値を追加
“`
overlays/dev/config/dev_message.txt
:
This is a message from the development environment.
ビルド結果の確認:
kustomize build overlays/dev/
を実行すると、app-config-<hash>
のような名前のConfigMapが生成され、Deploymentのvolume.configMap.name
とenv.valueFrom.configMapKeyRef.name
がこのハッシュ付きの名前に自動的に更新されていることが確認できます。これにより、dev_message.txt
の内容が変更されるたびにConfigMapのハッシュ値が変わり、Deploymentが再デプロイされるようになります。これは、Kubernetesにおける「設定の自動ロールアウト」を実現する非常に強力な機能です。
Secretについても同様にsecretGenerator
を使用できます。
“`yaml
overlays/prod/kustomization.yaml (抜粋)
secretGenerator:
– name: app-secret
literals:
– API_KEY=supersecretkey # リテラル値をBase64エンコードして格納
files:
– secrets/prod_db_credentials.txt # ファイルの内容をBase64エンコードして格納
“`
secretGenerator
は、literals
で与えられた値を自動的にBase64エンコードして格納します。files
も同様に内容をエンコードします。
4.6. パッチ(Patches)
既存のリソースの特定の部分を変更する最も強力で柔軟な機能です。Kustomizeは主に以下の2種類のパッチをサポートしています。
-
Strategic Merge Patch (
patchesStrategicMerge
):
Kubernetes独自のYAMLマージルールに従って、YAMLファイルを部分的に上書きまたは追加します。これは、Kustomizeで最も一般的に使用されるパッチ形式です。パッチファイルでは、変更したいフィールドだけを記述し、KustomizeがBaseのリソースとマージします。リストの要素(例: コンテナリスト)をマージする際には、キーとなるフィールド(例: コンテナのname
)に基づいて要素を識別し、マージします。例:
deployment-patch.yaml
でreplicas
を変更。“`yaml
overlays/dev/kustomization.yaml (抜粋)
patchesStrategicMerge:
– deployment-patch.yaml
“`“`yaml
overlays/dev/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment # どのリソースに対するパッチかを指定
spec:
replicas: 1 # ここだけ変更
“`Strategic Merge Patchの大きな利点は、KustomizeがKubernetesリソースのスキーマを理解しているため、例えばコンテナのリストに対して、特定の名前のコンテナのみを変更したり、新しいコンテナを追加したりといったスマートなマージができる点です。
-
JSON 6902 Patch (
patchesJson6902
):
RFC 6902で定義されているJSON Patch形式を使用します。これはJSON形式の配列で、add
,remove
,replace
,copy
,move
,test
といった操作をパスと値の組み合わせで表現します。Strategic Merge Patchよりも低レベルですが、より詳細な操作が可能です。特に、リストの特定の位置に要素を挿入したり、特定のフィールドを完全に削除したりする場合に役立ちます。例: Deploymentの特定の環境変数を削除する。
“`yaml
overlays/prod/kustomization.yaml (抜粋)
patchesJson6902:
– target:
group: apps
version: v1
kind: Deployment
name: nginx-deployment
path: delete-env-var.yaml
“`“`yaml
overlays/prod/delete-env-var.yaml
- op: remove
path: /spec/template/spec/containers/0/env/0 # 最初のコンテナの最初の環境変数を削除
“`
patchesJson6902
は、target
フィールドでパッチを適用するリソースを特定し、path
フィールドでパッチファイルへのパスを指定します。path
はJSON Patchの操作が記述されたYAMLファイルです。JSON Patchは非常に強力ですが、パスの指定が厳密であるため、元のYAML構造を正確に把握しておく必要があります。 - op: remove
パッチの選択:
* ほとんどの場合、patchesStrategicMerge
で十分です。可読性が高く、Kubernetesリソースのセマンティクスに沿った変更ができます。
* リストの特定の要素を完全に削除したい場合や、特定の位置に挿入したい場合など、より詳細な操作が必要な場合にpatchesJson6902
を検討します。
4.7. コンポーネント(Components)
Kustomize v4.xで導入されたコンポーネントは、共通のカスタマイズロジック(パッチ、ジェネレータ、共通ラベルなど)をモジュール化し、再利用可能にするための機能です。これにより、複数のOverlayで同じカスタマイズを適用する際に、重複記述を避けることができます。
例: 開発用に追加したいデバッグ用サイドカーコンテナの定義をコンポーネント化する。
components/debug-container/kustomization.yaml
:
“`yaml
kustomize-demo/components/debug-container/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patchesStrategicMerge:
– add-debug-container.yaml
“`
components/debug-container/add-debug-container.yaml
:
“`yaml
kustomize-demo/components/debug-container/add-debug-container.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
template:
spec:
containers:
– name: debug-sidecar
image: busybox
command: [“sh”, “-c”, “echo ‘Hello from debug sidecar!’; sleep 3600”]
“`
overlays/dev/kustomization.yaml
(修正):
components
フィールドでコンポーネントを参照します。
“`yaml
kustomize-demo/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
– ../../base
patchesStrategicMerge:
– deployment-patch.yaml
images:
– name: nginx
newTag: latest
commonLabels:
env: dev
configMapGenerator:
– name: app-config
files:
– config/dev_message.txt
literals:
– APP_ENV=development
コンポーネントの適用
components:
– ../../components/debug-container
“`
これでdev
環境をビルドすると、BaseのDeploymentに加えて、debug-sidecar
コンテナが追加されたDeploymentが生成されます。コンポーネントは、再利用可能なカスタマイズの単位として非常に有効です。
5. 実践的なKustomizeのワークフロー
Kustomizeは単体で強力なツールですが、CI/CDパイプラインやGitOpsワークフローに組み込むことで、その真価を発揮します。
5.1. プロジェクト構造の推奨例
前述の例のようなディレクトリ構造は、Kustomizeのベストプラクティスとされています。
.
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
├── components/ # Kustomize v4.x以降で使用
│ ├── debug-container/
│ │ ├── add-debug-container.yaml
│ │ └── kustomization.yaml
│ └── custom-resource-defaults/
│ ├── crd-defaults-patch.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
│ ├── deployment-patch.yaml
│ ├── kustomization.yaml
│ └── config/
│ └── dev_message.txt
└── prod/
├── deployment-patch.yaml
├── service-patch.yaml
├── kustomization.yaml
└── config/
└── prod_message.txt
この構造のポイントは以下の通りです。
* base
ディレクトリはアプリケーションの共通かつ基本的なリソースのみを格納します。
* overlays
ディレクトリは環境ごとの差分を管理します。各環境のディレクトリには、その環境固有のkustomization.yaml
とパッチファイル、設定ファイルなどを置きます。
* components
ディレクトリは、複数のOverlayで共有されるカスタマイズロジック(例:特定の機能を追加するパッチ群)をカプセル化します。
* 設定ファイル(dev_message.txt
など)は、ジェネレータで利用するためにOverlayディレクトリ内に配置します。
5.2. CI/CDパイプラインへの組み込み
KustomizeはCI/CDパイプラインに非常に組み込みやすいツールです。
一般的なCI/CDステップ:
- コードのチェックアウト: GitリポジトリからKubernetesマニフェストとKustomize設定をチェックアウトします。
-
Kustomizeビルド: ターゲット環境(例:
overlays/prod
)のKustomize設定をビルドし、最終的なYAMLマニフェストを生成します。bash
kustomize build overlays/prod > prod-manifests.yaml -
セキュリティスキャン: 生成された
prod-manifests.yaml
に対して、Kubernetes設定のベストプラクティスやセキュリティポリシーに違反がないか、kube-linterやDatreeなどのツールでスキャンを行います。 -
デプロイ: 生成されたYAMLをKubernetesクラスターに適用します。
bash
kubectl apply -f prod-manifests.yaml
このシンプルなワークフローにより、バージョン管理されたKustomize設定から、常に一貫性のあるKubernetes設定を生成し、デプロイすることが可能になります。
5.3. GitOpsとの親和性
GitOpsは、Gitリポジトリを「信頼できる唯一の情報源(Single Source of Truth)」として、インフラストラクチャやアプリケーションの状態を宣言的に管理するプラクティスです。Kustomizeは、GitOpsの原則と非常に高い親和性を持っています。
KustomizeがGitOpsに適している理由:
- 宣言的: Kustomizeの設定はすべてYAMLファイルとして宣言的に記述されます。これはGitOpsの主要な要件です。
- バージョン管理: ベース設定とオーバーレイ設定のすべてがGitでバージョン管理されるため、いつでも過去の状態に戻したり、変更履歴を追跡したりできます。
- 透明性: Kustomizeの出力は純粋なKubernetes YAMLであり、人間が読解可能です。これにより、デプロイされる内容の透明性が保たれます。
- 非侵襲性: ベースマニフェストを直接変更しないため、コミュニティのHelmチャートやオペレーターのマニフェストなど、外部のソースをそのまま利用し、その上に独自のカスタマイズを適用することが容易です。
Argo CDやFlux CDといったGitOpsツールは、Kustomizeをネイティブにサポートしています。これらのツールは、Gitリポジトリ内のKustomize設定の変更を自動的に検知し、Kustomizeビルドを実行してクラスターに適用することで、継続的なデプロイメントを実現します。
例: Argo CDでKustomizeアプリケーションをデプロイする場合
Argo CDのApplicationリソースでは、ソースとしてGitリポジトリのKustomizeディレクトリを指定するだけです。
yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-nginx-app-prod
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/kustomize-demo.git # GitリポジトリのURL
targetRevision: HEAD
path: overlays/prod # Kustomizeのkustomization.yamlがあるパス
destination:
server: https://kubernetes.default.svc
namespace: production # Kustomizeのnamespaceフィールドと一致させる
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
このように、KustomizeはCI/CDとGitOpsの基盤として、Kubernetesアプリケーションのデプロイメントパイプラインを堅牢かつ効率的に構築するための強力なツールとなります。
6. Kustomizeと他のツールの比較
Kubernetesの設定管理にはKustomize以外にも多くの選択肢があります。ここでは、特にHelmとの比較に焦点を当て、Kustomizeがどのような点で優れており、どのような場合にKustomizeを選ぶべきかを考察します。
6.1. Helmとの比較:テンプレート vs. 宣言的パッチ
HelmはKubernetesの「パッケージマネージャー」であり、アプリケーションをパッケージ化し、テンプレートを使用して設定をカスタマイズするツールです。
特徴 | Kustomize | Helm |
---|---|---|
アプローチ | 既存のYAMLに対する宣言的パッチ適用 | GoテンプレートエンジンによるYAML生成(チャート) |
学習曲線 | Kubernetes YAMLの知識があれば比較的低い | Goテンプレート構文、Helm固有の関数、チャートの構造を学ぶ必要あり |
透明性 | ベースYAML + パッチで最終形が明確 | テンプレートロジックが複雑になると最終形を推測しにくい |
デバッグ | ベースYAMLとパッチを個別に検証しやすい | テンプレートのレンダリングエラーや変数の間違いのデバッグが難しい |
再利用性 | ベースを再利用し、Overlayで差分を表現 | チャートとしてパッケージ化し、values.yaml でカスタマイズ |
管理対象 | 任意のKubernetes YAML設定 | アプリケーション単位の「Helm Chart」 |
依存性管理 | 明示的な依存性管理機能は持たない(ディレクトリ構造で表現) | Chart内のサブチャートとして依存性を管理できる |
CLI統合 | kubectl に統合されている |
独自のCLI (helm ) |
用途 | 既存のYAMLを柔軟にカスタマイズしたい場合、GitOpsとの親和性が高い場合、シンプルな差分管理をしたい場合 | 複雑なデプロイロジックが必要な場合、オフラインでのパッケージ共有、アプリケーションの依存性管理をしたい場合 |
Helmの強み:
- パッケージングと共有: Helm Chartとしてアプリケーション全体をパッケージ化し、レジストリ(Chart Repository)を通じて簡単に共有・配布できます。これは、サードパーティ製アプリケーションのデプロイに特に便利です。
- リリース管理: リリース履歴、ロールバック、アップグレードなどのリリース管理機能が充実しています。
- 複雑なロジック: Goテンプレートのフルパワーを活用して、条件分岐、ループ、算術演算など、複雑なデプロイロジックを記述できます。
- 依存性管理: Chartの依存関係を管理し、関連するアプリケーションをまとめてデプロイできます。
Helmの弱み:
- テンプレートの複雑性: テンプレートロジックが複雑になると、可読性が低下し、デバッグが困難になります。
- 値の管理:
values.yaml
が環境ごとに肥大化し、管理が難しくなることがあります。 - 非侵襲的な変更の難しさ: Helm Chart自体をカスタマイズするには、テンプレートを上書きするか、Goテンプレートの知識が必要です。
Kustomizeの強み:
- シンプルさと透明性: YAMLファイルを直接パッチするため、最終的な設定が直感的に理解しやすいです。
- 非侵襲性: 元のYAMLファイルに手を加えることなく、必要な変更だけを適用できます。これにより、上流のプロジェクト(例:Kubernetesの公式サンプル、OSSプロジェクトのYAML)の変更を簡単に取り込めます。
- GitOpsとの親和性: 宣言的なYAMLベースの管理はGitOpsワークフローと非常に相性が良いです。
- Kubernetesネイティブ:
kubectl
に統合されており、Kustomizeの概念がKubernetesのそれと自然にフィットします。
Kustomizeの弱み:
- リリース管理機能の欠如: Helmのようなリリース履歴やロールバックの機能は持たず、これらはGitやCI/CDツールで別途管理する必要があります。
- パッケージングの不在: アプリケーションを「パッケージ」として配布する機能はありません。
- 複雑な条件分岐の難しさ: テンプレートではないため、複雑な条件分岐やロジックに基づいた設定変更は苦手です。
どちらを選ぶべきか?:
-
Kustomizeを選ぶべき場合:
- 既存のYAMLをカスタマイズしたい: 上流のプロジェクトやシンプルな手動で書かれたYAMLをベースに、環境ごとの差分を管理したい場合。
- テンプレートの複雑さを避けたい: Goテンプレートの学習やデバッグのオーバーヘッドを避け、より直接的にYAMLを操作したい場合。
- GitOpsを推進したい: すべての設定をGitで宣言的に管理し、変更の透明性を高めたい場合。
- シンプルな差分管理で十分: 複雑な条件分岐や動的な値の生成があまり必要でない場合。
-
Helmを選ぶべき場合:
- アプリケーションを再利用可能なパッケージとして配布したい: 複数のユーザーやクラスターで共通のアプリケーションをデプロイ・管理したい場合。
- 複雑なデプロイロジックが必要: 環境によって大きく設定が変わる、複数の関連リソースを動的に生成・変更する必要がある場合。
- 充実したリリース管理機能が必要: ロールバック、バージョン管理されたアップグレードパス、依存性管理をHelmの機能として利用したい場合。
両方を組み合わせるアプローチ:
KustomizeとHelmは排他的な関係ではありません。Helm Chartをデプロイし、そのChartが出力するYAMLに対してKustomizeでさらにカスタマイズを加えるという組み合わせも可能です。例えば、Helm Chartをhelm template
でYAMLに出力し、その出力をKustomizeのBaseとして使用し、その上にKustomizeのOverlayを適用する、といった方法です。これにより、Helmのパッケージング能力とKustomizeの柔軟なカスタマイズ能力の両方の利点を享受できます。
6.2. Jsonnetとの比較
JsonnetはGoogleが開発したデータテンプレート言語で、JSONをプログラム的に生成するのに使われます。Kubernetesの設定でも利用されることがあります。
- Jsonnet: プログラマブルな言語であり、関数、変数、インポートなどを用いて高度なロジックを記述し、最終的にJSON(またはYAML)を出力します。非常に強力で柔軟ですが、プログラミング言語の学習が必要です。
- Kustomize: 宣言的な設定ツールであり、既存のYAMLに対してパッチや変換を適用します。プログラミングの知識は不要で、YAMLの知識があればすぐに利用できます。
Jsonnetは「設定のコード化」を極限まで推し進めることができますが、学習曲線が非常に急であり、YAMLに慣れたインフラエンジニアにとってはKustomizeの方が直感的であると感じられることが多いでしょう。
7. Kustomizeのベストプラクティスと注意点
Kustomizeを効果的に利用するためには、いくつかのベストプラクティスと注意点を押さえておくことが重要です。
7.1. Baseはシンプルに保つ
Baseディレクトリ内のリソースは、可能な限りシンプルで汎用的な状態に保つべきです。環境固有の設定や、後でOverlayで変更されることが確実な値(例: replicas: 1
)は、最小限に抑えるか、あるいはBaseには含めず、Overlayで追加することを検討します。これにより、Baseの再利用性が高まり、異なるOverlay間での共通認識が容易になります。
7.2. Overlayは差分のみに集中する
Overlayディレクトリ内のkustomization.yaml
とパッチファイルは、Baseからの変更点のみを記述するようにします。Baseにすでに存在する設定を冗長に記述したり、必要以上にパッチの範囲を広げたりしないようにします。これにより、変更の意図が明確になり、設定ファイルの管理が容易になります。
7.3. パッチの粒度を適切に保つ
patchesStrategicMerge
やpatchesJson6902
を使用する際、一つのパッチファイルで複数のリソースを変更したり、非常に広範な変更を記述したりすると、パッチの可読性やメンテナンス性が低下します。理想的には、一つのパッチファイルは一つの特定の目的(例: レプリカ数の変更、サービスタイプの変更)のために、一つのリソースを対象とするようにします。
7.4. バージョニング戦略
Gitを使ってKustomize設定をバージョン管理することは必須です。Base、Overlay、パッチファイルすべてをGitにコミットし、変更履歴を追跡可能にします。デプロイされた環境とGitリポジトリの状態を一致させることで、GitOpsのような自動化されたデプロイメントを容易に実現できます。
7.5. デバッグ方法
Kustomizeのビルド結果をデバッグする最も簡単な方法は、kustomize build <path/to/overlay>
(またはkubectl kustomize <path/to/overlay>
)コマンドで生成されたYAMLを詳細に確認することです。
--output-directory
: ビルド結果を標準出力ではなく、ファイルとして出力したい場合は、kustomize build overlays/dev --output-directory build/dev
のように指定できます。- 中間ファイルの確認: Kustomizeは内部的に一時ファイルを作成して処理を進めます。問題が発生した場合、Kustomizeのバージョンや設定によっては、詳細なログやデバッグ情報を出力できる場合があります(例:
KUSTOMIZE_DEBUG=true kustomize build ...
)。 kustomize edit
: Kustomize v3.5.0以降で導入されたkustomize edit
コマンドは、kustomization.yaml
をプログラム的に編集するのに役立ちます。例えば、kustomize edit add resource deployment.yaml
でリソースを追加できます。
7.6. Kustomizeのバージョンアップと非互換性
Kustomizeは活発に開発が進められており、新しいバージョンがリリースされることがあります。メジャーバージョンアップ(例: v3からv4、v4からv5)では、一部のフィールド名が変更されたり、振る舞いが変わったりする場合があります。例えば、bases
フィールドがresources
に統合されたり、patches
がpatchesStrategicMerge
に変わったりしました。
- 公式ドキュメントの確認: KustomizeのGitHubリポジトリ(
kubernetes-sigs/kustomize
)のリリースノートやドキュメントを定期的に確認し、変更点や非互換性を把握しておくことが重要です。 kustomize build --enable-helm
: Kustomize v4.x以降では、Helmチャートをリソースとして組み込むための--enable-helm
フラグがあります。kustomize build --enable-alpha-plugins
: アルファ版のプラグイン機能を利用する場合に必要です。
7.7. シークレットの管理
secretGenerator
はシークレットを管理するのに便利ですが、実際の運用ではより堅牢なシークレット管理ソリューションと組み合わせることを検討してください。例えば、VaultやAWS Secrets Manager、Azure Key Vault、GCP Secret Managerといったシークレット管理サービスからシークレットを取得し、それらをKubernetesのSecretリソースとして注入するために、外部シークレットオペレーター(External Secrets Operatorなど)を使用するアプローチが推奨されます。この場合、KustomizeはConfigMapのようなパブリックな設定の管理に主に使用し、機密情報は外部ツールに任せることになります。
まとめ:Kustomizeが提供する価値と今後の展望
本記事では、Kustomizeの基本的な概念から始め、BaseとOverlayの仕組み、kustomization.yaml
の役割、そしてnamePrefix
/commonLabels
/images
/generator
/patches
といった主要な機能について、具体的な例を交えながら詳細に解説しました。さらに、KustomizeをCI/CDパイプラインやGitOpsワークフローに組み込む方法、そしてHelmのような他のツールとの比較を通じて、Kustomizeがどのような課題を解決し、どのような状況で最適な選択肢となるかを考察しました。
Kustomizeは、その「テンプレートなし」というユニークなアプローチにより、Kubernetesの設定管理に以下のような明確な価値をもたらします。
- シンプルさと透明性: 複雑なテンプレート言語を学ぶ必要がなく、KubernetesのネイティブなYAMLを直接パッチ適用するため、設定の意図が明確で理解しやすいです。
- 非侵襲性: ベースとなるYAMLファイルを変更することなくカスタマイズできるため、上流のプロジェクトの変更を容易に追従できます。これは、オープンソースのHelmチャートやオペレーターのマニフェストをカスタマイズする際に特に有用です。
- GitOpsとの親和性: 宣言的なYAMLベースの管理と非侵襲的なアプローチは、GitOpsの原則に完全に合致し、自動化された信頼性の高いデプロイメントパイプラインの構築を可能にします。
- 環境差分の効率的な管理: BaseとOverlayの構造により、共通設定と環境固有の差分を効率的に分離・管理でき、設定の重複を避けることができます。
Kustomizeは、特に小規模から中規模のプロジェクトや、既存のYAMLマニフェストをベースに運用するケースにおいて、非常に強力な選択肢となります。また、kubectl
に統合されていることもあり、Kubernetesユーザーにとってアクセスしやすいツールです。
Kubernetesエコシステムは日々進化しており、設定管理のベストプラクティスも変化し続けています。Kustomizeは、そのシンプルさと柔軟性から、今後もKubernetes設定管理の重要なツールとして広く利用されていくでしょう。本記事が、皆さんのKubernetes設定管理の効率化と堅牢性向上に役立つことを願っています。ぜひKustomizeを実際に試してみて、そのシンプルさと強力さを体験してください。