# 使用CronJob执行自动任务

参考文档: Running Automated Tasks with a CronJob (opens new window)

CronJob 可以用来执行基于时间计划的定时任务,类似于Linux/Unix系统中的 crontable (opens new window)

CronJob 执行周期性的重复任务时非常有用,例如备份数据、发送邮件等。CronJob 也可以用来指定将来某个时间点执行单个任务,例如将某项任务定时到系统负载比较低的时候执行。

CronJob 也存在某些限制,例如,在某些情况下,一个 CronJob 可能会创建多个 Job。因此,Job 必须是 幂等 的。更多与此相关的限制请参考 CronJob

# 创建CronJob

下面例子中的 CronJob 每分钟,打印一次当前时间并输出 hello world 信息。

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 执行命令以创建 CronJob:

    kubectl create -f https://kuboard.cn/statics/learning/job/cronjob.yaml
    
    1

    输出结果如下所示:

    cronjob.batch/hello created
    
    1

    或者,您也可以直接使用 kubectl run 命令创建 CronJob:

    kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster"
    
    1
  • 执行命令以查看已创建 CronJob 的状态

    kubectl get cronjob hello
    
    1

    输出结果如下所示:

    NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
    hello   */1 * * * *   False     0        <none>          10s
    
    1
    2

    从输出结果可以看到,该 CronJob 还未运行任何 Job。执行一下命令,并等候一分钟左右时间

    kubectl get jobs --watch
    
    1

    输出结果如下所示:

    NAME               COMPLETIONS   DURATION   AGE
    hello-4111706356   0/1                      0s
    hello-4111706356   0/1   0s    0s
    hello-4111706356   1/1   5s    5s
    
    1
    2
    3
    4

    此时,可以看到该 CronJob 创建了一个 "hello-4111706356" Job,并执行结束。这时ctrl + c 停止 watch,并重新查看 Cronjob 的状态:

    kubectl get cronjob hello
    
    1

    输出信息如下所示:


     

    NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
    hello   */1 * * * *   False     0        50s             75s
    
    1
    2

    输出结果显示,该 CronJob 在 LAST SCHEDULE 这个时间点成功创建了一个 Job。当前 ACTIVE Job 数为 0,意味着,该 Job 已经成功结束,或者已经失败。

  • 查看 Pod 的输出信息

    执行命令获取 Pod 的名称

    # 将 "hello-4111706356" 替换成您系统中的 Job name
    pods=$(kubectl get pods --selector=job-name=hello-4111706356 --output=jsonpath={.items[*].metadata.name})
    
    1
    2

    查看 Pod 的日志:

    kubectl logs $pods
    
    1

    输出结果如下所示:

    Fri Feb 22 11:02:09 UTC 2019
    Hello from the Kubernetes cluster
    
    1
    2

# 删除CronJob

当您不再需要某个 CronJob 时,可以使用命令将其删除 kubectl delete cronjob <cronjob name>,在本例中,可以执行命令:

kubectl delete cronjob hello
1

或者

kubectl delete -f https://kuboard.cn/statics/learning/job/cronjob.yaml
1

删除 CronJob 时,将移除该 CronJob 创建的所有 Job 和 Pod,并且 CronJob 控制器将不会为其在创建任何新的 Job。更多信息请参考 垃圾回收

# 编写CronJob YAML

与其他所有 Kubernetes 对象一样,CronJob 对象需要 apiVersionkindmetadata 这几个字段。CronJob 还需要 .spec 字段。

TIP

所有对 CronJob 对象作出的修改,尤其是 .spec 的修改,都只对修改之后新建的 Job 有效,已经创建的 Job 不会受到影响

# Schedule

.spec.schedule 是一个必填字段。类型为 Cron (opens new window) 格式的字符串,例如 0 * * * * 或者 @hourly,该字段定义了 CronJob 应该何时创建和执行 Job。

该字段同样支持 vixie cron step 值(step values),参考 FreeBSD manual (opens new window)。例如,指定 CronJob 每隔两个小时执行一次,可以有如下三种写法:

  • 0 0,2,4,5,6,8,12,14,16,17,20,22 * * *
  • 使用 范围值 + Step 值的写法:0 0-23/2 * * *
  • Step 也可以跟在一个星号后面,如 0 */2 * * *

TIP

问号 ? 与 星号 * 的含义相同,代表着该字段不做限定

# Job Template

.spec.jobTemplate 字段是必填字段。该字段的结构与 Job 相同,只是不需要 apiVersionkind。请参考 编写Job的定义

# Starting Deadline

.spec.startingDeadlineSeconds 为可选字段,代表着从计划的时间点开始,最迟多少秒之内必须启动 Job。如果超过了这个时间点,CronJob 就不会为其创建 Job,并将其记录为一次错过的执行次数。如果该字段未指定,则 Job 必须在指定的时间点执行。

CronJob 控制器将为每一个 CronJob 记录错过了多少次执行次数,如果错过的执行次数超过 100,则控制器将不会再为该 CronJob 创建新的 Job。如果 .spec.startingDeadlineSeconds 未指定,CronJob 控制器计算从 .status.lastScheduleTime 开始到现在为止总共错过的执行次数。

例如,某一个 CronJob 应该每分钟执行一次,.status.lastScheduleTime 的值是 上午5:00,假设现在已经是上午7:00。这意味着已经有 120 次执行时间点被错过,因此该 CronJob 将不再执行了。

如果 .spec.startingDeadlineSeconds 字段被设置为一个非空的值,则 CronJob 控制器计算将从 .spec.startingDeadlineSeconds 秒以前到现在这个时间段内错过的执行次数。

例如,假设该字段被设置为 200,控制器将只计算过去 200 秒内错过的执行次数。如果在过去 200 秒之内,有超过 100 次错过的执行次数,则 CronJob 将不再执行。

# Concurrency Policy

.spec.concurrencyPolicy 是选填字段,指定了如何控制该 CronJob 创建的 Job 的并发性,可选的值有:

  • Allow: 默认值,允许并发运行 Job
  • Forbid: 不允许并发运行 Job;如果新的执行时间点到了,而上一个 Job 还未执行完,则 CronJob 将跳过新的执行时间点,保留仍在运行的 Job,且不会在此刻创建新的 Job
  • Replace: 如果新的执行时间点到了,而上一个 Job 还未执行完,则 CronJob 将创建一个新的 Job 以替代正在执行的 Job

TIP

Concurrency policy 只对由同一个 CronJob 创建的 Job 生效。如果有多个 CronJob,则他们各自创建的 Job 之间不会相互影响。

# Suspend

.spec.suspend 是选填字段。如果该字段设置为 true,所有的后续执行都将挂起,该字段不会影响到已经创建的 Job。默认值为 false

警告

挂起(suspend)的时间段内,如果恰好存在有计划的执行时间点,则这些执行时间计划都被记录下来。如果不指定 .spec.startingDeadlineSeconds,并将 .spec.suspend 字段从 true 修改为 false,则挂起这段时间内的执行计划都将被立刻执行。

# Job History Limits

.spec.successfulJobsHistoryLimit.spec.failedJobsHistoryLimit 字段是可选的。这些字段指定了 CronJob 应该保留多少个 completed 和 failed 的 Job 记录。

  • .spec.successfulJobsHistoryLimit 的默认值为 3
  • .spec.failedJobsHistoryLimit 的默认值为 1

如果将其设置为 0,则 CronJob 不会保留已经结束的 Job 的记录。

更新时间: 2019-11-19 11:56:33