1. CronJob
CronJob 管理基于时间的 Job,即:
- 在给定时间点只运行一次
- 周期性地在给定时间点运行。创建周期性运行的 Job,例如:数据库备份、发送邮件。
注意:
Cronjob 管理的对象是 job,job 运行时创建的 pod,cronjob不直接管理 pod。
一个 CronJob 对象类似于 Linux 系统计划任务 crontab 文件中的一行。它根据指定的预定计划周期性地运行一个 Job,格式可以参考 Cron 。
从集群版本 1.8 开始,batch/v2alpha1 API 组中的 CronJob 资源已经被废弃。 你应该切换到 API 服务器默认启用的 batch/v1beta1 API 组。
对于先前版本的集群,版本 < 1.8,启动 API Server(参考 为集群开启或关闭 API 版本 获取更多信息)时,通过传递选项 --runtime-config=batch/v2alpha1=true
可以开启 batch/v2alpha1 API。
在 Kubernetes 1.4 版本引入了 ScheduledJob 资源,但从 1.5 版本开始改成了 CronJob。
为 CronJob 资源创建清单时,请确保所提供的名称是一个合法的 DNS 子域名. 名称不能超过 52 个字符。 这是因为 CronJob 控制器将自动在提供的 Job 名称后附加 11 个字符,并且存在一个限制, 即 Job 名称的最大长度不能超过 63 个字符。
1.1. API 版本对照表
Kubernetes 版本 | Batch API 版本 | 默认开启 |
---|---|---|
v1.5-v1.7 | batch/v2alpha1 | 否 |
v1.8-v1.9 | batch/v1beta1 | 是 |
注意:使用默认未开启的 API 时需要在 kube-apiserver 中配置 --runtime-config=batch/v2alpha1
。
1.2. CronJob Spec
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
namespace: test-ns
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
1.2.1. schedule
.spec.schedule
:调度,必需字段,指定任务运行周期,格式同 Cron。
它的值是 Cron 格式字的符串,例如:0 * * * *
,或者 @hourly
,根据指定的调度时间 Job 会被创建和执行。
在预定计划中,问号(?)和星号(*)的意义是相同的,表示给定字段的取值是任意可用值。
注意:
所有 CronJob 的 schedule 时间都是基于初始 Job 的主控节点的时区。
Crontab 基本语法:
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
该格式也包含了扩展的 vixie cron 步长值。 FreeBSD 手册中解释如下: 步长可被用于范围组合。范围后面带有 /<数字> 可以声明范围内的步幅数值。 例如,0-23/2 可被用在小时域来声明命令在其他数值的小时数执行 ( V7 标准中对应的方法是0,2,4,6,8,10,12,14,16,18,20,22)。 步长也可以放在通配符后面,因此如果你想表达 "每两小时",就用 */2 。
1.2.2. jobTemplate
.spec.jobTemplate
:Job 模板,必需字段,指定需要运行的任务,格式同 Job。
它是 Job 的模板。 除了它可以是嵌套的,并且不具有 apiVersion 或 kind 字段之外,它和 Job 一样具有完全相同的模式(schema)。 参考 编写 Job 规格。
1.2.3. startingDeadlineSeconds
.spec.startingDeadlineSeconds
:启动 Job 的期限(秒级别),该字段是可选的。它表示任务如果由于某种原因错过了调度时间,开始该任务的截止时间的秒数。过了截止时间,CronJob 就不会开始任务。 不满足这种最后期限的任务会被统计为失败任务。如果该域没有声明,那任务就没有最后期限。
CronJob 控制器会统计错过了多少次调度。如果错过了100次以上的调度,CronJob 就不再调度了。 当没有设置 .spec.startingDeadlineSeconds
时,CronJob 控制器统计从 status.lastScheduleTime
到当前的调度错过次数。 例如一个 CronJob 期望每分钟执行一次,status.lastScheduleTime
是 5:00am, 但现在是 7:00am。那意味着 120 次调度被错过了,所以 CronJob 将不再被调度。 如果设置了 .spec.startingDeadlineSeconds
域(非空),CronJob 控制器统计从 `.spec.startingDeadlineSeconds1 到当前时间错过了多少次任务。 例如设置了 200,它会统计过去 200 秒内错过了多少次调度。 在那种情况下,如果过去 200 秒内错过了超过 100 次的调度,CronJob 就不再调度。
1.2.4. successfulJobsHistoryLimit
.spec.successfulJobsHistoryLimit
历史成功任务的保留数量,该字段是可选的,在 Kubernetes 1.8版本后支持。
成功完成的作业保存多少个。默认为3,设置限制的值为 0
时相关类型的 Job 完成后将不会被保留。
1.2.5. failedJobsHistoryLimit
.spec.failedJobsHistoryLimit
: 历史失败任务的保留数量,该字段是可选的,在 Kubernetes 1.8版本后支持。
失败的作业保存多少个,默认为1,设置限制的值为 0
时相关类型的 Job 完成后将不会被保留。
1.2.6. concurrencyPolicy
.spec.concurrencyPolicy
:并发策略,该字段也是可选的。它指定了如何处理被 Cron Job 创建的 Job 的并发执行。只允许指定下面策略中的一种:
Allow
(默认):允许并发运行 JobForbid
:禁止并发运行,如果前一个还没有完成,则直接跳过下一个Replace
:取消当前正在运行的 Job,用一个新的来替换
注意:
当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总是允许并发运行。
1.2.7. suspend
.spec.suspend
:挂起,该字段也是可选的。如果设置为 true
,后续所有执行都会被挂起。它对已经开始执行的 Job 不起作用。默认值为 false
。
注意:
在调度时间内挂起的执行都会被统计为错过的任务。当
.spec.suspend
从true
改为false
时, 且没有开始的最后期限,错过的任务会被立即调度。
1.3. 示例
1.3.1. 创建cronjob
$ kubectl create -f cronjob.yaml
cronjob "hello" created
当然,也可以用kubectl run
来创建一个CronJob:
kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster"
1.3.2. 查看cronjob
$ kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE
hello */1 * * * * False 0 <none>
$ kubectl get jobs
NAME DESIRED SUCCESSFUL AGE
hello-1202039034 1 1 49s
$ pods=$(kubectl get pods --selector=job-name=hello-1202039034 --output=jsonpath={.items..metadata.name})
$ kubectl logs $pods
Mon Aug 29 21:34:09 UTC 2016
Hello from the Kubernetes cluster
$ kubectl delete cronjob hello
cronjob "hello" deleted
1.3.3. 删除 Cron Job
一旦不再需要 Cron Job,简单地可以使用 kubectl
命令删除它:
$ kubectl delete cronjob hello
cronjob "hello" deleted
这将会终止正在创建的 Job。
然而,运行中的 Job 将不会被终止,不会删除 Job 或 它们的 Pod。
为了清理那些 Job 和 Pod,需要列出该 Cron Job 创建的全部 Job,然后删除它们:
$ kubectl get jobs
NAME DESIRED SUCCESSFUL AGE
hello-1201907962 1 1 11m
hello-1202039034 1 1 8m
...
$ kubectl delete jobs hello-1201907962 hello-1202039034 ...
job "hello-1201907962" deleted
job "hello-1202039034" deleted
...
一旦 Job 被删除,由 Job 创建的 Pod 也会被删除。
注意:
所有由名称为 “hello” 的 Cron Job 创建的 Job 会以前缀字符串 “hello-” 进行命名。如果想要删除当前 Namespace 中的所有 Job,可以通过命令
kubectl delete jobs --all
立刻删除它们。
1.4. 扩展阅读
1.4.1. CronJob 限制
CronJob 根据其计划编排,在每次该执行任务的时候大约会创建一个 Job。 我们之所以说 "大约",是因为在某些情况下,可能会创建两个 Job,或者不会创建任何 Job。 我们试图使这些情况尽量少发生,但不能完全杜绝。因此,Job 应该是 幂等的。
如果 startingDeadlineSeconds
设置为很大的数值或未设置(默认),并且 concurrencyPolicy
设置为 Allow,则作业将始终至少运行一次。
对于每个 CronJob,CronJob 控制器 检查从上一次调度的时间点到现在所错过了调度次数。如果错过的调度次数超过 100 次, 那么它就不会启动这个任务,并记录这个错误:
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
设置的值到现在而不是从上一个计划时间到现在错过了多少次 Job。 例如,如果 startingDeadlineSeconds
是 200,则控制器会统计在过去 200 秒中错过了多少次 Job。
如果未能在调度时间内创建 CronJob,则计为错过。 例如,如果 concurrencyPolicy
被设置为 Forbid,并且当前有一个调度仍在运行的情况下, 试图调度的 CronJob 将被计算为错过。
例如,假设一个 CronJob 被设置为从 08:30:00 开始每隔一分钟创建一个新的 Job,并且它的 startingDeadlineSeconds
字段 未被设置。如果 CronJob 控制器从 08:29:00 到 10:21:00 终止运行,则该 Job 将不会启动,因为其错过的调度次数超过了100。
为了进一步阐述这个概念,假设将 CronJob 设置为从 08:30:00 开始每隔一分钟创建一个新的 Job, 并将其 startingDeadlineSeconds
字段设置为 200 秒。 如果 CronJob 控制器恰好在与上一个示例相同的时间段(08:29:00 到 10:21:00)终止运行, 则 Job 仍将从 10:22:00 开始。 造成这种情况的原因是控制器现在检查在最近 200 秒(即 3 个错过的调度)中发生了多少次错过的 Job 调度,而不是从现在为止的最后一个调度时间开始。
CronJob 仅负责创建与其调度时间相匹配的 Job,而 Job 又负责管理其代表的 Pod。