HEARTBEATS

KustomizeとComponentsの利用例の紹介

   

技術開発チームの基盤システム担当の小倉です。

最近、社内システム用のコンテナ基盤をDockerからマネージドKubernetesサービスであるAmazon EKSとAzure Kubernetes Serviceに移設しました。その際に、Kubernetesのマニフェストの管理にオープンソースのKustomizeを利用しました。

私自身は実際に動かすことでKustomizeについての理解が進みました。そのため、本ブログはハンズオン形式でKustomizeを紹介します。ぜひ、手元で動かしていただけましたら幸いです。

Kustomizeとは

公式ドキュメントから引用すると以下のとおりです。

KustomizeはKubernetesマニフェストを横断し、フォークすることなく設定オプションを追加、削除、更新します。スタンドアロンバイナリとしてもkubectlのネイティブ機能としても利用可能です。

※ 参照:https://kustomize.io/

本ブログ内ではkustomizeコマンド(スタンドアロンバイナリ)を利用します。インストール手順は以下をご参照ください。
https://kubectl.docs.kubernetes.io/installation/kustomize/

kustomizeを使うには、kustomization.yamlというファイルが必要です。Kubernetesに適用する際には、kustomize buildコマンドでkustomization.yamlを基にマニフェストをビルドし、パイプでkubectlコマンドに渡して利用します。

$ kustomize build {kustomization.yamlがあるディレクトリ} |kubectl apply -

例の紹介

この例で利用しているサンプルは以下で公開しています。
https://github.com/heartbeatsjp/kustomize_samples

実例を紹介します。このセクションでは、./firstディレクトリのサンプルを利用しています。

first_1.png

まずはresourcesセクションに注目します。resourcesは他のkustomizationもしくはマニフェストファイルを読み込むセクションです。この例では、./overlays/production./overlays/stagingがそれぞれ、./baseを指定しています。この両者の関係において、./overlays/production./overlays/stagingオーバーレイbaseベースと呼ばれます。 参照する側と参照される側の関係を示しており、以下のように数珠つなぎで参照できます。

Overlay → Base(Overlay) → Base(Overlay) → Base

この例では、baseを指定してビルドすると、./base/deployment.yamlの内容がそのまま出力されます。 これは./base/kustomization.yml./base/deployment.yamlを読み込んでいるだけだからです。diffコマンドで差分がないことを確認できます。

$ diff base/deployment.yaml <(kustomize build base/)

次に、./overlays/productionを指定してビルドした場合との差分を確認します。

$ diff -u <(kustomize build base/) <(kustomize build overlays/production/)
...省略...
     name: hello-world
-  name: hello-world
+  name: production-hello-world
 spec:
-  replicas: 1
+  replicas: 4
   selector:

nameとreplicasに差分がでました。図で示すと以下のような流れになります。

first_2.png

また、./overlays/production./overlays/stagingを比較すると以下のようになります。

$ diff -u <(kustomize build overlays/staging/) <(kustomize build overlays/production/)
...省略...
     name: hello-world
-  name: staging-hello-world
+  name: production-hello-world
 spec:
-  replicas: 2
+  replicas: 4
   selector:

このようにベースのパラメータを環境ごとに変更できます。続いて、パラメータを変更した機能であるパッチやトランスフォーマー、コンポーネントといった機能を紹介していきます。

パッチ(JSON6902 patches)

replicasの値を上書きした機能のことをパッチと呼びます。 パッチには、JSON6902 patchesstrategic merge patchの2つの記法が利用できます。 本ブログ内では、より簡潔な構文をもつJSON6902 patchesの記法を利用します。

JSON6902の6902はRFCの番号です。構文や機能の詳細はRFCをご参照ください。

https://datatracker.ietf.org/doc/html/rfc6902

パッチはkustomization.ymlファイルにインラインで書くこともできます。前述のreplicasの上書きをインラインで記載すると以下のようになります。pathでファイルを指定していた部分をpatchに置き換え、その後にファイルの中身を指定しています。インデントに注意してください。

patches:
  - patch: |-
      - op: replace
        path: /spec/replicas
        value: 4
    target:
      kind: Deployment

実際に書き換えの処理を記載しているのは、oppathvalueブロックです。opに操作の種類を、pathにどの部分を操作するのかを、valueに適用する値を指定します。

pathは「操作対象の値のキー」からトップレベルまで遡って/で区切ります。配列にアクセスする場合は以下のようにインデックスを指定します。

      - op: replace
        path: /spec/template/spec/containers/0/image
        value: hello-world-staging

また、上の例でtargetにkind: Deploymentと指定していますが、この場合は全てのDeploymentリソースに適用されます。特定のリソースにのみ適用したい場合は、name: hello-worldなどの固有のパラメータも追加して指定する必要があります。

配列への追加(add)

このセクションでは、./patch_addディレクトリのサンプルを利用しています。

opOperations)にはreplaceの他にもadd、removeなどが指定できます。addは配列に要素を追加する場合に利用します。環境変数のように複数パラメータを配列で指定する際に利用します。以下が利用例です。

patch.png

差分を確認すると配列に要素を追加できていることがわかります。

$ diff -u <(kustomize build base/) <(kustomize build overlays/production/)
...省略...
         - name: DB_USER
           value: dbuser
+        - name: DB_PASSWORD
+          value: production-password
         image: hello-world
         name: hello-world

配列に追加する際は、path: /spec/template/spec/containers/0/env/-のように最後にハイフンを指定する点がポイントです。

コンポーネント(Components)

このセクションでは、./components_kustomizeディレクトリのサンプルを利用しています。

コンポーネントとはv3.7.0から利用できる機能です。 https://kubectl.docs.kubernetes.io/guides/config_management/components/では以下のように説明されています。

コンポーネントは複数のオプション機能をサポートするアプリケーションを扱うときに便利で、異なるオーバーレイでそれらのサブセットのみを有効にしたい場合、つまり、異なる環境やオーディエンスに対して異なる機能を有効にしたい場合に使用します。

先ほどまでの例でコンポーネントは利用していませんが、環境(オーバーレイ)ごとにパラメータを調整できました。最小限の例でしたが、機能単位での追加も可能に見えます。Kustomizationとの違いは以下に説明があります。

https://github.com/kubernetes/enhancements/tree/master/keps/sig-cli/1802-kustomize-components#proposal

コンポーネントとしてマークされたKustomizationは基本的に通常のKustomizationと同じ機能を持ちます。 主な違いは、親Kustomization(オーバーレイまたはコンポーネント)のリソースが蓄積された後、その上で評価されることです。

例を基にKustomizeとコンポーネントの違いを紹介します。

component_kustomize_1.png

まず、コンポーネントはapiVersionとkindが異なります。(Kustomizeは省略できるため記載していません)そして呼び出すときも、resourcesではなく、componentsに指定します。

./overlays/componentsは、baseとcomponentsを読み込み、./overlays/kustomizeは、baseとkustomizeを読み込みます。 コンポーネント以外は同じ内容でビルドし、両者の違いを確認します。

$ diff -u <(kustomize build overlays/kustomize/) <(kustomize build overlays/components/)
...省略...
   name: hello-world
 spec:
-  replicas: 1
+  replicas: 4
   selector:
     matchLabels:

kustomizeの方がreplicasの値を変更できていません。これはkustomizeの影響範囲は親Kustomizationには及ばないためです。先ほど引用したコンポーネントの違いのように説明すると、「2つのベースのリソースが蓄積されずに評価が完了し、別のベースへのパッチが反映されなかった」ということになります。

コンポーネントは親のKustomization(オーバーレイ)に影響を与えられるため、親Kustomizationでpatchを書いたときと同じ効果が得られます。この特性はコンポーネントを使ううえでの注意点にもなります。コンポーネントでNamespacenamePrefixなどを定義すると親Kustomizationまで影響してしまうためです。親Kustomizationに影響するということは、そのKustomizeの配下の全てのリソースに影響し、全てのリソースのNamespaceやリソース名を変えてしまうことになります。

影響範囲のイメージを図に示します。

components_kustomize_2.png

コンポーネントの利用例

コンポーネントを利用して、Ingressにパッチを適用する例を紹介します。このセクションでは、./componentsディレクトリのサンプルを利用しています。

components.png

./base/ingress.yamlにてrules: []のようにすると、配列を空の状態で定義できます。productionは2つのコンポーネントを参照し、stagingは1つのコンポーネントを参照します。

productionをターゲットにビルドした際のIngressリソースは以下のとおりとなります。

$ kustomize build overlays/production/
...省略...
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kustomize-ingress
spec:
  rules:
  - host: hello-world.net
    http:
      paths:
      - backend:
          service:
            name: hello-world
            port:
              number: 8000
        path: /
        pathType: Prefix
  - host: hello-kustomize.net
    http:
      paths:
      - backend:
          service:
            name: hello-kustomize
            port:
              number: 8000
        path: /
        pathType: Prefix

もとは空の配列であったIngressのrulesに2つ追加されていることがわかります。stagingは./components/hello-worldしか参照していないためその分のルールだけ追加されます。./components/hello-world./components/hello-kustomizeはそれぞれDeploymentとServiceのマニフェストファイルを読み込んでいます。コンポーネントを使うことでDeployment、Service、Ingressのルールを1つのサービス・機能としてまとめて管理できます。

これをコンポーネントなしで実現しようとすると環境ごとにIngressを整備するか、親Kustomizationでパッチをそれぞれ定義する必要があります。追加削除の変更が大きくなりますし、共通リソースに手を加えなければなりません。 コンポーネントを利用すればオーバーレイから参照するか否かだけでデプロイを制御し、機能のセットを追加できます。

トランスフォーマー(Transformer)

トランスフォーマーについて詳しい説明は以下のリンクにあります。

https://github.com/kubernetes-sigs/kustomize/blob/master/examples/transformerconfigs/README.md

以下、概要の引用です。

Kustomize は元のリソース セットに一連の変換を適用することで新しいリソースを作成します。 Kustomize は以下のデフォルトのトランスフォーマーを提供します:

上記のように便利なものがあらかじめいくつか用意されています。すでに本ブログではprefixはnamePrefixとして利用しました。引用にもあるとおり、元の値の変換を行えることがパッチとの違いになります。またトランスフォーマーの中にはkustomizeコマンドにサブコマンドが用意されているものもあり、手順やCIの作成に便利です。

その他活用例

CIでのイメージタグの更新

ビルドしたアプリケーションのコンテナのタグをマニフェストへ反映するためにKustomizeの機能を活用できます。Gitlab CIによる例を以下に紹介します。

...省略...
  script:
    - git clone git@gitlab.xxxxx.jp:kube/manifest.git --single-branch --branch main manifest && cd cd-manifest
    - git checkout -b update_image_tag
    - cd overlays/production
    - kustomize edit set image ${IMAGE_URL}=:${IMAGE_TAG}
    - git commit -am "update image tag"
    - git push origin update_image_tag -o merge_request.target=main -o merge_request.create

環境ごとのパッチを適用する

パスワードやバックエンドのアクセス先名など環境ごとに変更したい場合があります。その場合は、以下のようにコンポーネントをさらにもう1階層作成すると環境ごとのパッチを適用できます。

./app
├── common
│   ├── deployment.yml
│   ├── ingress-patch-domain.yml
│   ├── kustomization.yml
│   └── service.yml
├── production
│   ├── deployment-env-patch.yml
│   └── kustomization.yml
└── staging
    ├── deployment-env-patch.yml
    └── kustomization.yml

productionとstagingはそれぞれcommonを参照し、オーバーレイからproductionとstagingをコンポーネントとして参照します。

おわりに

これまで紹介したようにKustomizeを利用することで、複数環境のマニフェストを共通化して管理できます。本ブログで紹介した以外にも機能をもっており、またHelmやArgoCDとの連携なども可能で使い勝手の良いものです。

Kustomizeを利用している方や利用を検討している方に本ブログが参考となれば幸いです。

株式会社ハートビーツの技術情報やイベント情報などをお届けする公式ブログです。



ハートビーツをフォロー

  • Twitter:HEARTBEATS
  • Facebook:HEARTBEATS
  • HATENA:HEARTBEATS
  • RSS:HEARTBEATS

殿堂入り記事