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
字段(不为空),则 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-controller-manager 会将其解释为相对于其本地时区的计划。
您可以通过将 .spec.timeZone
设置为有效的 时区 名称来为 CronJob 指定时区。例如,设置 .spec.timeZone: "Etc/UTC"
会指示 Kubernetes 将计划解释为相对于协调世界时。
二进制文件中包含一个来自 Go 标准库的时区数据库,并在系统上没有外部数据库可用时用作回退。
CronJob 限制
不支持的 TimeZone 规范
使用 .spec.schedule
中的 CRON_TZ
或 TZ
变量指定时区是官方不支持的(并且从未支持过)。
从 Kubernetes 1.29 开始,如果您尝试设置包含 TZ
或 CRON_TZ
时区规范的计划,Kubernetes 将无法创建资源并显示验证错误。对已使用 TZ
或 CRON_TZ
的 CronJob 的更新将继续向客户端报告警告。
修改 CronJob
根据设计,CronJob 包含新作业的模板。如果您修改现有的 CronJob,您所做的更改将应用于在修改完成后开始运行的新作业。已启动的作业(及其 Pod)将继续运行,而不会发生更改。也就是说,CronJob 不会更新现有作业,即使这些作业仍在运行。
作业创建
CronJob 大约在其计划的每次执行时间创建一个 Job 对象。调度是近似的,因为在某些情况下可能会创建两个作业,或者可能不会创建任何作业。Kubernetes 试图避免这些情况,但不能完全阻止它们。因此,您定义的作业应该是幂等的。
如果 startingDeadlineSeconds
设置为较大的值或未设置(默认值),并且 concurrencyPolicy
设置为 Allow
,则作业将始终至少运行一次。
警告
如果startingDeadlineSeconds
设置为小于 10 秒的值,则 CronJob 可能不会被调度。这是因为 CronJob 控制器每 10 秒检查一次。对于每个 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
字段(不是 nil
),则控制器会计算从 startingDeadlineSeconds
的值到现在为止错过了多少个作业,而不是从上次计划时间到现在为止。例如,如果 startingDeadlineSeconds
为 200
,则控制器会计算在过去 200 秒内错过了多少个作业。
如果 CronJob 未能在其计划时间创建,则计为错过。例如,如果 concurrencyPolicy
设置为 Forbid
,并且在之前的计划仍在运行时尝试调度 CronJob,则该 CronJob 将被计为错过。
例如,假设 CronJob 设置为从 08:30:00
开始每分钟调度一个新作业,并且其 startingDeadlineSeconds
字段未设置。如果 CronJob 控制器恰好在 08:29:00
到 10:21:00
之间关闭,则作业将不会启动,因为错过计划的作业数量大于 100。
为了进一步说明此概念,假设 CronJob 设置为从 08:30:00
开始每分钟调度一个新作业,并且其 startingDeadlineSeconds
设置为 200 秒。如果 CronJob 控制器恰好在与上一个示例相同的时间段(08:29:00
到 10:21:00
)关闭,则作业仍将在 10:22:00 启动。这是因为控制器现在检查在过去 200 秒内错过了多少个计划(即 3 个错过的计划),而不是从上次计划时间到现在为止。
CronJob 仅负责创建与其计划匹配的作业,而作业又负责管理其表示的 Pod。
下一步
- 了解Pod和作业,这两个概念是 CronJob 所依赖的。
- 阅读有关 CronJob
.spec.schedule
字段的详细格式。 - 有关创建和使用 CronJob 的说明,以及 CronJob 清单的示例,请参阅使用 CronJob 运行自动化任务。
CronJob
是 Kubernetes REST API 的一部分。有关更多详细信息,请阅读CronJob API 参考。