CronJob

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 创建的作业定义了一个模板,它是必需的。它与 作业 的架构完全相同,只是它是嵌套的,并且没有 apiVersionkind。你可以为模板化的作业指定通用元数据,例如 标签注释。有关编写作业 .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_TZTZ 变量指定时区是官方不支持的(并且从未支持过)。

从 Kubernetes 1.29 开始,如果您尝试设置包含 TZCRON_TZ 时区规范的计划,Kubernetes 将无法创建资源并显示验证错误。对已使用 TZCRON_TZ 的 CronJob 的更新将继续向客户端报告警告

修改 CronJob

根据设计,CronJob 包含作业的模板。如果您修改现有的 CronJob,您所做的更改将应用于在修改完成后开始运行的新作业。已启动的作业(及其 Pod)将继续运行,而不会发生更改。也就是说,CronJob 不会更新现有作业,即使这些作业仍在运行。

作业创建

CronJob 大约在其计划的每次执行时间创建一个 Job 对象。调度是近似的,因为在某些情况下可能会创建两个作业,或者可能不会创建任何作业。Kubernetes 试图避免这些情况,但不能完全阻止它们。因此,您定义的作业应该是幂等的

如果 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 字段(不是 nil),则控制器会计算从 startingDeadlineSeconds 的值到现在为止错过了多少个作业,而不是从上次计划时间到现在为止。例如,如果 startingDeadlineSeconds200,则控制器会计算在过去 200 秒内错过了多少个作业。

如果 CronJob 未能在其计划时间创建,则计为错过。例如,如果 concurrencyPolicy 设置为 Forbid,并且在之前的计划仍在运行时尝试调度 CronJob,则该 CronJob 将被计为错过。

例如,假设 CronJob 设置为从 08:30:00 开始每分钟调度一个新作业,并且其 startingDeadlineSeconds 字段未设置。如果 CronJob 控制器恰好在 08:29:0010:21:00 之间关闭,则作业将不会启动,因为错过计划的作业数量大于 100。

为了进一步说明此概念,假设 CronJob 设置为从 08:30:00 开始每分钟调度一个新作业,并且其 startingDeadlineSeconds 设置为 200 秒。如果 CronJob 控制器恰好在与上一个示例相同的时间段(08:29:0010:21:00)关闭,则作业仍将在 10:22:00 启动。这是因为控制器现在检查在过去 200 秒内错过了多少个计划(即 3 个错过的计划),而不是从上次计划时间到现在为止。

CronJob 仅负责创建与其计划匹配的作业,而作业又负责管理其表示的 Pod。

下一步

  • 了解Pod作业,这两个概念是 CronJob 所依赖的。
  • 阅读有关 CronJob .spec.schedule 字段的详细格式
  • 有关创建和使用 CronJob 的说明,以及 CronJob 清单的示例,请参阅使用 CronJob 运行自动化任务
  • CronJob 是 Kubernetes REST API 的一部分。有关更多详细信息,请阅读CronJob API 参考。
上次修改时间:2024 年 4 月 12 日上午 9:48(太平洋标准时间):更新 cronjobs 历史记录限制规范描述 (dba05c9a60)