repl.info

kubernetesのCronJobを触る

kubernetes上で定期的に何か処理を行う場合どうやるのかなと思っていたら、Cron Jobsというものがあるらしい。軽く触ってどんなものか見てみた。

なお、使用したminikubeとkubernetesのバージョンは以下の通り。

$ minikube version

minikube version: v0.15.0

$ kubectl version

Client Version: version.Info{Major:"1", Minor:"5", GitVersion:"v1.5.2", GitCommit:"08e099554f3c31f6e6f07b448ab3ed78d0520507", GitTreeState:"clean", BuildDate:"2017-01-12T04:57:25Z", GoVersion:"go1.7.4", Compiler:"gc", Platform:"darwin/amd64"}

Server Version: version.Info{Major:"1", Minor:"5", GitVersion:"v1.5.1", GitCommit:"82450d03cb057bab0950214ef122b67c83fb11df", GitTreeState:"clean", BuildDate:"1970-01-01T00:00:00Z", GoVersion:"go1.7.1", Compiler:"gc", Platform:"linux/amd64"}

CronJobのマニフェスト

以下のようにした。イメージはrails.ymlと同じものを使う。argsに、実行するコマンドを指定するようだ。実行タイミングはcron形式なのでなじみがありますね。

apiVersion: batch/v2alpha1

kind: CronJob

metadata:

  name: hello

spec:

  schedule: "*/1 * * * *"

  jobTemplate:

    spec:

      template:

        spec:

          containers:

          - name: hello

            image: localhost:5000/r_takaishi/docker-mysql-rails

            args: ["bundle", "exec", "rake", "foo"]

            env:

              - name: RAILS_ENV

                value: development

              - name: MYSQL_HOST

                value: mysql.default.svc.cluster.local

              - name: MYSQL_USER

                value: root

              - name: MYSQL_PASSWORD

                value: passw0rd

          restartPolicy: Never

なお、実行するRakeタスクは追加してイメージを更新しておく。

desc "this is foo"

task :foo => :environment do

    p :foo

end

さて、マニフェストを作成したらCronJobを作る。

$kubectl create -f ./cron.yml

cronjob "hello" created

作成されたことが確認できた。この時点ではジョブは1回も動いていない。

$ kubectl get cronjob

NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE

hello */1 * * * * False 0 <none>

ジョブが動いた!

ジョブが動作するとLAST-SCHEDULEが更新されるようだ。動作中だとACTIVEが1になるのかな。

$ kubectl get cronjob

NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE

hello */1 * * * * False 1 Tue, 07 Feb 2017 22:19:00 +0900

ジョブ一覧を見てみる。成功したようだ。

$ kubectl get job

NAME DESIRED SUCCESSFUL AGE

hello-1486473540 1 1 17s

ジョブ hello-1486473540 の詳細を見る。実際に動作したのはhello-1486473540-cxr0n というポッドの中ということがわかる。

$ kubectl describe job hello-148647354

Name: hello-1486473540

Namespace: default

Image(s): localhost:5000/r_takaishi/docker-mysql-rails

Selector: controller-uid=00f009f6-ed38-11e6-93b9-080027cb3417

Parallelism: 1

Completions: 1

Start Time: Tue, 07 Feb 2017 22:19:07 +0900

Labels: controller-uid=00f009f6-ed38-11e6-93b9-080027cb3417

                job-name=hello-1486473540

Pods Statuses: 0 Running / 1 Succeeded / 0 Failed

No volumes.

Events:

  FirstSeen LastSeen Count From SubObjectPath Type Reason Message

  --------- -------- ----- ---- ------------- -------- ------ -------

  34s 34s 1 {job-controller } Normal SuccessfulCreate Created pod: hello-1486473540-cxr0n

ポッドのログを見ると、Rakeに追加したタスクが実行されていることが確認できた!

$ kubectl logs hello-1486473540-cxr0n

:foo

yamlでマニフェストを書けば後はk8sにまかせられるという感じで、楽そうですね。

ところで、しばらく放置してからジョブ一覧を見るとこんな感じに。

$ kubectl get job

NAME DESIRED SUCCESSFUL AGE

hello-1486473540 1 1 7m

hello-1486473600 1 1 6m

hello-1486473660 1 1 5m

hello-1486473720 1 1 4m

hello-1486473780 1 1 3m

hello-1486473840 1 1 2m

hello-1486473900 1 1 1m

hello-1486473960 1 1 34s

ポッドも、-aオプションをつけると完了したものが残っている。

$ kubectl get pod -a

NAME READY STATUS RESTARTS AGE

hello-1486473540-cxr0n 0/1 Completed 0 8m

hello-1486473600-t3tls 0/1 Completed 0 7m

hello-1486473660-7m4w9 0/1 Completed 0 6m

hello-1486473720-6hjsc 0/1 Completed 0 5m

hello-1486473780-jq2vn 0/1 Completed 0 4m

hello-1486473840-f26cj 0/1 Completed 0 3m

hello-1486473900-3b5h6 0/1 Completed 0 2m

hello-1486473960-ph0db 0/1 Completed 0 1m

hello-1486474020-f44k3 0/1 Completed 0 50s

mysql-8kd4q 1/1 Running 2 6d

rails-8cnzn 1/1 Running 0 2d

ジョブの種類が増えて、しばらく時間が経過すると見るのが大変そうだと感じた。そのうち変わるのかな−。ある程度前のジョブは消すようにするのがいいのかも。

まとめ

CronJobを軽く触ってみた。ちゃんと動いていて、しかも実行時だけコンテナを起動しているのでFaaSっぽい雰囲気。ただ、ハンドリングに慣れないうちは中でcrondを動かすコンテナを常時起動しておき、今まで通りのcronで定期実行する方法も併用してもいいのかも。