検索
連載

「Kustomize」超入門――複数環境の重過ぎKubernetesマニフェスト、どう管理すればいいのかCloud Nativeチートシート(2)

Kubernetesやクラウドネイティブをより便利に利用する技術やツールについて概要や使い方を凝縮して紹介していく連載。今回は、「Kustomize」を取り上げます。

PC用表示 関連情報
Share
Tweet
LINE
Hatena

 Kubernetesやクラウドネイティブをより便利に利用する技術やツールについて概要や使い方を凝縮して紹介していく本連載「Cloud Nativeチートシート」。今回は「Kustomize」を取り上げます。

複数環境の重過ぎKubernetesマニフェスト、どう管理すればいいのか

 Kubernetesへのデプロイは「マニフェスト」を使っている方が多いのではないでしょうか。手動でデプロイする場合であれば、下記のようなコマンドを実行すると思います。CI/CD(継続的インテグレーション/継続的デリバリー)ツールなどを使ってデプロイをする際でも、手動の場合と同じようにマニフェストを使うことがほとんどでしょう。

kubectl apply -f manifest.yaml

 このようにKubernetesでは、デプロイに関する記述をマニフェストというコードの形式で管理できるため、IaC(Infrastructure as Code)を手軽に実現できます。しかし、商用サービスを開発するようなケースでは、開発/試験/本番環境といった複数環境を利用することが求められます。このようなケースでは、例えば下記のような設定は、それぞれの環境において異なる値が設定される可能性があるため、環境差分としてこれらの情報を管理する必要があります。

  • アプリケーションのバージョン
  • 接続先のエンドポイント情報
  • データベースへのクレデンシャル情報

 では、どのようにしてこれらの環境差分を管理したらいいのでしょうか?

 CI/CDツールなどを利用している場合、CI/CDツールをメンテナンスする若干名しか詳細を把握しておらず「最終的に、どのような状態になるか」が分かりにくくなるため、IaCの実現に苦労している方も多いと思います。環境ごとにGitのブランチを分けたり、フォルダを分けたりして、環境ごとにそれぞれのマニフェストを管理している方もいるかもしれませんが、マニフェストの記述量が増えると、環境差分の管理が大変になります。ファイルやブランチで管理していると、環境間でのファイルやブランチのマージにおいて“漏れ”なども発生します(図1)。


図1

「Kustomize」とは

 そこで、「Kustomize」を利用すると、この環境差分の管理が簡単にできるようになります。Kustomizeでは、ベースとなるマニフェストと、そのマニフェストに対する環境差分を管理し、ベースのマニフェストに対して環境差分情報のパッチを当てるという形でデプロイするマニフェストを生成、管理します(図2)。


図2

 そのため、上述した問題点を解消し、複数環境で開発しないといけない場合でも手軽にIaCを実現できます。

 Kustomizeは、このように環境差分だけを管理し、同じ設定を重複して管理する必要がないため、「DRY(Don't Repeat Yourself)」の原則をサポートするためのツールと紹介されることもあります。

Kustomizeの構成

 Kustomizeの構成を簡単に説明すると、図3のようになります。


図3

 開発環境(dev)と商用環境(prod)へそれぞれ別の設定でデプロイしたいとしましょう。まず、環境共通のマニフェスト「base」を定義します。baseに対し、それぞれの環境用の差分を「overlay」(上書き用のパッチ)として用意します。最終的にそれぞれのパッチが適用されたマニフェストを生成することができます。

 具体的にファイル構成を見ていくと、次のようになります。

├── base
│   ├── deployment.yaml
│   ├── kustomization.yaml
│   └── service.yaml
└── overlays
    ├── dev
    │   ├── kustomization.yaml
    │   └── patch.yaml
    ├── prod
    │   ├── kustomization.yaml
    │   └── patch.yaml
    └── staging
        ├── kustomization.yaml
        └── patch.yaml

※本稿で利用しているサンプルは、「https://github.com/cloudnativecheetsheet/kustomize」から「git clone」コマンドで取得できるので、参考にしてください。

 フォルダ構成を見ると、baseとoverlaysの2つのフォルダを確認できます。baseのフォルダには、全ての環境のベースとなるマニフェストを管理し、overlaysフォルダにある環境ごとの管理フォルダ(dev、prod)で、環境ごとの差分となる設定ファイル(マニフェスト)をパッチとして管理します。

 各フォルダには、kustomizationファイル(kustomization.yaml)が配置されていますが、kustomizationファイルの中に環境ごとのパッチの処理を記述します。

 具体的な設定方法や適用イメージについては、後述の「Kustomizeを使ってみよう」で見ていきます。

Kustomizeのインストール

 Kustomizeを利用するには、「kubectl」コマンド組み込みのKustomizeを、「-k」オプションで利用する方法と、Kustomizeバイナリを導入してkustomizeコマンドで利用する方法があります。

 2020年12月の執筆時時点でKustomizeの最新バージョンは、3.8.7ですが、kubectl組み込みのKustomizeは2.0.3と若干古いバージョンとなっています(※kubectl組み込みのKustomizeも将来的にバージョンアップされる予定があります)。

 また、kubectlコマンドを利用する場合、「kubectl apply --dry-run=client -k」のように明示的に「--dry-run=client」オプションを付与しないと、「クラスタへのデプロイが発生します。kubectlコマンドを利用すると、生成されるYAMLを確認したかったのに、誤ってデプロイする」という可能性もあるので、Kustomizeを個別に導入することをお勧めします。

 本稿では、最新のKustomizeを個別に導入して解説します。

 インストール方法は、「curl」「bash」コマンドが使えるOSなら、「root」もしくは「sudo」ユーザーで下記コマンドを実行するだけです。

$ curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash

 インストーラがOSを自動的に判別し、適切なバイナリをインストールしてくれます。なおWindowsの場合は、bashがデフォルトでは利用できないので、Kustomizeのリリースサイトの「Assets」から、exeファイルをダウンロードしインストールしてください。直接端末からインターネットに接続できない環境で利用する場合も、上記のリリースサイトからバイナリをダウンロード、コピーして、インストールしてください。

 インストールが完了したら、シェルでkustomizeのコマンドやオプションを補完できるようにしておくと便利です。例えば、bashシェルの補完を利用するには、下記のようなコマンドを実行して、一度ログアウトしてログインし直します。

$ kustomize completion bash >> ~/.bashrc

 bash以外にも、「zsh」「fish」「PowerShell」などの補完もサポートしています。

Kustomizeを使って差分情報を管理する方法

 Kustomizeを使って差分情報を管理する方法は大きく2通りあります。

  1. patchマニフェストに差分を記述し、「kustomization」ファイルとは別ファイルとして管理
  2. プラグインを利用してkustomizationファイルに記述して管理

 基本的に差分が別ファイルにばらばらに管理されると、変更内容の全体を把握するのが大変なので、2のプラグインを利用する方法がお勧めです。プラグインを利用すると、コンテナイメージのバージョンや「ConfigMap」など、環境ごとに頻繁に変わる設定については、kustomizationファイルに簡易な記述をするだけでパッチを当てることができます。

 プラグインで対応できない場合は、1のpatchマニフェストを利用するとよいでしょう。

1.patch機能によるマニフェスト管理の実践

 ここでは、nginxのレプリカ数(replica)を、prod環境で「3」に変更します。

「base」フォルダ

 「deployment.yaml」「service.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.14.2
        ports:
        - containerPort: 80
base/deployment.yaml
kind: Service
apiVersion: v1
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: http
base/service.yaml

 baseのkustomization.yamlには先ほどのマニフェストへのパスを「resources」に定義します。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
base/kustomization.yaml

 baseのファイルが完成したら、baseディレクトリの親ディレクトリで下記のコマンドを実行すると、baseのファイルから生成される各環境のパッチを当てる前のマニフェストを確認できます。

$ ls -F
base/
$ kustomize build base
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
...

「overlays」フォルダ

 例ではdev、staging、prodと3つ挙げていますが、1つ実践してみれば、同じ要領で使えるので、ここではprodのみを対象にします。以下、prodディレクトリ以下にファイルを作成していきます。

 パッチ対象とパッチ内容「replicas: 3」を記述します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
overlays/prod/patch.yaml

 最後にoverlays/prodのkustomization.yamlを作成します。resourcesにはbaseへのパスを定義し、patchesには先ほどのパッチ内容を記述したマニフェストへのパスを定義します。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
resources:
  - ../../base
 
patches:
  - patch.yaml
overlays/prod/kustomization.yaml

 パッチを当てたマニフェストを出力してみます。baseディレクトリとoverlaysディレクトリを配置した親ディレクトリで下記のコマンドを実行します。

$ ls -F
base/ overlays/
$ kustomize build overlays/prod
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
...(中略)...
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx-deployment
...(中略)...

 1つのマニフェストとして出力されたことを確認できたかと思います。次にbaseマニフェストとの差分を確認してみましょう。

$ diff -u <(kustomize build base) <(kustomize build overlays/prod)
...
 spec:
-  replicas: 1
+  replicas: 3
   selector:
...

 上記のようにreplicasが3に変更されていることを確認できます。Kustomizeで生成されたマニフェストからKubernetesのリソースを作成するには、次のようにします。

$ kustomize build overlays/prod | kubectl apply -f - 

2.プラグインを利用したKustomizeの利用

 次に、Kustomizeが提供しているプラグインを使った差分管理の方法を見ていきます。プラグインを利用して、先ほどのreplicasの1を3に変更してみます。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
#patches:
#  - patch.yaml
# patchesの代わりにreplicasを利用して、deploymentのreplicasを設定
replicas:
  - name: nginx-deployment
    count: 3
overlays/prod/kustomization.yaml

 上記のように、replicasを記述して、「Deployment」のリソース名と変更するレプリカ数を記述するだけで、値を変更できます。

 patchはどのような変更にも対応できますが、プラグインが利用できる場合は、プラグインを利用すると、patchに比べて直感的に変更内容を指定できます。できるだけプラグインを利用して環境ごとにカスタマイズした方がいいでしょう。また、patchなしでbaseだけでマニフェストが適用できるようにしておけば、baseマニフェストのテストが簡単になり、環境個別の部分だけをpatchで記述すればよくなります。

主なプラグイン、17の使い方

 2020年12月の原稿執筆時点で、Kustomizeでは下記のプラグインを標準で提供しています。

プラグイン名 概要
resources Kustomizeで扱うマニフェスト、baseへのパスなどを定義
images imageのバージョンタグなどのパッチを定義
replicas replicasの値のパッチを定義
namespace デプロイ先のnamespaceのパッチを定義
namePrefix デプロイ名(metadata.name)に指定したプレフィックスを付与するパッチを定義
nameSuffix デプロイ名(metadata.name)に指定したサフィックスを付与するパッチを定義
commonLabels デプロイ対象全てに指定したラベルをmetadata.labelsに付与するパッチを定義。Deployment、「StatefulSet」「DaemonSet」については、「Pod Template」の「spec.template.metadata.labels」にも付与される
commonAnnotations デプロイ対象全てに指定したラベルをmetadata.annotationsに付与するパッチを定義。Deployment、StatefulSet、DaemonSetについては、Pod Templateのspec.template.metadata.annotationsにも付与される
configMapGenerator ConfigMapを生成するためのプラグイン。さまざまな生成方法をサポート
secretGenerator 「Secret」を生成するためのプラグイン。さまざまな生成方法をサポート
generatorOptions configMapGenerator、secretGeneratorなどのジェネレータープラグインで生成されるSecret、ConfigMapリソースの生成方法を定義
patches 任意のパッチを定義。「strategic-merge-style patch(SMP)」形式、もしくは「JSON Patch」形式で定義可能
patchesJson6902 任意のパッチを定義。patchesにおける「JSON Patch」形式のみを記述する場合に利用
patchesStrategicMerge 任意のパッチを定義。patchesにおける「strategic-merge-style patch(SMP)」
crds Kustomizeで「CustomResourceDefinition(CRD)」を扱う場合に、対象のCRDを指定
components 複数のオーバーレイ(overlays)から再利用可能な設定ロジックを定義。複数のオプション機能をサポートしているアプリケーションで、異なるオーバーレイでそれらのサブセットだけを有効にしたい場合に利用
vars あるリソースのフィールドから文字列を取得し、その文字列を別の設定値に挿入するために使用。例えば、「Service」で定義したサービス名(metadata.name)の名前をDeploymentで実行するPodのコマンドラインの引数(args)や環境変数(env)に渡すような使い方が可能

 以前は、「bases」も提供されていましたが、「resources」で代替可能となり、非推奨となりました。

 以下、主なプラグインを上記表の記述順に解説します。resourcesについては既に紹介しているので、解説は省略します。

images

 デプロイ対象のコンテナイメージを確認ごとに変更したいときに利用します。例えば、staging環境で新規イメージの動作を確認してから、prod環境のイメージを変更したいときなどに利用するとよいでしょう。パッチできる内容は下記の通りです。

フィールド 概要
name パッチ対象のコンテナイメージ名を指定
newTag コンテナイメージのtagを指定
digest コンテナイメージのdigestを指定
newName パッチ対象のコンテナイメージ名を変更したい場合に、変更後のイメージ名を指定

 例えば、イメージ名「nginx」のコンテナのタグに1.8.0を指定したい場合は、次のようにします。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
images:
  - name: nginx
    newTag: 1.8.0
overlays/prod/kustomization.yaml

 imagesプラグインによるbaseマニフェストからの差分を確認してみましょう。

$ diff -u <(kustomize build base) <(kustomize build overlays/prod)
-       - image: nginx:1.14.2
+       - image: nginx:1.8.0

 このように、イメージタグが変更され、古いイメージをデプロイできるようになりました。

replicas

 デプロイ対象のspec.replicasの値に変更するための機能です。以下のリソースを指定できます。

  • Deployment
  • ReplicaSet
  • StatefulSet
  • ReplicationController
フィールド 概要
name パッチ対象のリソース名(metadata/nameの値)を指定
count レプリカ数を指定

 利用方法については、Deploymentリソースのreplicasの変更例を既に紹介済みなので省略します。

namespace

 デプロイ対象のネームスペースを変更するための機能です。resourcesで指定したリソースの全てのネームスペースを指定した値に変更します。同一Kubernetesクラスタ内でネームスペースを変えて異なるステージング環境にデプロイしたいときなどに利用すると便利です。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
namespace: prod
overlays/prod/kustomization.yaml

 パッチの内容を確認してみましょう。

$ kustomize build overlays/prod
 
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: prod
spec:
  ... 省略
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx-deployment
  namespace: prod
spec:
  ... 省略

 7行目、17行目の通り、全てのリソースのネームスペースが変更されました。

namePrefix、nameSuffix

 デプロイ対象のリソース名の前にプレフィックスとサフィックスを付与するための機能です。例えば、namePrefixは「xxx」という名前のリソースに「pre-xxx」のようにリソース名の前にプレフィクスを追加できます。nameSuffixはリソース名の後ろに「xxx-post」のようにサフィックスを追加できます。

 ここでは、namePrefixの利用例を紹介します。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
namePrefix: pre-
overlays/prod/kustomization.yaml

 パッチの内容を確認してみましょう。

$ diff -u <(kustomize build base) <(kustomize build overlays/prod)
-   name: nginx-service
+   name: pre-nginx-service
...
-   name: nginx-deployment
+   name: pre-nginx-deployment

 また、このパッチは「PodSpec」から参照されているConfigMapやSecretのリソース名にも適用されます。

commonLabels

 全てのリソースに指定したラベルを追加します。ServiceやDeploymentのセレクタ(spec.selector)にもラベルが追加され、リソース参照の整合性を取るようになっています。

 例えば、次のように定義します。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
commonLabels:
  app: nginx
  environment: prod
overlays/prod/kustomization.yaml

 パッチの内容を確認してみましょう。

$ kustomize build overlays/prod
 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
    environment: prod
  name: nginx-service
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: http
  selector:
    app: nginx
    environment: prod
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
    environment: prod
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      environment: prod
  template:
    metadata:
      labels:
        app: nginx
        environment: prod
    spec:
      containers:
      - image: nginx:1.14.2
        name: nginx
        ports:
        - containerPort: 80

 6〜8行目、16〜17行目、22〜24行目、29〜31行目、34〜36行目の通り、ラベルが追加されているのを確認できます。

commonAnnotations

 リソースにアノテーションを追加します。デプロイしたリソースが明示的に「どの環境にデプロイしたものか」を分かりやすくするのに利用できます。現在チェックしているリソース環境の取り違いを防止できます。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
commonAnnotations:
  env: prod**
overlays/prod/kustomization.yaml

 パッチの内容を確認してみましょう。

$ kustomize build overlays/prod
 
apiVersion: v1
kind: Service
metadata:
  annotations:
    env: prod
  name: nginx-service
spec:
 ... 省略
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    env: prod
  labels:
    app: nginx
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      annotations:
        env: prod
... 省略

 6〜7行目、15〜16行目、27〜28行目の通り、アノテーションが追加されているのを確認できます。

configMapGenerator

 configMatpGeneratorは、ConfigMapリソースを作成するための機能です。例えば、baseで次のように定義します。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
configMapGenerator:
- name: my-configmap
  files:
  - common.properties
  literals:
  - port=8080
base/kustomization.yaml

 nameにConfigMap名を、filesにプロパティが記述されたファイルパスを、literalsでプロパティを指定します。ここでは、filesで指定するプロパティファイルに、下記を作成してみます。

proxy=proxy.example.com
base/common.properties

 ファイルが準備できたら、baseディレクトリでkustomizeを実行して確認してみます。

$ kustomize build .
 
apiVersion: v1
data:
  common.properties: |
    proxy=proxy.example.com
  port: "8080"
kind: ConfigMap
metadata:
  name: my-configmap-g5c5m5cdtb

 kind(8行目)とmetadata(10行目)の位置が通常と異なるので分かりづらいですが、ConfigMapリソースの定義が作成されているのを確認できます。

 またリソース名には、「my-configmap」と指定したリソース名に「-g5c5m5cdtb」というように、configMapGeneratorで定義された内容からハッシュ値が追加され、定義した内容に対し、値が一意の値になっています。

 次に、prod環境のkustomizationファイルと設定を準備します。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
configMapGenerator:
- name: my-configmap
  behavior: merge
  files:
  - env.properties
  - secret.properties
overlays/prod/kustomization.yaml

 ConfigMapGeneratorのbehaviorにmergeを指定してbaseと同様に定義していきます。「merge」と記載すると、baseの内容とprodに記載した内容をマージします。replaceとすると、baseで定義した内容が上書きされます。

 ここでは、下記のプロパティファイルを用意します。

host=prod-server.example.com
overlays/prod/env.properties
proxyPassword=proxyPasswordForProd
overlays/prod/secret.properties

 baseとprodの差分を確認してみます。

$ diff -u <(kustomize build base) <(kustomize build overlays/prod)
...
 data:
   common.properties: |
     proxy=proxy.example.com
+  env.properties: |
+    host=prod-server.example.com
   port: "8080"
+  secret.properties: |
+    proxyPassword=proxyPasswordForProd
 kind: ConfigMap
 metadata:
-  name: my-configmap-g5c5m5cdtb
+  annotations: {}
+  labels: {}
+  name: my-configmap-5kfgt2259c

 prodのconfigMapGeneratorで追加したプロパティが追加されているのが分かります。また、ConfigMapの内容が変更になったので、リソース名に付与されたハッシュ値が「g5c5m5cdtb」から「5kfgt2259c」に変更されているのが分かります。リソース名にハッシュ値が追加されていますが、DeploymentリソースなどでConfigMapを参照している場合は、自動的にハッシュ値が付与されたConfigMapのリソース名に変更され、整合性が自動的に取られます。

 毎回ハッシュ値が追加されてリソース名が変更されるのが嫌な場合は、後述のgeneratorOptionsの「disableNameSuffixHash」で「false」と設定します。

secretGenerator

 configMapGeneratorと同様にSecretリソースを生成するための機能です。configMapGeneratorと使い方はほぼ同じで、追加でSecretリソースの「type」フィールドを定義できるようになっています。他の点は、configMapGeneratorと同様なので、事前にconfigMapGeneratorを一読してください。

 例えば、baseで次のように定義します。typeにはSecretリソースのtypeで指定する「Opaque」「kubernetes.io/tls」などの値を定義します。ここでは、kubernetes.io/tlsを利用した例を紹介します。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
  - name: app-tls
    files:
      - "tls.crt"
      - "tls.key"
    type: "kubernetes.io/tls"
base/kustomization.yaml

 base/kustomization.yamlでは、証明書や秘密鍵を下記のように指定します。

-----BEGIN CERTIFICATE-----
MIID1zC...
(中略)
-----END CERTIFICATE-----
base/tls.crt(証明書)
-----BEGIN PRIVATE KEY-----
MIIEvgI....
(中略)
-----END PRIVATE KEY-----
base/tls.key(秘密鍵)

 ファイルが準備できたら、baseディレクトリでkustomizeを実行して確認してみます(4〜5行目、8〜9行目)。

$ kustomize build .
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJ...
  tls.key: LS0tLS1CRUdJTiBQUkl...
kind: Secret
metadata:
  name: app-tls-tf8km6hb9h
type: kubernetes.io/tls

 prodについてはconfigMapGeneratorと同様に記述することができます。

generatorOptions

 configMapGeneratorやsecretGeneratorで生成するマニフェストにannotations、labelsを付与できます。また、generatorによって生成されたマニフェストのnameにはハッシュ値が付与されますが、disableNameSuffixHashによってこのハッシュ値を付与するかどうかを制御できます。

 例えば、baseで次のように定義します。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
  - name: app-tls
    files:
      - "tls.crt"
      - "tls.key"
    type: "kubernetes.io/tls"
generatorOptions:
  labels:
    kustomize.generated.resources: base
  annotations:
    kustomize.generated.resource: base
  disableNameSuffixHash: true
base/kustomization.yaml

 ファイルが準備できたら、baseディレクトリでkustomizeを実行して確認してみます。

$ kustomize build .
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJ...
  tls.key: LS0tLS1CRUdJTiBQUkl...
kind: Secret
metadata:
  annotations:
    kustomize.generated.resource: base
  labels:
    kustomize.generated.resources: base
  name: app-tls
type: kubernetes.io/tls

 annotations(9行目)、labels(11行目)に値が付与されていることが分かります。また、nameの値にハッシュ値が付与されていないことを確認できます(12行目)。

patches、patchesJson6902、patchesStrategicMerge

 patches、patchesJson6902、patchesStrategicMergeは任意のパッチを適用するための機能です。patchesがサポートしているパッチの定義方法は下記リストの通りです。「記述スタイル」「記述箇所」「パッチ対象」を組み合わせることで複数の方法でパッチ定義を表現できます。

  • 記述スタイル
  • 記述箇所
    • ファイル
    • インライン文字列
  • パッチ対象
    • 単一リソース
    • 複数リソース

 まずは、基本構文から解説し、JSON Patch、SMPのそれぞれの記述スタイルによる定義方法を解説していきたいと思います。なお、patchesJson6902はJSON Patchの記述スタイルのみ、patchesStrategicMergeはSMPの記述スタイルのみのサポートとなります。patchesでどちらの形式もサポート可能なので、patchesのみを対象に解説します。

 パッチは、次のフォーマットで記述します。

patches:
  - path: パッチ内容を記述したファイルへのパス
    target:
      group: パッチ対象のリソースのgroupを指定
      version: パッチ対象のリソースのversionを指定
      kind: パッチ対象のリソースのkindを指定
      name: パッチ対象のリソースのmetadata.nameを指定。正規表現でも記述することが可能
      namespace: パッチ対象のリソースのnamespaceを指定
      labelSelector: パッチ対象のリソースに設定されているmetadata.labelsに対するラベルセレクタを指定
      annotationSelector: パッチ対象のリソースに設定されているmetadata.annotationsに対するセレクタを指定
kustomization.yaml

 パッチ内容を別ファイルではなく、kustomization.yamlファイル内にインライン文字列として記述することもできます。

patches:
  - patch: |-
      パッチ内容をインライン文字列で記述
    ...
kustomization.yaml

・JSON Patchの記述スタイル

 JSON Patchを利用するとパッチをJSON形式で記述することもできます。ここでは、「overlays/prod/patch.json」ファイルにnginxのDeploymentに「livenessProbe」を追加するパッチを定義します。

[
  {
    "op": "add",
    "path": "/spec/template/spec/containers/0/livenessProbe",
    "value": {
      "httpGet": {
        "port": 80,
        "path": "/"
      },
      "failureThreshold": 5,
      "periodSeconds": 5
    }
  }
]
overlays/prod/patch.json

 「op」に変更操作(ここでは追加「add」)を、「path」に変更するパスを、「value」に内容を追加します。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
resources:
  - ../../base
patches:
  - path: patch.json
    target:
      group: apps
      version: v1
      kind: Deployment
      name: nginx-deployment
overlays/prod/kustomization.yaml

 パッチの内容を確認してみましょう。

$ kustomize build overlays/prod
 
...
---
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.14.2
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /
            port: 80
          periodSeconds: 5
        name: nginx
        ports:
        - containerPort: 80

 23〜28行目にある通り、nginxのDeploymentにlivenessProbeが追加できていることを確認できました。

 次にインライン文字列で定義する方法を解説します。パッチの内容は先ほどと同様です。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
patches:
  - patch: |-
      - op: add
        path: /spec/template/spec/containers/0/livenessProbe
        value: 
          httpGet:
            port: 80
            path: /
          failureThreshold: 5
          periodSeconds: 5
    target:
      group: apps
      version: v1
      kind: Deployment
      name: nginx-deployment
overlays/prod/kustomization.yaml

 結果を確認すると、ファイルで定義した場合と同様な結果が得られることが分かります。target.nameには「nginx-.*」のように正規表現を指定でき、パターンにマッチするリソースを一括して指定可能です。

・SMPの記述スタイル

 次に、もう一つの記述スタイルであるSMPを解説していきます。パッチを記述すファイルは、「overlays/prod/patch.yaml」とします。先ほどと同じnginxのDeploymentにlivenessProbeを定義するパッチは下記のようになります。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  template:
    spec:
      containers:
      - name: nginx
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /
            port: 80
          periodSeconds: 5
overlays/prod/patch.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
patches:
  - path: patch.yaml
    target:
      group: apps
      version: v1
      kind: Deployment
      name: nginx-deployment
overlays/prod/kustomization.yaml

 kustomizationファイル内で下記のようにインラインでも記述できます。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
patches:
  - patch: |-
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nginx-deployment
      spec:
        template:
          spec:
            containers:
            - name: nginx
              livenessProbe:
                failureThreshold: 5
                httpGet:
                  path: /
                  port: 80
                periodSeconds: 5
    target:
      group: apps
      version: v1
      kind: Deployment
      name: nginx-deployment
overlays/prod/kustomization.yaml

vars

 あるリソースのフィールドから文字列を取得し、その文字列を別の設定値に挿入できます。例えば、Serviceで定義したリソース名(metadata.name)をDeploymentで実行するPodのコマンドラインの引数(args)や環境変数(env)に渡すような使い方が可能なので、自サービスの公開サービス名を確認変数から渡したいケース、互いのサービスを呼び出すようなケースなどで利用できます。

 サンプルを見ていきましょう。まずは下記のようにbaseに変数を用意しておきます。変数は「$(変数名)」のように設定します(24行目)。

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.14.2
        ports:
        - containerPort: 80
        env:
        - name: NGINX_HOST
          value: $(NGINX_SERVICE)
base/deployment.yaml

 続いて、overlays/prodで「$(NGINX_SERVICE)」に値を代入します。「objref」「fieldref」を用いて代入する値の取得元を指定します。objrefにはKubernetesのオブジェクト名を、fieldrefには当該オブジェクトにおける値の取得元フィールドを指定します。fieldrefは省略可能で、省略するとリソース名がデフォルト値になります。ここでは、代入する値はnginxのServiceリソースのリソース名とする例を示します。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
vars:
  - name: NGINX_SERVICE
    objref:
      kind: Service
      apiVersion: v1
      name: nginx-service
    fieldref:
      fieldpath: metadata.name
overlays/prod/kustomization.yaml

 パッチを適用した結果を確認してみましょう。

$ kustomize build overlays/prod
 
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: http
  selector:
    app: nginx
---
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:
      - env:
        - name: NGINX_HOST
          value: nginx-service
        image: nginx:1.14.2
        name: nginx
        ports:
        - containerPort: 80

 $(NGINX_SERVICE)にnginxのServiceリソースのリソース名nginx-serviceが代入されたことを確認できました(34行目)。

 変数に代入できる箇所は決まっており、「/api/konfig/builtinpluginconsts/varreference.go」に記述されている箇所のみなので、注意が必要です。

 デフォルトで代入できない場所に変数を代入したい場合は、「configurations」と「varReference」を利用します。varReferenceファイルに変数を代入するパスを指定しconfigurationsでvarReferenceファイルを指定します。記述方法は、参照先と同様にkustomization.yamlに記述します。

 試しに、下記のようにbase/deployment.yamlに変数を設定してみます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      service: $(NGINX_SERVICE)
  template:
    metadata:
      labels:
        app: nginx
        service: $(NGINX_SERVICE)
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
        env:
        - name: NGINX_HOST
          value: $(NGINX_SERVICE)
base/deployment.yaml

 すると、下記の26行目、31行目のように変数に値が代入されていないことが分かります。

$ kustomize build base
 
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: http
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      service: $(NGINX_SERVICE)
  template:
    metadata:
      labels:
        app: nginx
        service: $(NGINX_SERVICE)
    spec:
      containers:
      - env:
        - name: NGINX_HOST
          value: nginx-service
        image: nginx:1.14.2
        name: nginx
        ports:
        - containerPort: 80

 上記に対し、configurations、varReferenceを使って変数に値を代入できるようにします。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
vars:
  - name: NGINX_SERVICE
    objref:
      kind: Service
      apiVersion: v1
      name: nginx-service
    fieldref:
      fieldpath: metadata.name
configurations:
  - varReference.yaml
overlays/prod/kustomization.yaml

 overlays/prod/varReference.yamlには、/api/konfig/builtinpluginconsts/varreference.goに記述されているように、「kind」「path」を使って変数を代入するリソースとパスを指定します。

varReference:
  - path: spec/selector/matchLabels/service
    kind: Deployment
  - path: spec/template/metadata/labels/service
    kind: Deployment
overlays/prod/varReference.yaml

 パッチを提供すると、先ほどまで変数に置換されていなかった値が変数で置換されていることを確認できます。

$ kustomize build prod
...
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      service: nginx-service
  template:
    metadata:
      labels:
        app: nginx
        service: nginx-service
    spec:

 14行目、19行目のように指定した箇所の変数にも値が代入されていることを確認できました。

Kustomizeをカスタマイズ

 Kustomizeではプラグインの仕組みが提供されており、自分でもパッチ機能を作ることができます。今まで紹介した機能もプラグインの仕組みで実現しています。

 今回は解説しませんが、ご興味がある読者の方は「Extending Kustomize」をぜひ確認してみてください。

「Helm」との使い分け

 Kustomize以外にも、アプリケーションをデプロイするためのツールとして「Helm」があります。

 Helmは、Kubernetes上でのパッケージマネジャーとして、広く利用されています。Linuxを利用したことがある読者なら「yum」「RPM」、macOSを利用しているなら「Homebrew」などのツールと同類と考えると理解しやすいでしょう。

 Helmは次回紹介しますが、使い分けの観点で簡単に比較しておきます。

メリット デメリット
Kustomize ・学習コストが低い
・Kubernetes標準のコマンドラインツールに統合されている
・カスタマイズしやすい(Kustomizeというだけある……)
・さまざまな設定が想定されるようなアプリケーションでは、利用者側のカスタマイズが多くなり利便性が下がる
Helm ・配布の仕組みが整っている
・条件分岐などが記述できるので、さまざまな設定が想定されるアプリケーションの管理に向いている
・Helmの記述方法を学習するコストが高い
・「どこまで共通的に利用できるテンプレートにすべきか」の設計が難しい
・テンプレートに書いてある以上のことができないので、カスタマイズ性が低い
・設定値がどのように反映されるのか把握しにくい

 上記の比較を踏まえ、自分が開発、運用しているシステム内のマイクロサービスをデプロイするためのツールはKustomizeが適していると筆者は考えます。また、Helmは公開されているアプリケーションをKubernetes上にデプロイ(インストール)する、もしくは自分のアプリケーションを公開するツールとして利用することに適していると考えています。

まとめ

 今回は、Kustomizeについて、基本的な機能を一通り紹介しました。Kustomizeは、複数環境でのCI/CDを実施していく上で今後、必須のツールになります。「複数環境のマニフェストの管理が煩雑だ」と感じた人はぜひ使ってみてください。また、これからCI/CDを始める人は、Kustomizeを前提にCI/CDを設計することをお勧めします。

今回のサンプル

Copyright © ITmedia, Inc. All Rights Reserved.

[an error occurred while processing this directive]
ページトップに戻る