kustomize の overlayes の使用例

<https://github.com/kubernetes-sigs/kustomize>

kustomize についての概括的な記事は他にもあると思うので、個人的な備忘録として、普段どのように使用しているかを記述しておきます。

前提として、ここでは以下のような条件下での例になります。

- base となる kubernetes ファイルが存在している。
- それらに対して overlays の機能を用いて設定を変更して、環境に応じた kubernetes ファイルを生成する。

# base
以下のような kubernetes ファイルが base ディレクトリに yaml ファイルとして置かれているとします。

- base/configmap.yaml
- base/service.yaml
- base/deployment.yaml

例としてあげているのは、これらの要素を組み合わせて動作させる、nginx で動作する Web アプリケーションです。設定内容はかなり実際のものから端折ってます。

```base/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: sada4j-configmap-nginx
data:
  nginx.conf: |-
    user  nginx;
    worker_processes  auto;

    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;

    events {
        worker_connections  512;
    }
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        upstream sada4j {
            server 127.0.0.1:8080;
        }

        server {
            listen 80;
            location / {
                proxy_pass         http://webapp;
                proxy_redirect     off;
            }
        }
    }
```

```base/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: sada4j-service
internal: "true"
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
```

```base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sada4j-deployment
spec:
  replicas: 2
  template:
    metadata:
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
      volumes:
        - name: nginx-config 
          configMap: 
            name: sada4j-configmap-nginx
```

```base/kustomization.yaml
resources:
- configmap.yaml
- service.yaml
- deployment.yaml
```

上述の kustomization.yaml に対して `kustomize build base` コマンドを実行すると、複数の yaml ファイルが一つのファイルに統合されます。
以下のように実行すると、統合されたファイルがひとまとめに kubernetes に apply されます。

```
$ kustomize build base | kubectl apply -f -
```

こういう形で、肥大化しがちな yaml ファイルを適切な粒度に分解し、実行時に Aggregation するというのが kustomize の初歩の使い方になります。

# overlays
## ケース１： deployment で動作するイメージを変更する

```overlayes/kustomization.yaml
bases:
- ../base
patches:
- deployment.yaml
``` 

```overlayes/deployment.yaml
apiVersion: apps/v1
kind: Deployment 
metadata:
  name: sada4j-deployment
spec:
  template:
    spec:
      containers:
      - name: nginx
        image: custom.image.io/nginx:v1.0.5
``` 

kustomize では overlayes という機構を用いて、もととなるテンプレートファイルの一部の設定の上書きを行うことができます。

上記では、動作させる Image の定義のみを抜き出した patch ファイルを用意しています。こうすることで `kustomize build` 時に生成されるファイルの定義を上書くことができます。

```
$ kustomize build overlayes | kubectl apply -f -
```

と実行すると、もともと動作していた image が apply したものに差し替わります。

overlays 側でフレキシブルに使用する docker image を切り替える事ができますし、patch 用の yaml ファイルのみを編集すれば良いので作業範囲を局地化することができるため、非常にアプリケーション更新の運用がしやすくなります。

## ケース２： replica 数と RollingUpdate Storategy を変更する


```overlayes/kustomization.yaml
bases:
- ../base
patches:
- deployment.yaml
``` 

```overlayes/deployment.yaml
apiVersion: apps/v1
kind: Deployment 
metadata:
  name: sada4j-deployment
spec:
  replicas: 5
  strategy: 
    rollingUpdate:
      maxSurge: 2 
      maxUnavailable: 2
    type: RollingUpdate
``` 

開発環境や本番環境など、環境に応じて pod の数や RollingUpdate 時の方式を変更したくなる時があります。
上記では、replica の数を 5 に変更し、明示的に設定していなかった RollingUpdate の定義を追記して上書く記述になっています。

他にも、deployment の記述内容について overlays で差し替える、というアイデアはいくつか思い浮かぶと思うので、以降では違う方面の例を記述します。

## ケース３：namespace を変更する
```overlayes/kustomization.yaml
namespace: sada4j-ng
bases:
- ../base
resources:
- namespace.yaml
``` 

```overlayes/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: sada4j-ng
``` 

たとえば同一の構成の deployment を多数横並べにしたい時などに、個々の kubernetes の namespace を変更したいケースがあります。

overlays の kustomization.yaml で `namespace` を定義すると、kustomize コマンドで生成された kuberentes ファイルの中のすべての要素に対して設定された namespace が自動挿入されます。
基本的には kustomization.yaml 一箇所に記述するだけで該当リソースにあまねく反映されるので、便利ですね。

ただし、設定した namespace があらかじめ存在しない場合は、事前に namespace を作成する必要があります。

Namespace の記述では `name` に namespace として適用したい値を設定する必要があるため、kustomization.yaml で記述した内容をそのまま適用することが出来ません。なので、個別に namespace を定義した yaml を kustomization.yaml に関連付ける必要があります。

このやり方だと namespace の記述が散逸化するのでイケてないなと思いますが、今のところ他のやり方を見つけられていません。

## ケース４：service の selector を変更する

```overlays/kustomization.yaml
commonLabels:
  env: prd
  project: sada4j
  cluster_id: 001
bases:
- ../base
```

kustomize 経由で service と deployment などを連携したファイルを統合すると、`labels` に設定されている値を自動的に selector の値として使用します。

上記を基に `kustomize build` を実行すると、selector の部分の記述は以下のようになります。

```
apiVersion: v1
kind: Service
metadata:
  labels:
    cluster_id: 001
    env: prd
    project: sada4j
  name: sada4j-service
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    cluster_id: 001
    env: prd
    project: sada4j
  type: LoadBalancer
```

このように kustomize build をすることが前提の環境の場合、base にあたるファイル内では selector の定義を書いていなくても自動的に label の値が挿入され、適切に service と deployment の結びつけが行われます。

## ケース５：vars を用いてプレースホルダーに書かれた値の差し替えを行う
<https://github.com/kubernetes-sigs/kustomize/blob/98a38eb290231dc8b8e4036a1548d375d6941d67/docs/kustomization.yaml>

> Vars are used to insert values from resources that cannot be referenced otherwise. For example if you need to pass a Service's name to the arguments or environment variables of a program but without hard coding the actual name of the Service you'd insert `$(MY_SERVICE_NAME)` into the value field of the env var or into the command or args of the container as shown here:

vars について、 kustomization.yaml のサンプルファイルなどにはこういう機能がある、と書かれていますが、意外と適用箇所が限られます。

以下のソース箇所が、vars で指定された値の差し替えを行っている箇所のようで、どの箇所に書かれたプレースホルダーが差し替え対象になっているかソースを通じて確認ができます。
<https://github.com/kubernetes-sigs/kustomize/blob/c25ed7f7bc6ed2b940cce28ba82a5467da635206/pkg/transformers/refvars.go#L21-L104>

逆にいうとここに書かれてない箇所にプレースホルダー定義を書いても差し替えは行われません。

そもそもプレースホルダー記述がある kubernetes の設定ファイルは、単体で動作させるのが難しくなるため、個人的には不便に感じあまり使用していません。

個人的には、overlays で値の差し替えを行いたい時は、 configmap や secret を generator やpatch / resource 経由で読み込み、そちらを用いて値を上書くこと方式を用いることが多いです。

# まとめにかえて
まとまりが無いですが、思いつき次第追記していきます。