Kustomizeでできること一覧

Kubernetesのマニフェストを書いていくと、環境(本番やStagingなど)ごとに重複するコードが出てきます。
そのため環境差分だけどこかに切り出したいなーと思うことがあるでしょう。
そういったときに使えるのがKustomizeというツールです。

今回はKustomizeでできることを **自分が知り限りの範囲で列挙** していきます。(適宜更新していきます。)
インストール方法は公式ドキュメントをご覧ください。

今回ここでご紹介する機能以外にも機能があるので
興味がありましたら[ドキュメント](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/)をご覧ください。

# 環境ごとにイメージのタグを変える
例えば `nginx` というコンテナイメージがあるとして
本番では `v1.8.0`、Stagingでは `v1.9.0` をデプロイしたいとします。
普通にマニフェストを書くと、イメージのタグが違うだけのDeploymentのマニフェストが2つできて無駄です。

そのような場合、以下のように環境ごとに設定を行うことができます。
sampleコードは[こちら](https://github.com/morix1500/sample-kustomize/tree/main/1)

```base/deploymet.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: sample
        ports:
        - containerPort: 80
```

```overlays/staging/kustomization.yaml
resources:
  - ../../base
images:
  - name: sample
    newName: nginx
    newTag: 1.19.0
```

`images.name` で、Deploymentで指定しているイメージ名を指定できます。この名前は自由に決められます。
`images.newName` で正しいイメージ名を指定します。
`images.newTag` で指定したいタグ名を指定します。

このようにすると、環境ごとに異なるタグを指定することが実現できます。

# 環境ごとにマニフェストの要素を書き換える
イメージタグ名以外の環境差分ももちろん表現することができます。
sampleコードは[こちら](https://github.com/morix1500/sample-kustomize/tree/main/2)

例えばDeploymentで定義するレプリカ数を本番だけ `2` にしたいとしましょう。
そういう場合以下のように書くことができます。

```overlays/production/kustomization.yaml
resources:
  - ../../base
patches:
  - deployment.yaml
```

```overlays/production/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 2
```

kustomization.yamlのpatchesで、上書きしたい要素のみを指定したマニフェストを指定することで
Kustomizeがうまいことマージしてくれます。

ちなみに要素を削除したい場合、以下のように実現できます。
argsという要素を消したい場合・・・

```overlays/production/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  template:
    spec:
      containers:
        - name: nginx
          args: null
          # 比較的新しいKustomizeのバージョンを使用している場合は以下の書き方のほうがわかりやすい
          # args:
          #  $patch: delete
```

# 配列内の要素を書き換える
上記のpatchのやり方だと難しいのが、配列に対する変更です。
例えば、配列の0番目の要素のみ書き換えた場合、上記のやり方だとできません。
そのようなことがやりたい場合は、`patchesJSON6902 ` を使用します。
sampleコードは[こちら](https://github.com/morix1500/sample-kustomize/tree/main/3)

たとえば以下のようなDeploymentがあったとして、argsの2番目の値を変えたいとします。

```base/deploymet.yaml
# 必要なところだけ抽出します
      containers:
      - name: nginx
        image: nginx:1.19.0
        args:
        - hoge
        - fuga
        ports:
        - containerPort: 80
```

これを書き換えるには以下のようにします。

```overlays/production/kustomization.yaml
resources:
  - ../../base
patchesJSON6902:
  - target:
      group: apps
      version: v1
      kind: Deployment
      name: sample-deployment
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0/args/1
        value: piyo
```

`patchesJSON6902` はその他にも `metadata.name` を変更できます。
通常のpatchはこの `metadata.name` を元にマージ戦略を考えますが、それ自体を変更するとなると `patchesJSON6902` を使う必要があります。

# リソースを配置するnamespaceを環境ごとに変える
例えば本番とStagingが同じk8sクラスタに存在した場合、namespaceで分けたいことがあると思います。
それもKustomizeで簡単に実現できます。
sampleコードは[こちら](https://github.com/morix1500/sample-kustomize/tree/main/4)

`namespace` をkustomization.yamlで書くだけです。

```overlays/production/kustomization.yaml
namespace: production
resources:
  - ../../base
```

これをbaseのkustomization.yamlに書けば、全環境でリソースの配置場所を統一することもできます。

# リソース名にPrefix/Suffixをつける
kustomization.yamlで指定されているリソースに関して、統一したPrefix/Suffixを付与することができます。
sampleコードは[こちら](https://github.com/morix1500/sample-kustomize/tree/main/5)

```overlays/production/kustomization.yaml
namePrefix: hoge-
nameSuffix: -fuga
resources:
  - ../../base
```

```bash
$ kustomize build overlays/production/
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hoge-sample-deployment-fuga
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.19.0
        name: nginx
        ports:
        - containerPort: 80
```

# ファイルを元にしたConfigMap/Secretの生成
ConfigMapの中身はなんらかの設定ファイルだったり環境変数が入ったりします。
それらをConfigMapのマニフェストファイルに入れていると、編集しづらいです。

また、ConfigMapのリソース名は中身のデータを変更したとしても名前は変わりません。
そのため、そのConfigMapに依存しているDeploymentなどの更新にも気を使わないといけません。

それらの解決のために `configMapGenerator` を使用します。
sampleコードは[こちら](https://github.com/morix1500/sample-kustomize/tree/main/6)

```overlays/production/kustomization.yaml
resources:
  - ../../base
configMapGenerator:
  - name: hoge-files
    files:
      - files/hoge.txt
  - name: hoge-envs
    envs:
      - files/hoge.env
```

```bash
$ kustomize build overlays/production/
apiVersion: v1
data:
  hoge: fuga
kind: ConfigMap
metadata:
  name: hoge-envs-5hkfff6687
---
apiVersion: v1
data:
  hoge.txt: |
    hoge!!
kind: ConfigMap
metadata:
  name: hoge-files-2bmb5dcchd
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - envFrom:
        - configMapRef:
            name: hoge-envs-5hkfff6687
        image: nginx:1.19.0
        name: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /test
          name: hoge-config
      volumes:
      - configMap:
          name: hoge-files-2bmb5dcchd
        name: hoge-config
```

ご覧のように、`configMapGenerator` で指定したファイルやenvファイルを元にConfigMapが生成されています。
また、リソース名の末尾にハッシュ値がついています。
これはConfigMap内のデータが変更されるたびに変更されるハッシュ値です。
またこの名前は自動的にDeploymentで指定しているConfigMapの名前のところも書き換えてくれます。（上記の`kustomize build` 実行結果参照)

このようにすることで、Deploymentの参照するConfigMapが変わりますので自動でPodが再生成されますし、
ロールバックする際も一つ前のConfigMapはそのまま残っているので簡単です。

なお、この末尾ハッシュ値が不要な場合は、kustomization.yamlで以下のように記述すれば末尾につかなくなります。

```kustomization.yaml
generatorOptions:
  disableNameSuffixHash: true
```

ここまでConfigMapの話をしましたが、Secretも同様に `secretGenerator` というものがあります。
使い方はConfigMapと同じです。

# カスタムリソースで参照しているConfigMapの名前も自動更新させる
configMapGeneratorの項目で
>またこの名前は自動的にDeploymentで指定しているConfigMapの名前のところも書き換えてくれます。

という話をしました。
これはKubernetesがデフォルトで用意しているリソースの話で、カスタムリソースでは対応していません。
けど安心してください。設定をすれば可能になります。
sampleコードは[こちら](https://github.com/morix1500/sample-kustomize/tree/main/7)

```base/custom-resource.yaml
apiVersion: v1
kind: Hoge
metadata:
  name: hoge
spec:
  configMap:
    name: hoge-envs
```

```base/kustomizeconfig/configmap.yaml
nameReference:
  - kind: ConfigMap
    version: v1
    fieldSpecs:
      - path: spec/configMap/name
        kind: Hoge
```

```bash
apiVersion: v1
data:
  hoge: fuga
kind: ConfigMap
metadata:
  name: hoge-envs-5hkfff6687
---
apiVersion: v1
kind: Hoge
metadata:
  name: hoge
spec:
  configMap:
    name: hoge-envs-5hkfff6687
```

`nameReference` を使用するところで、カスタムリソースでもリソース名に関してKustomizeに情報を伝えることができます。
このようにしておくと、`namePrefix` で指定したPrefixもカスタムリソースの方に反映されます。

# 外部のマニフェストを参照する
Kubernetesを運用していると、自分たちで作るマニフェスト以外に
外部で提供しているマニフェストを使用することがあると思います。

例えばMetrics ServerはHPAなどに使用されるため、導入している人は多いのではないでしょうか。
[EKSのMetrics Serverインストール方法](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/metrics-server.html)を見てみると・・・

```bash
$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
```

こんな感じでApplyに外部のマニフェストを参照できます。
ただこれを素直にやると、Kubernetesクラスタ構築時に手動でやる手順が増えてしまいます。
またこの外部のマニフェストの内容を環境ごとに違う設定にしたい！っていう要望もあると思います。
そんなときにもKustomizeは便利に使えます。

sampleコードは[こちら](https://github.com/morix1500/sample-kustomize/tree/main/8)

今回例に挙げたMetrics Serverは公式でkustomization.yamlを公開しています。
これを利用させてもらうと・・・

```base/kustomization.yaml
resources:
  - https://github.com/kubernetes-sigs/metrics-server/manifests/release?ref=v0.4.4
```

これで `kustomize build`  をすれば、GitHubに配置されているkustomization.yamlを参照し、マニフェストが生成されます。

ちなみに kustomization.yamlが提供されていない場合は、直接Yamlを指定することもできます。

```base/kustomization.yaml
resources:
  - https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.4.4/components.yaml
```

外部マニフェストの一部を変更したい場合は、ここでご紹介した「環境ごとにマニフェストの要素を書き換える」などの機能を使って実現します。