CronJob
Kubernetes v1.21 [稳定]
一个 _CronJob_ 会在重复的计划中创建 作业。
CronJob 用于执行定期计划的操作,例如备份、报告生成等等。一个 CronJob 对象就像 Unix 系统上的 _crontab_(cron 表)文件中的单行。它按给定计划定期运行一个作业,该计划以 Cron 格式编写。
CronJob 存在限制和特殊情况。例如,在某些情况下,单个 CronJob 可以创建多个并发作业。请参阅下面的 限制。
当控制平面为 CronJob 创建新的作业(间接地)和 Pod 时,CronJob 的 .metadata.name
是为这些 Pod 命名的基础的一部分。CronJob 的名称必须是有效的 DNS 子域 值,但这可能会为 Pod 主机名产生意外的结果。为了最好的兼容性,名称应该遵循 DNS 标签 的更严格规则。即使名称是 DNS 子域,名称的长度也不能超过 52 个字符。这是因为 CronJob 控制器会自动将您提供的名称附加 11 个字符,并且有一个约束,即作业名称的长度不超过 63 个字符。
示例
此 CronJob 清单示例每分钟打印当前时间和一条问候语。
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.28
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
(使用 CronJob 运行自动化任务 会更详细地介绍此示例)。
编写 CronJob 规范
计划语法
.spec.schedule
字段是必需的。该字段的值遵循 Cron 语法
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday)
# │ │ │ │ │ OR sun, mon, tue, wed, thu, fri, sat
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
例如,0 0 13 * 5
表示任务必须在每个月的 13 日午夜以及每个星期五午夜启动。
该格式还包括扩展的“Vixie cron”步进值。如 FreeBSD 手册 中所述
步进值可以与范围一起使用。在范围后加上
/<number>
表示在范围内以该数字的值跳过。例如,0-23/2
可以用在小时字段中,表示每隔一个小时执行命令(在 V7 标准中的替代方法是0,2,4,6,8,10,12,14,16,18,20,22
)。步进值也可以在星号后使用,因此如果要表示“每两个小时”,只需使用*/2
即可。
注意
计划中的问号 (?
) 与星号 *
的含义相同,即它代表给定字段中的任何可用值。除了标准语法之外,还可以使用一些宏,例如 @monthly
条目 | 描述 | 等效于 |
---|---|---|
@yearly(或 @annually) | 每年 1 月 1 日午夜运行一次 | 0 0 1 1 * |
@monthly | 每月第一个月的午夜运行一次 | 0 0 1 * * |
@weekly | 每周星期天凌晨午夜运行一次 | 0 0 * * 0 |
@daily(或 @midnight) | 每天午夜运行一次 | 0 0 * * * |
@hourly | 每小时开始时运行一次 | 0 * * * * |
要生成 CronJob 计划表达式,还可以使用诸如 crontab.guru 之类的 Web 工具。
作业模板
.spec.jobTemplate
定义了 CronJob 创建的作业的模板,它是必需的。它具有与 作业 完全相同的模式,只是它嵌套在内,并且没有 apiVersion
或 kind
。您可以为模板化的作业指定通用元数据,例如 标签 或 注释。有关编写作业 .spec
的信息,请参阅 编写作业规范。
延迟作业启动的截止时间
.spec.startingDeadlineSeconds
字段是可选的。此字段定义了作业启动的截止时间(以整秒为单位),如果该作业由于任何原因错过了其预定的时间。
错过截止时间后,CronJob 会跳过该作业的实例(将来的发生时间仍然会安排)。例如,如果您有一个每天运行两次的备份作业,您可能允许它延迟最多 8 小时启动,但不能再晚,因为在任何时间之后进行的备份都没有用:您宁愿等待下一次预定的运行。
对于错过其配置的截止时间的作业,Kubernetes 会将其视为失败的作业。如果您没有为 CronJob 指定 startingDeadlineSeconds
,则作业发生时间没有截止时间。
如果设置了 .spec.startingDeadlineSeconds
字段(不是 null),则 CronJob 控制器会测量从作业预计创建的时间到现在的这段时间。如果差异大于该限制,它将跳过这次执行。
例如,如果它设置为 200
,则允许在实际计划时间后最多 200 秒创建作业。
并发策略
.spec.concurrencyPolicy
字段也是可选的。它指定了如何处理由此 CronJob 创建的作业的并发执行。规范最多只能指定以下并发策略之一
Allow
(默认):CronJob 允许并发运行作业Forbid
:CronJob 不允许并发运行;如果到了新的作业运行时间,而之前的作业运行尚未完成,则 CronJob 会跳过新的作业运行。还要注意,当之前的作业运行完成时,仍然会考虑.spec.startingDeadlineSeconds
,并且可能导致新的作业运行。Replace
:如果到了新的作业运行时间,而之前的作业运行尚未完成,则 CronJob 会用新的作业运行替换当前正在运行的作业运行
请注意,并发策略仅适用于由同一 CronJob 创建的作业。如果有多个 CronJob,则始终允许其各自的作业并发运行。
计划暂停
您可以通过将可选的 .spec.suspend
字段设置为 true 来暂停 CronJob 的作业执行。该字段默认为 false。
此设置不会影响 CronJob 已经启动的作业。
如果您确实将该字段设置为 true,则所有后续执行都会被暂停(它们仍然会排程,但 CronJob 控制器不会启动作业来运行任务),直到您取消暂停 CronJob 为止。
作业历史记录限制
.spec.successfulJobsHistoryLimit
和 .spec.failedJobsHistoryLimit
字段指定应保留多少个已完成的成功作业和失败作业。这两个字段都是可选的。
.spec.successfulJobsHistoryLimit
:此字段指定要保留的成功完成作业的数量。默认值为3
。将此字段设置为0
将不会保留任何成功作业。.spec.failedJobsHistoryLimit
:此字段指定要保留的失败完成作业的数量。默认值为1
。将此字段设置为0
将不会保留任何失败作业。
有关自动清理作业的另一种方法,请参阅 自动清理完成的作业。
时区
Kubernetes v1.27 [稳定]
对于没有指定时区的 CronJob,kube-控制器管理器 会将其本地时区作为参考来解释计划。
您可以通过将 .spec.timeZone
设置为有效 时区 的名称来为 CronJob 指定时区。例如,将 .spec.timeZone: "Etc/UTC"
设置为告诉 Kubernetes 以协调世界时 (UTC) 为参考来解释计划。
Go 标准库中的时区数据库包含在二进制文件中,并在系统上没有外部数据库时用作后备。
CronJob 限制
不支持的时区规范
使用 .spec.schedule
中的 CRON_TZ
或 TZ
变量来指定时区是 **未正式支持的**(而且从未支持过)。
从 Kubernetes 1.29 版本开始,如果您尝试设置包含 TZ
或 CRON_TZ
时区规范的计划,Kubernetes 将无法创建资源,并会返回验证错误。已使用 TZ
或 CRON_TZ
的 CronJobs 更新将继续向客户端报告 警告。
修改 CronJob
根据设计,CronJob 包含一个用于 新 Job 的模板。如果您修改现有的 CronJob,您所做的更改将应用于修改完成之后开始运行的新 Job。已经开始运行的 Job(及其 Pod)将继续运行而不会发生更改。也就是说,CronJob 不会更新现有的 Job,即使这些 Job 仍然在运行。
Job 创建
CronJob 大约会在其计划的每次执行时间创建一次 Job 对象。调度是近似执行的,因为在某些情况下可能会创建两个 Job,或者可能不会创建任何 Job。Kubernetes 试图避免这些情况,但并不能完全阻止它们。因此,您定义的 Job 应该具有 幂等性。
如果 startingDeadlineSeconds
设置为一个较大的值或保持未设置(默认值),并且如果 concurrencyPolicy
设置为 Allow
,则 Job 将始终至少运行一次。
注意
如果startingDeadlineSeconds
设置为小于 10 秒的值,则 CronJob 可能不会被调度。这是因为 CronJob 控制器每 10 秒检查一次。对于每个 CronJob,CronJob 控制器 检查从其上次计划时间到现在的持续时间内错过了多少个计划。如果错过的计划超过 100 个,那么它将不会启动 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
字段被设置(不是 nil
),则控制器将计算从 startingDeadlineSeconds
的值到现在的持续时间内错过了多少个 Job,而不是从上次计划时间到现在的持续时间内错过的 Job 数量。例如,如果 startingDeadlineSeconds
为 200
,则控制器将计算过去 200 秒内错过了多少个 Job。
如果 CronJob 在其计划的时间内未能创建,则它会被计为错过。例如,如果 concurrencyPolicy
设置为 Forbid
,并且在先前计划仍在运行时尝试调度 CronJob,则它会被计为错过。
例如,假设 CronJob 被设置为从 08:30:00
开始每分钟调度一个新 Job,并且其 startingDeadlineSeconds
字段未设置。如果 CronJob 控制器恰好在 08:29:00
到 10:21:00
之间发生故障,则 Job 不会启动,因为错过的 Job 数量超过了 100 个。
为了进一步说明这个概念,假设 CronJob 被设置为从 08:30:00
开始每分钟调度一个新 Job,并且其 startingDeadlineSeconds
设置为 200 秒。如果 CronJob 控制器恰好在与上一个例子相同的时期内发生故障(08:29:00
到 10:21:00
),则 Job 仍然会在 10:22:00 启动。这是因为控制器现在检查过去 200 秒内错过了多少个计划(即 3 个错过的计划),而不是从上次计划时间到现在的持续时间内错过的计划数量。
CronJob 仅负责创建与其计划匹配的 Job,而 Job 负责管理其所代表的 Pod。
下一步
- 了解 Pod 和 Job,这两个概念是 CronJob 所依赖的。
- 阅读关于 CronJob
.spec.schedule
字段的详细 格式。 - 有关创建和使用 CronJob 的说明以及 CronJob 清单示例,请参阅 使用 CronJob 运行自动化任务。
CronJob
是 Kubernetes REST API 的一部分。阅读 CronJob API 参考以了解更多详细信息。