【重识云原生】第六章容器基础6.4.8节——CronJob

2023-03-23 22:36:16 浏览数 (1)

1 CronJob概述

        CronJob 创建基于时隔重复调度的 Jobs。

        一个 CronJob 对象就像 crontab (cron table) 文件中的一行。 它用 Cron 格式进行编写, 并周期性地在给定的调度时间执行 Job。

1.1 介绍

        CronJob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。也就是说,CronJob可以在特定的时间点(反复的)去运行job任务。

Cron Job 管理基于时间的 Job,即:

  • 在给定时间点只运行一次
  • 周期性地在给定时间点运行

        使用条件:当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)

典型的用法如下所示:

  • 在给定的时间点调度 Job 运行
  • 创建周期性运行的 Job,例如:数据库备份、发送邮件

注意:所有 CronJob 的 schedule: 时间都是基于 kube-controller-manager. 的时区。

        如果你的控制平面在 Pod 或是裸容器中运行了 kube-controller-manager, 那么为该容器所设置的时区将会决定 Cron Job 的控制器所使用的时区。

1.2 使用示例

        下面的 CronJob 示例清单会在每分钟打印出当前时间和问候消息:application/job/cronjob.yaml

代码语言:javascript复制
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 运行自动化任务 一文会为你详细讲解此例。

1.3 Cron 时间表语法

代码语言:javascript复制
# ┌───────────── 分钟 (0 - 59)

# │ ┌───────────── 小时 (0 - 23)

# │ │ ┌───────────── 月的某天 (1 - 31)

# │ │ │ ┌───────────── 月份 (1 - 12)

# │ │ │ │ ┌───────────── 周的某天 (0 - 6)(周日到周一;在某些系统上,7 也是星期日)

# │ │ │ │ │                或者是 sun,mon,tue,web,thu,fri,sat

# │ │ │ │ │

# │ │ │ │ │

# * * * * *

输入

描述

相当于

@yearly (or @annually)

每年 1 月 1 日的午夜运行一次

0 0 1 1 *

@monthly

每月第一天的午夜运行一次

0 0 1 * *

@weekly

每周的周日午夜运行一次

0 0 * * 0

@daily (or @midnight)

每天午夜运行一次

0 0 * * *

@hourly

每小时的开始一次

0 * * * *

        例如,下面这行指出必须在每个星期五的午夜以及每个月 13 号的午夜开始任务:

0 0 13 * 5

        要生成 CronJob 时间表表达式,你还可以使用 crontab.guru 之类的 Web 工具。

1.4 时区

        对于没有指定时区的 CronJob,kube-controller-manager 基于本地时区解释排期表(Schedule)。

特性状态: Kubernetes v1.25 [beta]

        如果启用了 CronJobTimeZone 特性门控, 你可以为 CronJob 指定一个时区(如果你没有启用该特性门控,或者你使用的是不支持试验性时区功能的 Kubernetes 版本,集群中所有 CronJob 的时区都是未指定的)。

        启用该特性后,你可以将 spec.timeZone 设置为有效时区名称。 例如,设置 spec.timeZone: "Etc/UTC" 指示 Kubernetes 采用 UTC 来解释排期表。

        Go 标准库中的时区数据库包含在二进制文件中,并用作备用数据库,以防系统上没有可用的外部数据库。

1.5 CronJob 限制

        CronJob 根据其计划编排,在每次该执行任务的时候大约会创建一个 Job。 我们之所以说 "大约",是因为在某些情况下,可能会创建两个 Job,或者不会创建任何 Job。 我们试图使这些情况尽量少发生,但不能完全杜绝。因此,Job 应该是 幂等的。

        如果 startingDeadlineSeconds 设置为很大的数值或未设置(默认),并且 concurrencyPolicy 设置为 Allow,则作业将始终至少运行一次。注意:

        如果 startingDeadlineSeconds 的设置值低于 10 秒钟,CronJob 可能无法被调度。 这是因为 CronJob 控制器每 10 秒钟执行一次检查。

        对于每个 CronJob,CronJob 控制器(Controller) 检查从上一次调度的时间点到现在所错过了调度次数。如果错过的调度次数超过 100 次, 那么它就不会启动这个任务,并记录这个错误:

代码语言:javascript复制
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。

2 CronJob使用

2.1 yaml文件字段简述

代码语言:javascript复制
apiVersion: batch/v1beta1 # batch/v1beta1 #1.21  batch/v1 
kind: CronJob 
metadata: 
  labels: 
    run: hello 
    name: hello 
    namespace: default 
spec: 
  concurrencyPolicy: Allow # 并发调度策略。可选参数如下 
  # Allow:允许同时运行多个任务。 
  # Forbid:不允许并发运行,如果之前的任务尚未完成,新的任务不会被创建。 
  # Replace:如果之前的任务尚未完成,新的任务会替换的之前的任务。 
  failedJobsHistoryLimit: 1 # 保留多少失败的任务 
  jobTemplate: 
    metadata: 
      spec: 
        template: 
          metadata: 
            labels: 
              run: hello 
          spec: 
            containers: 
              - args: 
                - /bin/sh 
                - -c 
                - date; echo Hello from the Kubernetes cluster 
              image: registry.cn-beijing.aliyuncs.com/dotbalo/busybox 
              imagePullPolicy: Always 
              name: hello 
            resources: {} 
            restartPolicy: OnFailure # 重启策略,和Pod一致 
            securityContext: {} 
  schedule: '*/1 * * * *' # 调度周期,和Linux一致,分别是分时日月周。 
  successfulJobsHistoryLimit: 3 # 保留多少已完成的任务,按需配置 
  suspend: false # 如果设置为true,则暂停后续的任务,默认为false。

2.2 CronJob Spec字段说明

  • .spec.schedule:调度,必需字段,指定任务运行周期,格式同 Cron
  • .spec.jobTemplate:Job 模板,必需字段,指定需要运行的任务,格式同 Job
  • .spec.startingDeadlineSeconds :启动 Job 的期限(秒级别),该字段是可选的。如果因为任何原因而错过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限
  • .spec.concurrencyPolicy:并发策略,该字段也是可选的。它指定了如何处理被 Cron Job 创建的 Job 的并发执行。只允许指定下面策略中的一种:
    • Allow(默认):允许并发运行 Job
    • Forbid:禁止并发运行,如果前一个还没有完成,则直接跳过下一个
    • Replace:取消当前正在运行的 Job,用一个新的来替换

注意,当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总是允许并发运行。

  • .spec.suspend :挂起,该字段也是可选的。如果设置为 true,后续所有执行都会被挂起。它对已经开始执行的 Job 不起作用。默认值为 false。
  • .spec.successfulJobsHistoryLimit 和 .spec.failedJobsHistoryLimit :历史限制,是可选的字段。它们指定了可以保留多少完成和失败的 Job。默认情况下,它们分别设置为 3 和 1。设置限制的值为 0,相关类型的 Job 完成后将不会被保留。

2.3 常规操作

2.3.1 运行CronJob

代码语言:javascript复制
$ kubectl create -f ./cronjob.yaml

cronjob "hello" created

或者通过祈使命令行方式:

代码语言:javascript复制
$ kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster"

cronjob "hello" created

2.3.2 查看CronJob状态

代码语言:javascript复制
$ kubectl get cronjob hello

NAME   SCHEDULE  SUSPEND ACTIVE LAST-SCHEDULE

hello   */1****  False    0         <none>
  • NAME:CronJob名称。
  • SCHEDULE:基于时间的调度规则。
  • SUSPEND:如果其值为True表示此CronJob暂时失效,不变成False之前不再创建新任务。对于已经创建的任务没有影响。
  • ACTIVE:表示当前活动的任务数,0表示当前没有活动任务。1表示有一个活动任务。此值可能大于1,原因如下:

1.任务允许重复启动,如前一次启动后还没有退出,下一次已经启动。

2.允许延后启动,当CronJob Controller发现因为某种原因错误启动,并且任务允许延后启动,则会启动任务。

  • LAST-SCHEDULE:表示最后一次调度时间,表示未曾调度过任务。

        从CronJob状态可以看出,其输出中并没有相关字段指示其所创建的JOB是否运行成功,运行如上命令查看JOB的详细信息:

2.3.3 查看CronJob创建的Job

代码语言:javascript复制
$ kubectl get jobs --watch

NAME             DESIRED SUCCESSFUL AGE

hello-4111706356    1        1       2s
  • NAME:表示CronJob创建的Job名称,后边的数字由系统自动生成,保证不重复。
  • DESIRED:表示CronJob只创建的是最简单的一次Job,只创建一个pod。
  • SUCCESSFUL:表示pod成功个数。
  • AGE:表示上JOB生存时间。

再次查看CronJob:

代码语言:javascript复制
$ kubectl get cronjob hello

NAME  SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE

hello */1****   False    0     Mon, 29 Aug 2016 14:34:00 -0700

        LAST-SCHEDULE表示最近一次调度时间,ACTIVE为0表示实例已经运行结束。

        CronJob创建Job,Job创建pod,已经获知CronJob创建的Job名称:hello-4111706356,查看pod方法如下:

代码语言:javascript复制
# Replace "hello-4111706356" with the job name in your system

$ pods=$(kubectl get pods --show-all --selector=job-name=hello-4111706356 --output=jsonpath={.items..metadata.name})

$ echo $pods

hello-4111706356-o9qcm

$ kubectl logs $pods

Mon Aug 29 21:34:09 UTC 2016

Hello from the Kubernetes cluster

2.3.4 删除CronJob

代码语言:javascript复制
$ kubectl delete cronjob hello

cronjob "hello" deleted

        删除CronJob会导致其创建的Job、pod一起被删除。

 参考链接

CronJob · Kubernetes指南

CronJob | Kubernetes

Kubernetes JobCronJob 控制器_疯子@123的博客-CSDN博客

深入K8S Job(三):cronJob controller源码分析 - UCloud云社区

Kubernetes(十)Kubernetes Job 和 CronJob 的实现原理_liu_weiliang10405的博客-CSDN博客

Kubernetes实战(八)-定时任务(Cronjob)_张志翔 ̮的博客-CSDN博客

Kubernetes K8S之资源控制器Job和CronJob详解 - 踏歌行666 - 博客园

7.深入k8s:任务调用Job与CronJob及源码分析

Kubernetes(k8s)计划任务Job&CronJob

K8s ❉ Job 与 CronJob控制器详解_wangjie722703的博客-CSDN博客

0 人点赞