cronみたいな定期実行のバッチや1回しか使わないバッチをDockerコンテナとしてパッケージにして定期実行することができます。
k8sのkind CronJobってのがcron的なもので、Jobってのがその時だけ実行するやつですね。
Dockerコンテナ内でcrontabを書いておく不安な方法よりも、実行するときだけPodsが起動するのでエコです。
それぞれ、失敗したときの挙動とか、並列実行とか設定できるので便利。詳しくは下記ページをご参照あれ。
Job: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/
CronJob: https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
Job
Jobの方から試してみましょう。
こんな感じのファイルを用意します。
FROM docker/whalesay:latest
ENTRYPOINT [ ":" ] # なにもしない。Dockerfile作る意味はとくにない。
apiVersion: batch/v1
kind: Job
metadata:
name: cowsay-job-20190520
spec:
template:
spec:
containers:
- name: cowsay-job
image: murata/cowsay-job:v3
command: ["cowsay", "わたしはk8sです。"]
restartPolicy: OnFailure
backoffLimit: 5
Dockerfileをビルドします。
~/tmp/k8s-job
❯ docker build -t murata/cowsay-job:v3 .
Sending build context to Docker daemon 3.072kB
Step 1/2 : FROM docker/whalesay:latest
---> 6b362a9f73eb
Step 2/2 : ENTRYPOINT [ ":" ] # なにもしない。Dockerfile作る意味ない。
---> Running in 93cd12fc5d81
Removing intermediate container 93cd12fc5d81
---> 453bf70f357d
Successfully built 453bf70f357d
Successfully tagged murata/cowsay-job:v3
k8sに食わせます。
~/tmp/k8s-job
❯ kubectl apply -f ./k8s.cowsay.job.yaml
job.batch/cowsay-job-20190520 created
job.batchとpodが出来上がっています。
すでに終わっていますね。
~/tmp/k8s-job
❯ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/cowsay-job-20190520-fpvmm 0/1 Completed 0 26s
NAME COMPLETIONS DURATION AGE
job.batch/cowsay-job-20190520 1/1 2s 26s
ログをみてみましょう。
~/tmp/k8s-job
❯ kubectl log job.batch/cowsay-job-20190520
log is DEPRECATED and will be removed in a future version. Use logs instead.
__________________________
< わたしはk8sです。 >
--------------------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
うごいていますね。
エラーの場合
backoffLimit: 5
としているので失敗しても5回まで実行してくれます。失敗させてみましょう。
下記のように存在しないコマンドにしてみます。
apiVersion: batch/v1
kind: Job
metadata:
name: pepesay-job-20190520
spec:
template:
spec:
containers:
- name: pepesay-job
image: murata/cowsay-job:v3
command: ["pepesay", "わたしはペペです。"]
restartPolicy: OnFailure
backoffLimit: 5
がんばっているようです。すでに2回リスタートしています。
~/tmp/k8s-job
❯ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/cowsay-job-20190520-fpvmm 0/1 Completed 0 5m30s
pod/pepesay-job-20190520-gchs9 0/1 RunContainerError 2 37s
NAME COMPLETIONS DURATION AGE
job.batch/cowsay-job-20190520 1/1 2s 5m30s
job.batch/pepesay-job-20190520 0/1 37s 37s
ちゃんと5回(リスタートは4回)終わって諦めたようです。
❯ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/cowsay-job-20190520-fpvmm 0/1 Completed 0 7m44s
pod/pepesay-job-20190520-gchs9 0/1 CrashLoopBackOff 4 2m51s
NAME COMPLETIONS DURATION AGE
job.batch/cowsay-job-20190520 1/1 2s 7m44s
job.batch/pepesay-job-20190520 0/1 2m51s 2m51s
jobのdescribeを見てみるとだめだったぽよってWarningが出ていますね。
❯ kubectl describe job.batch/pepesay-job-20190520
Name: pepesay-job-20190520
Namespace: cowsay
Selector: controller-uid=28ea1281-7c74-11e9-9b99-080027ae51c3
Labels: controller-uid=28ea1281-7c74-11e9-9b99-080027ae51c3
job-name=pepesay-job-20190520
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"batch/v1","kind":"Job","metadata":{"annotations":{},"name":"pepesay-job-20190520","namespace":"cowsay"},"spec":{"backoffLim...
Parallelism: 1
Completions: 1
Start Time: Wed, 22 May 2019 18:29:55 +0900
Pods Statuses: 0 Running / 0 Succeeded / 1 Failed
Pod Template:
Labels: controller-uid=28ea1281-7c74-11e9-9b99-080027ae51c3
job-name=pepesay-job-20190520
Containers:
pepesay-job:
Image: murata/cowsay-job:v3
Port: <none>
Host Port: <none>
Command:
pepesay
わたしはk8sです。
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 3m25s job-controller Created pod: pepesay-job-20190520-gchs9
Normal SuccessfulDelete 11s job-controller Deleted pod: pepesay-job-20190520-gchs9
Warning BackoffLimitExceeded 11s job-controller Job has reached the specified backoff limit
エラーjobの仕込み方が悪かったのかログがでていない。。。
❯ kubectl logs job.batch/pepesay-job-20190520
error: timed out waiting for the condition
CronJob
cronjobの場合は、scheduleにcrontab形式で記載します。また、前の処理が終わっていなかった場合にどうするかをconcurrencyPolicyで決めます。(終わるまでまつ、やらない、殺して実行とか。)
1分に1回実行してみます。
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cowsay-cronjob-20190520
spec:
concurrencyPolicy: Replace
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: cowsay-cronjob
image: murata/cowsay-job:v3
command: ["cowsay", "わたしはCronJobです。"]
restartPolicy: OnFailure
こんな感じcronjobが配置されます。
❯ kubectl get all,jobs -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/cowsay-job-20190520-fpvmm 0/1 Completed 0 57m 172.17.0.6 minikube <none> <none>
NAME COMPLETIONS DURATION AGE CONTAINERS IMAGES SELECTOR
job.batch/cowsay-job-20190520 1/1 2s 57m cowsay-job murata/cowsay-job:v3 controller-uid=7a5a3b6b-7c73-11e9-9b99-080027ae51c3
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR
cronjob.batch/cowsay-cronjob-20190520 */1 * * * * False 0 <none> 18s cowsay-cronjob murata/cowsay-job:v3 <none>
しばらくするとこんな感じに表示されます。
❯ kubectl get all,jobs -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/cowsay-cronjob-20190520-1558520580-xtwq7 0/1 Completed 0 89s 172.17.0.6 minikube <none> <none>
pod/cowsay-cronjob-20190520-1558520640-br724 0/1 Completed 0 29s 172.17.0.6 minikube <none> <none>
pod/cowsay-job-20190520-fpvmm 0/1 Completed 0 59m 172.17.0.6 minikube <none> <none>
NAME COMPLETIONS DURATION AGE CONTAINERS IMAGES SELECTOR
job.batch/cowsay-cronjob-20190520-1558520580 1/1 1s 89s cowsay-cronjob murata/cowsay-job:v3 controller-uid=97619397-7c7b-11e9-9b99-080027ae51c3
job.batch/cowsay-cronjob-20190520-1558520640 1/1 1s 29s cowsay-cronjob murata/cowsay-job:v3 controller-uid=bb45dacd-7c7b-11e9-9b99-080027ae51c3
job.batch/cowsay-job-20190520 1/1 2s 59m cowsay-job murata/cowsay-job:v3 controller-uid=7a5a3b6b-7c73-11e9-9b99-080027ae51c3
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR
cronjob.batch/cowsay-cronjob-20190520 */1 * * * * False 0 36s 2m8s cowsay-cronjob murata/cowsay-job:v3 <none>
実行結果をみてみます。
❯ kubectl logs pod/cowsay-cronjob-20190520-1558520580-xtwq7
______________________________
< わたしはCronJobです。 >
------------------------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
自分の環境の場合、完了後のpodは3個残るようです。
.spec.successfulJobsHistoryLimit
と .spec.failedJobsHistoryLimit
で設定できるみたい。
まとめ
今回はk8sでバッチを実行してみました。まぁ普通は並列実行とかしないので、k8sじゃない限りは、crontabでもよいのですが、k8s環境にいる人はぜひ使うと捗りそうです。
なによりロギングが楽。
crontabに適当に書いて、 /dev/null に捨てちゃったりしていませんか?
ちゃんと設定すればよいのですが、デフォルトがメールやら/var/log/cronなので、他コンテナと同様に処理されるのはよいですね。
デーモン的な永遠に動き続けるもの場合はDaemonSet というものがあります。
https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
pm2も便利かもしれません。 http://pm2.keymetrics.io/
ただしpm2を使う場合1podの中にあまり詰め込みすぎないように気をつけましょう。ノード負荷が偏ります。