CronJob简介
定时任务对我们并不陌生,例如Linux的crontab,各种编程语言都内置了定时任务支持,这在我们应用开发中比较常见,但这种定时任务在分布式系统中使用会有限制,因此需要分布式计划任务。 Kubernetes的CronJob可以理解为Kubernetes对分布式计划任务的支持。
Kubernetes集群使用CronJob管理基于时间的作业,可以在指定的时间点执行一次或在指定时间点执行多次任务。 一个CronJob就好像Linux crontab中的一行,可以按照Cron定时运行任务。
在使用CronJob之前需要确认Kubernetes集群的版本>=1.5。
所有 CronJob 的 schedule: 时间都是基于初始 Job 的主控节点的时区。
CronJob Spec
.spec.schedule:调度,必需字段,指定任务运行周期,格式同 Cron
.spec.jobTemplate:Job 模板,必需字段,指定需要运行的任务,格式同 Job,只是不需要 apiVersion 和 kind。
.spec.startingDeadlineSeconds :启动 Job 的期限(秒级别),该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限
.spec.concurrencyPolicy:并发策略,该字段也是可选的。它指定了如何处理被 CronJob 创建的 Job 的并发执行。只允许指定下面策略中的一种:
- Allow(默认):允许并发运行 Job
- Forbid:禁止并发运行,如果前一个还没有完成,则直接跳过下一个
- Replace:取消当前正在运行的 Job,用一个新的来替换
注意,当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总是允许并发运行。
.spec.suspend :挂起,该字段也是可选的。如果设置为 true,后续所有执行都会被挂起。它对已经开始执行的 Job 不起作用。默认值为 false。
.spec.successfulJobsHistoryLimit 和 .spec.failedJobsHistoryLimit :历史限制,是可选的字段。它们指定了可以保留多少完成和失败的 Job。
默认情况下,它们分别设置为 3 和 1。设置限制的值为 0,相关类型的 Job 完成后将不会被保留。
CronJob 限制
一个 CronJob 在时间计划中的每次执行时刻,都创建大约一个Job对象,在少数情况下会创建两个Job对象,或者不创建Job对象。尽管K8S尽最大的可能性避免这种情况的出现,但是并不能完全杜绝此现象的发生。因此Job程序必须是幂等的。
当以下两个条件都满足时,Job 将至少运行一次:
- startingDeadlineSeconds 被设置为一个较大的值,或者不设置该值
- concurrencyPolicy 被设置为 Allow
对于每一个 CronJob,CronJob 控制器将检查自上一次执行的时间点到现在为止有多少次执行被错过了。如果错过的执行次数超过了 100,则 CronJob 控制器将不再创建 Job 对象,并记录如下错误:
Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.
如果设置了 startingDeadlineSeconds,控制器将按照从 startingDeadlineSeconds 秒之前到现在为止的时间段计算被错过的执行次数,而不是按照从上一次执行的时间点到现在为止的时间段来计算被错过的执行次数。例如,如果 startingDeadlineSeconds 被设置为 200,则,控制器将计算过去 200 秒内,被错过的执行次数。
当 CronJob 在其计划的时间点应该创建 Job 时却创建失败,此时 CronJob 被认为错过了一次执行。例如,如果 concurrencyPolicy 被设置为 Forbid 且 CronJob 上一次创建的 Job 仍然在运行,此时 CronJob 再次遇到一个新的计划执行的时间点并尝试创建一个 Job,该此创建尝试将失败,并被认为错过了一次执行。
又例如,假设某个 CronJob 被设置为:自 08:30:00 开始,每分钟创建一个新的 Job,且 CronJob 的 startingDeadlineSeconds 字段未被设置。如果 CronJob 控制器恰好在 08:29:00 到 10:21:00 这个时间段出现故障(例如 Crash),则该 CronJob 将不会再次执行,因为其错过的执行次数已经超过了 100。
为了进一步解释这个概念,我们再列举一个例子,假设某个 CronJob 被设置为:自 08:30:00 开始,每分钟创建一个新的 Job,且 CronJob 的 startingDeadlineSeconds 字段被设置为 200 秒。同样,如果 CronJob 控制器恰好在 08:29:00 到 10:21:00 这个时间段出现故障(时间段与上个例子相同),此时 CronJob 控制器将在 10:22:00 为该 CronJob 创建一个 Job。这是因为,在这个例子中,控制器将只计算过去 200 秒中错过的执行次数(大约 3 次),而不是从上一次执行的时间点开始计算错过的执行次数。
CronJob 只负责按照时间计划的规定创建 Job 对象,由 Job 来负责管理具体 Pod 的创建和执行。
创建及运行CronJob
打印一次当前时间并输出 hello world 信息:
SPEC方式
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
$ kubectl create -f ./cronjob.yaml
cronjob "hello" created
命令行模式
$ kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster"
cronjob "hello" created
查看状态
$ kubectl get cronjob hello
NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE
hello */1 * * * * False 0 <none>
NAME:CronJob名称。
SCHEDULE:基于时间的调度规则。
SUSPEND:如果其值为True表示此CronJob暂时失效,不变成False之前不再创建新任务。对于已经创建的任务没有影响。
ACTIVE:表示当前活动的任务数,0表示当前没有活动任务。1表示有一个活动任务。此值可能大于1,原因如下:
1.任务允许重复启动,如前一次启动后还没有退出,下一次已经启动。
2.允许延后启动,当CronJob Controller发现因为某种原因错误启动,并且任务允许延后启动,则会启动任务。
LAST-SCHEDULE:表示最后一次调度时间,
查看CronJob创建的Job
$ kubectl get jobs --watch
NAME DESIRED SUCCESSFUL AGE
hello-4111706356 1 1 2s
$ kubectl get cronjob hello
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 50s 75s
NAME:表示CronJob创建的Job名称,后边的数字由系统自动生成,保证不重复。
DESIRED:表示CronJob只创建的是最简单的一次Job,只创建一个pod。
SUCCESSFUL:表示pod成功个数。
AGE:表示上JOB生存时间。
输出结果显示,该 CronJob 在 LAST SCHEDULE 这个时间点成功创建了一个 Job。当前 ACTIVE Job 数为 0,意味着,该 Job 已经成功结束,或者已经失败。
查看Pod日志
# 将 "hello-4111706356" 替换成自己系统中的 Job name
$ pods=$(kubectl get pods --show-all --selector=job-name=hello-4111706356 --output=jsonpath={.items..metadata.name})
$ echo $pods
hello-4111706356-o9qcm
$ kubectl logs $pods
Mon Aug 29 21:34:09 UTC 2019
删除CronJob
当不再需要某个 CronJob 时,可以使用命令将其删除 kubectl delete cronjob
$ kubectl delete cronjob hello
cronjob "hello" deleted
删除 CronJob 时,将移除该 CronJob 创建的所有 Job 和 Pod,并且 CronJob 控制器将不会为其在创建任何新的 Job。