kustomizeでconfigMapGeneratorを利用し外部のファイルからconfigmapを生成する方法

## モチベーション

今担当しているシステムでは[kube-job](https://github.com/h3poteto/kube-job)を利用し、特定のPodからjobを起動しています。
実行するbatchのマニフェストは、configmapで管理しています。configmapをdeploymentでマウントして実行するイメージです。

configmapの中にkubernetesマニフェストであるbatchを記述するのですが、

- configmap内にマニフェストを書いているので可読性が損なわれる
- 記述ミスが増そう(予感

など、色々問題がありそうなので、このタイミングで直しました。
configmapGeneratorの記事はたくさんあるのですが、volumeの設定に関して少しハマったので、備忘録的に残しておきます。

対策する前はこんな感じです。マニフェストの中にマニフェストを書くのはちょっと辛い。

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: config
data:
  task.yml: |+
    apiVersion: batch/v1
    kind: Job
    metadata:
      name: task
      labels:
        app: task
```

## 前提

- kustomize v4.4.0
- kubectl v1.22.2

### ディレクトリ構成

今回は備忘録的に残しておくだけなので、きっちりディレクトリを構成しません。

```sh
$ tree
└── base
    ├── config
    │   └── task.yaml #　このファイルをConfigmapで扱いたい
    ├── deployment.yaml # 生成したConfigmapをmountしたい
    └── kustomization.yaml
```

## やり方

### kustomization.yaml
`configMapGenerator`を設定し、`files`に実際に読み込みたいファイルを指定します。
`files`の内容もkubernetes manifestですが、これはさまざまなユースケースに合わせて自由に記述できます。

```yaml
resources:
- deployment.yaml
configMapGenerator:
- name: cm-in-task
  files:
    - ./config/task.yaml # 公式から拾ってきたCronJobのサンプルをコピペして持ってきた
```

### deployment.yaml

`volumes`に`configMapGenerator`で記述した`name`、作成するファイル名をitems配下に指定します。
最初envの読み込み方(configMapKeyRef)とごっちゃになりハマりました。普通にマニフェストの仕様通り読み込めばよかったです。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  # (本件と関係ない設定は諸々省略してます)
  template:
    spec:
      # (本件と関係ない設定は諸々省略してます)
      containers:
      - name: nginx
        image: nginx:1.14.2
        volumeMounts:
        - name: cm-in-task # mountしたいvolumeを指定
          mountPath: /etc/config
        ports:
        - containerPort: 80
      volumes:
      - name: cm-in-task
        configMap:
　　　　　　　　　　　　　　　　　　　　# どうやって読み込むかで結構ハマった
          name: cm-in-task # configmapGeneratorで設定したnameを指定
          items:
          - key: task.yaml # 生成するファイル名
            path: task.yaml # 生成するファイル名
```

### `kustomize build`の結果
```yaml
# configmapが生成されている
apiVersion: v1
data:
  task.yaml: |
    apiVersion: batch/v1
    kind: CronJob
    metadata:
      name: hello
    spec:
      schedule: "*/1 * * * *"
      jobTemplate:
        spec:
          template:
            spec:
              containers:
              - name: hello
                image: busybox
                command:
                - /bin/sh
                - -c
                - date; echo Hello from the Kubernetes cluster
              restartPolicy: OnFailure
kind: ConfigMap
metadata:
  name: cm-in-task-fmtgff4cb2 #　hashつきのnameを自動生成
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        name: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /etc/config
          name: cm-in-task
      volumes:
      - configMap:
          items:
          - key: task.yaml
            path: task.yaml
          name: cm-in-task-fmtgff4cb2　#　hashつきnameが自動で適用
        name: cm-in-task
```

### podの中を確認

実際にpodに入りconfigmapの内容が参照できるか確認します。

```sh
$ head etc/config/task.yaml 
apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
```

## 終わりに

いかがでしたか？
configmapに複雑な設定を記述したい場合に、外部のファイルに切り出せるのはメリットがありますね。
特に、configmapで生成するマニフェスト自体もkubeval等でチェックできるのが最高です。

今後は、configmapで生成するマニフェストもkustomizeでbase, overlaysで共通化できないかを調べてみたいと考えています。

## 参考

今回検証するために以下を参考にさせていただきました。

- https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
- https://qiita.com/syogun/items/9362b74545d1d5c88e38