(2020年10月の検証記事です)

KubernetesのCronJobは、Job同様にオプション設定によってPodの扱いが変わってくるようなので試してみた。実行環境はMacOS上のminikube。

 

気になっていた設定は以下。

successfulJobsHistoryLimit(成功時のPod履歴数。デフォルト3)
failedJobsHistoryLimit(失敗時のPod履歴数。デフォルト1)
restartPolicy (NeverかOnFailureか)
backoffLimit (失敗時のリトライ数。デフォルト6だが0にする必要があるか)

上の2つは履歴数といっても実際にPodがその数だけ残るので、リソースが逼迫気味なワーカーノードでは気にしたいところ。

以下サンプルマニフェスト。dateコマンド結果を吐き出すだけの無意味なタスク。

cron_test_never.yaml

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cron-test
spec:
  schedule: "*/1 * * * *"
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 2
  failedJobsHistoryLimit: 2
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: cron-test
            image: busybox
            command: ["/bin/sh", "-c", "echo $(date -u) > /tmp/date.log"]
restartPolicy: Never

 

今回は深追いしていないが、concurrencyPolicy: Forbid は同時実行を抑止するため設定。backofflimit:0 はこの段階では設定しない。

実行結果

$ kubectl get cronjob
NAME        SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cron-test   */1 * * * *   False     0        <none>          7s

$ kubectl get po
NAME                         READY   STATUS      RESTARTS   AGE
cron-test-1603592640-58wdq   0/1     Completed   0          54s

$ kubectl get po
NAME                         READY   STATUS      RESTARTS   AGE
cron-test-1603592640-58wdq   0/1     Completed   0          84s
cron-test-1603592700-8wlrx   0/1     Completed   0          24s

$ kubectl get po
NAME                         READY   STATUS      RESTARTS   AGE
cron-test-1603592700-8wlrx   0/1     Completed   0          77s
cron-test-1603592760-jdbcn   0/1     Completed   0          17s

 

指定通り、Podが2世代まで残る。次にsuccessfulJobsHistoryLimit: 0 にしてapply。

$ kubectl get po
No resources found in default namespace.

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603593300-vv7zd   0/1     ContainerCreating   0          1s

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603593300-vv7zd   0/1     ContainerCreating   0          4s

$ kubectl get po
NAME                         READY   STATUS      RESTARTS   AGE
cron-test-1603593300-vv7zd   0/1     Completed   0          7s

$ kubectl get po
No resources found in default namespace.

 

上記の繰り返しとなる。Podは実行中のみ存在し、Pod生成後10秒まではステータス取得可能らしい。restartPolicy: OnFailureでも同様のパターンでapplyしてみたが、正常時の動作はNeverと変わらなかった。

CronJobではsuccessfulJobsHistoryLimit: 0にしておけば、backofflimit:0 設定は必要ない?と考えたが、失敗時の動作も見ておく必要があるのでそれも試してみた。

エラーパターンではcommandの命令を以下のようにして、存在しないパスを指定した。

 

command: ["/usr/sh", "-c", "echo $(date -u) > /tmp/date.log"]

 

restartPolicy: Never エラーケース

restartPolicy: Never
failedJobsHistoryLimit: 2
backokfflimit指定なし

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603596240-srrjj   0/1     ContainerCreating   0          4s

$ kubectl get po
NAME                         READY   STATUS               RESTARTS   AGE
cron-test-1603596240-kwk4q   0/1     ContainerCannotRun   0          6s
cron-test-1603596240-srrjj   0/1     ContainerCannotRun   0          11s

(snip)

$ kubectl get po
NAME                         READY   STATUS               RESTARTS   AGE
cron-test-1603596240-dxvt2   0/1     ContainerCannotRun   0          58s
cron-test-1603596240-kwk4q   0/1     ContainerCannotRun   0          68s
cron-test-1603596240-m69th   0/1     ContainerCannotRun   0          38s
cron-test-1603596240-srrjj   0/1     ContainerCannotRun   0          73s

$ kubectl get po
NAME                         READY   STATUS               RESTARTS   AGE
cron-test-1603596240-7b42n   0/1     ContainerCannotRun   0          7s
cron-test-1603596240-dxvt2   0/1     ContainerCannotRun   0          107s
cron-test-1603596240-kwk4q   0/1     ContainerCannotRun   0          117s
cron-test-1603596240-m69th   0/1     ContainerCannotRun   0          87s
cron-test-1603596240-srrjj   0/1     ContainerCannotRun   0          2m2s

 

failedJobsHistoryLimit: 2に関わらず、backofflimitのデフォルト値6(実際は5)の分だけPodが残ってしまう!

ここで、backokfflimit:0をセットしてapply。

 

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cron-test
spec:
  schedule: "*/1 * * * *"
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 2
  failedJobsHistoryLimit: 2
  jobTemplate:
    spec:
      backoffLimit: 0
      template:
        spec:
          containers:
          - name: cron-test
            image: busybox
            command: ["/usr/sh", "-c", "echo $(date -u) > /tmp/date.log"]
restartPolicy: Never

 

$ kubectl get po
NAME                         READY   STATUS               RESTARTS   AGE
cron-test-1603596900-2fgfp   0/1     ContainerCannotRun   0          2m10s
cron-test-1603596960-rtvj2   0/1     ContainerCannotRun   0          69s
cron-test-1603597020-mhgm8   0/1     ContainerCannotRun   0          9s

$ kubectl get po
NAME                         READY   STATUS               RESTARTS   AGE
cron-test-1603597020-mhgm8   0/1     ContainerCannotRun   0          96s
cron-test-1603597080-548zl   0/1     ContainerCannotRun   0          36s

 

backokfflimit:0により、failedJobsHistoryLimit: 2の指定通りに世代が残った。

次にfailedJobsHistoryLimit: 0にしてapply。すると、Podが存在するのはタスク実行時のみとなった。

$ kubectl get po
No resources found in default namespace.

$ kubectl get po
NAME                         READY   STATUS               RESTARTS   AGE
cron-test-1603597320-8kk2g   0/1     ContainerCannotRun   0          5s

$ kubectl get po
NAME                         READY   STATUS               RESTARTS   AGE
cron-test-1603597320-8kk2g   0/1     ContainerCannotRun   0          8s

$ kubectl get po
No resources found in default namespace.

 

確かに余分なリソースは食わないが、エラー調査がまったくできない。そこを考慮するならば、failedJobsHistoryLimit: 1が理想的かもしれない。

restartPolicy: OnFailure エラーケース

restartPolicy: OnFailure
failedJobsHistoryLimit: 2
backokfflimit指定なし

 

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603597980-swr2d   0/1     RunContainerError   0          19s

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603597980-swr2d   0/1     RunContainerError   1          32s

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603597980-swr2d   0/1     RunContainerError   2          42s

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603597980-swr2d   0/1     RunContainerError   3          66s

$ kubectl get po
NAME                         READY   STATUS             RESTARTS   AGE
cron-test-1603597980-swr2d   0/1     CrashLoopBackOff   4          2m15s

 

failedJobsHistoryLimit: 2は影響せず、同一podでリスタートを繰り返す。Neverパターンではステータスが"ContainerCannotRun"だったが、OnFailureでは"RunContainerError"となる。途中からCrashLoopBackOffになった。

次にbackokfflimit:0をセットしてapply。

 

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603598820-vnrfr   0/1     ContainerCreating   0          2s

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603598820-vnrfr   0/1     RunContainerError   0          6s

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603598820-vnrfr   0/1     RunContainerError   0          22s

$ kubectl get po
No resources found in default namespace.

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603598880-l2jmx   0/1     RunContainerError   0          12s

$ kubectl get po
NAME                         READY   STATUS        RESTARTS   AGE
cron-test-1603598880-l2jmx   0/1     Terminating   1          23s

$ kubectl get po
No resources found in default namespace.

 

起動されるPodは常に1つだが、異なるPodが起動された。次にfailedJobsHistoryLimit: 0にしてapplyしたところ、動作としては上記と変わらず、起動の都度Podが変化した。Podがわずかな時間しか存在しないため調査が困難と想定する。

 

結局どうすればいいか
成功時も失敗時も余分なPodを起動させないようにしたい。ただしエラー発生時は調査可能にしておきたい。であれば、以下の設定が妥当かと思われる。

 

successfulJobsHistoryLimit: 0
failedJobsHistoryLimit: 1
backoffLimit: 0
restartPolicy: Never

上記ステータスで改めてapply。

 

$ kubectl get po
NAME                         READY   STATUS              RESTARTS   AGE
cron-test-1603600380-t8jgq   0/1     ContainerCreating   0          3s

$ kubectl get po
NAME                         READY   STATUS               RESTARTS   AGE
cron-test-1603600380-t8jgq   0/1     ContainerCannotRun   0          57s

$ kubectl get po
NAME                         READY   STATUS               RESTARTS   AGE
cron-test-1603600440-pzf5r   0/1     ContainerCannotRun   0          24s #1分後は次のPodが起動

 

PodはCron実行時間単位で新たに起動されるので、1分毎に実行の場合はその間にログを取得する必要がある…といっても次に起動したPodで取得してもいいんだから、まぁどうにかなるか。