Kustomize で CronJob を同一テンプレートからスケジュール毎に生成する

## 問題

Kubernetes の CronJob は `schedule` を1つしか設定できません。
そのため同じコンテナ定義で `schedule` と `command` , `args` だけを変えたスケジュールを設定したくても、その数の分だけ CronJob を作成する必要があります。

```yaml
# 1個目
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: greeting-morning
spec:
  schedule: 0 9 * * *
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - image: alpine:latest
            name: main
            command:
            - echo
            args:
            - Good morning.
---
# 2個目
# 違いは name, schedule, args のみ
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: greeting-midnight
spec:
  schedule: 0 0 * * *
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - image: alpine:latest
            name: main
            command:
            - echo
            args:
            - It's midnight.
```

## 解決策

Kustomize を使ってひとつのテンプレートから複数の CronJob を生成し、さらにそれらを最後にひとつにまとめます。

デモ: https://github.com/yubessy/example-kustomize-cronjob-multiple-schedule

ディレクトリ構成は次のようにします。

```
.
├── template
│   ├── kustomization.yaml     # テンプレート用
│   └── cronjob.yaml           # テンプレートとなる CronJob
├── schedules
│   ├── 0-9-any-any-any
│   │   ├── kustomization.yaml # 1個目の CronJob 用
│   │   └── patch.yaml         # schedule, args の patch
│   └── 0-0-any-any-any
│       ├── kustomization.yaml # 2個目の CronJob 用
│       └── patch.yaml         # schedule, args の patch
└── kustomization.yaml         # 最終的に出力をまとめる用
```

各ファイルの中身はこんな感じです。

```yaml:template/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./cronjob.yaml
```

```yaml:template/cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: greeting
spec:
  schedule: ""
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: main
            image: alpine:latest
            command:
            - echo
            args:
            - This is template.
```

```yaml:schedules/.../kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../template
# これがないと怒られる
nameSuffix: -midnight
patchesJson6902:
- target:
    group: batch
    version: v1beta1
    kind: CronJob
    name: greeting
  path: ./patch.yaml
```

```yaml:schedules/.../patch.yaml
- op: replace
  path: /spec/schedule
  value: "0 9 * * *"
- op: replace
  path: /spec/jobTemplate/spec/template/spec/containers/0/args/0
  value: "Good morning."
```

```yaml:kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ./schedules/0-9-any-any-any
- ./schedules/0-0-any-any-any
```

`schedules/.../kustomization.yaml` の `nameSuffix` がミソです。
Kustomize は通常ひとつのベースリソースからひとつの派生リソースしか作れないのですが、`nameSuffix` か `namePrefix` を使うと同一のベースリソースから複数の派生リソースを作成することができます。

今回の場合はこれがないと次のようなエラーが出てしまいます。

```
Error: ./schedules/0-0-any-any-any: id '"batch_v1beta1_CronJob|~X|~P|template|~S"' already used
```

このディレクトリ構成のトップで `kustomize build` すれば次のように複数の CronJob がまとめて出力されます。

```
$ kustomize build
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: greeting-morning
spec:
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - args:
            - Good morning.
            command:
            - echo
            image: alpine:latest
            name: main
  schedule: 0 9 * * *
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: greeting-midnight
spec:
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - args:
            - It's midnight.
            command:
            - echo
            image: alpine:latest
            name: main
  schedule: 0 0 * * *
```

## 参考

- [add genericGenerator · Issue #126 · kubernetes-sigs/kustomize](https://github.com/kubernetes-sigs/kustomize/issues/126)
- [Demo: multibases with a common base · kubernetes-sigs/kustomize](https://github.com/kubernetes-sigs/kustomize/blob/master/examples/multibases/README.md)