动手动脑学Kubernetes系列教程之CronJob

查理谈科技 2024-05-12 22:56:02

在之前的文章中, 介绍了搭建好的#minikube#环境,如果你现在还没有一个可用的minikube环境, 那么可以去中直接下载;

在#动手动脑学Kubernetes#系列教程中, 我们展示了Kubernetes的基本用法

在里, 学习了#Pod#的基本知识;

在里, 学习了标签(#Label#)的语法, 使用Label来选择和过滤Kubernetes 资源;

在里, 介绍了#Deployment#的使用, 介绍了Deployment与Replica Set、Pod的关系, 并展示了如何进行应用的版本回滚;

在里, 介绍了#Service#的使用,使用Replication Controller创建Pod, 并创建Service, 展示了从Service 调用应用的方法; 随后又展示了扩展 Pod的数量为2, 比较了Service和之前的不同, 基本展示了Cluster IP 类型的Service的基本用法.

在里, 介绍了#Namespace#的使用, 除了创建,列出系统的Namespace之外, 还说明Namespace 如何对资源进行隔离, 建立Development, Staging, Production等环境的方法.

在里, 介绍了#Service Discovery#的使用, 讲解了如何检查Kube-dns, 如何检查和使用Service的FQDN等知识, 对Kubernetes的DNS 系统有整体的理解.

在里, 介绍了#Port Forwards#, #端口转发#的用法, 在本地程序开发的时候, 使用端口转发可以简化本地测试的工作, 同时介绍了其他几种本地端口转发的用法.

在里, 介绍了#Probe#(#探针#)的知识, 介绍了livenessProbe 和readinessProbe的用法,同时介绍了Pod 容器中的几个状态变化, 以及2个容器生命周期回调接口.

在里, 介绍了#环境变量#的用法, 使用环境变量可以把Pod 定义的信息传递给运行其中的镜像.

在里, 我们介绍了#Volume#, 卷的用法, 主要展示了emptyDir卷的使用, emptyDir卷的生命周期是和Pod 生命周期同步的.

在里, 我们介绍了#Persistent Volume#, 也就是持久卷的用法,展示了当数据存入到PV 之后,数据超乎Pod 生命周期之外的情况.

在里, 介绍了Secret, 也就是机密信息的用法, 机密是绑定在命名空间里的, 在使用时候和Volume的用法一样, 可以被Pod 访问, 本篇展示了Opaque类型的Secret的用法.

在里, 介绍了日志(logging)的使用, 介绍了Kubernetes中基本日志记录的查看和常用的命令行参数,在理论部分展示了其他几种logging的使用.

在第十四篇里,介绍了Job的使用, 并介绍了批处理作用中最常见的Job, 也就是一次性作业的使用, 这种作业是执行一次, 然后结束; 同时还介绍了批处理作业中的几种模式, 以及Job 和Pod 的关系, 和Job中失败后如何处理的策略等。

在本篇里, 我们将继续学习另外一种Job,#CronJob#, 也就是定时作业, 继续学习吧!

之前我们介绍的Job 都是一次性作业, 但是假如有下面一个作业, 需要每两小时运行一次, 这时候就需要CronJob了, CronJob借助#Cron# 表达式, 可以在设定好的时间内启动批处理作业。

CronJobs 对于创建周期性的、反复重复的任务很有用,例如执行数据备份或者发送邮件。 CronJobs 也可以用来计划在指定时间来执行的独立任务,例如计划当集群看起来很空闲时 执行某个 Job。

先来看一个例子吧。

从镜像开始

先来看一下这次CronJob的镜像(image), 这个镜像的程序逻辑是从数字1作为起始值, 把传入的参数(数值)作为上限, 每隔两秒就会打印一个带有当前序号的字符串。

#! /bin/bashLOOP_COUNT=$1echo "This Job will echo message $1 times"for ((i=1;i<=$LOOP_COUNT;i++)); do sleep 2 echo $i] Hey I will run till the job completes.done

下面是cronjob的具体信息:

文件地址:https://raw.githubusercontent.com/hintcnuie/kbe/main/specs/jobs/cronjob.yaml

yaml文件内容:

apiVersion: batch/v1beta1kind: CronJobmetadata: name: cronjob-demospec: schedule: "0,15,30,45 * * * *" jobTemplate: spec: template: metadata: labels: app: cronjob-demo spec: restartPolicy: OnFailure containers: - name: cronjob-demo image: hintcnuie/cronjob-demo args: ["100"]

注意: 这其中的apiVersion信息是batch/v1beta1, 也就是说cronjob 当前还处于beta1的状态, 这跟job的apiVersion: batch/v1是不同的, 在编写的时候需要当心版本问题。

下面来创建这个cronjob:

$ kubectl apply -f https://raw.githubusercontent.com/hintcnuie/kbe/main/specs/jobs/cronjob.yamlcronjob.batch/cronjob-demo created$ kubectl get cronjobs.batch NAME            SCHEDULE             SUSPEND   ACTIVE   LAST SCHEDULE   AGEcronjob-demo    0,15,30,45 * * * *   False     0        <none>          12s

下面我们来看一下这个cronjob 是怎么样被调度和执行的(schedule)

查看CronJob的调度信息

我们在上面的文件定义中可以看到, 这个cronjob的cron 表达式是这样的:0,15,30,45 * * * *, 这是什么意思呢? 在Kubernetes的cron 表达式中, 第一项是分钟(minutes), 也就是在这个表达式里面, 每隔15分钟运行一次, 分别在[0,15,30,45]这几个时间点运行。

我们在用命令查看的时候,也能看出这个schedule的具体情况:

如上图所示, 当我们在第一次查看pod 信息的时候,时间是44分,这时 并没有发现cronjob-demo相关的Pod;而当第二次查看, 也就是在45分钟的时候, 可以看到已经产生了一个名为cronjob-demo-1617547500-smrz6的Pod(当然, Pod 的名称里, 后缀部分是随机产生的), 负责执行这个job。

来看下这个Pod的日志情况, 从日志中可以看出, 已经打印出了 从1 到100的信息:

$ kubectl logs cronjob-demo-1617547500-smrz6This Job will echo message 100 times1] Hey I will run till the job completes....100] Hey I will run till the job completes.

可见, 这个CronJob 已经按照调度, 每隔15分钟执行一次作业。

当然, 时间跨度再大一点, 还可以看到CronJob的其他几次调度, 这里从Dashboard会看得更加清楚:

手动触发CronJob

对于CronJob, 除了等待被调用之外, 有没有其他方法来验证Job 是否会正常执行? 答案是可以, CronJob 可以通过手工的方式kubectl create job --from=cronjob/<job-name>来调用:

$ kubectl create job manual-cronjob-demo --from=cronjob/cronjob-demojob.batch/manual-cronjob-demo created$ kubectl get cronjobsNAME            SCHEDULE             SUSPEND   ACTIVE   LAST SCHEDULE   AGEcronjob-demo    0,15,30,45 * * * *   False     0        5m40s           46mhellocronjob    */1 * * * *          False     0        3h33m           13hhellocronjob2   */1 * * * *          False     0        3h33m           11h$ kubectl get jobNAME                       COMPLETIONS   DURATION   AGEcronjob-demo-1617547500    1/1           3m32s      35mcronjob-demo-1617548400    1/1           3m26s      20mcronjob-demo-1617549300    1/1           3m26s      5m50smanual-cronjob-demo        0/1           24s        24s

通过执行命令kubectl create job manual-cronjob-demo --from=cronjob/cronjob-demo, 我们创建了一个对cronjob-demo的拷贝, 但是注意, 这个新的job 只是一个一次性的Job, 所以只能用来临时性的调试或者查看CronJob, 这种方式失去了CronJob的调度信息。

好了, 对于CronJob的操作部分, 我们就介绍到这里吧, 下面来看看理论部分。

Kuberentes CronJob的表达式

Kubernetes 从1.5版本开始增加了一种新的类型 Job,即类似 Linux Cron 的定时任务 Cron Job,Cron Job 创建基于时间调度的 Jobs。

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

注意:

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

为 CronJob 资源创建清单时,请确保所提供的名称是一个合法的 DNS 子域名. 名称不能超过 52 个字符。 这是因为 CronJob 控制器将自动在提供的 Job 名称后附加 11 个字符,并且存在一个限制, 即 Job 名称的最大长度不能超过 63 个字符。

CronJob中的Cron 表达式

Kubernetes CronJob中的Cron 表达式和Linux 中常用的Cron 表达式非常类似, 但两者之间也有一些区别,需要注意的是 Kubernetes 的 Cron Job 定时表达式第 1 位是分钟而不是秒,格式如下:

# ┌───────────── 分钟 (0 - 59)# │ ┌───────────── 小时 (0 - 23)# │ │ ┌───────────── 月的某天 (1 - 31)# │ │ │ ┌───────────── 月份 (1 - 12)# │ │ │ │ ┌───────────── 周的某天 (0 - 6) (周日到周一;在某些系统上,7 也是星期日)# │ │ │ │ │ # │ │ │ │ │# │ │ │ │ │# * * * * *

输入

描述

相当于

*

表示匹配任意值

如果在Minutes 项使用,表示每分钟

/

递进值

表示起始时间开始触发,然后每隔固定时间触发一次。在Minutes 设置的是5/20,则表示第一次触发是在第5min时,接下来每20min触发一次,即,第25min,45min等时刻触发。比如每隔1min执行一次任务:则Cron 表达式如下:

*/1 * * * *

用逗号分隔开的值列表

表示在指定的时间点执行, 如上面的0,15,30,45 * * * *

-

范围值

表示在指定的时间范围内执行, 如下面的表达式指定在9点和17点之间,每个小时的第0分钟开始执行任务

0 9-17 * * *

@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的Cron表达式学习难度大, 那么可以到专门的网站去使用Cron表达式生成器来产生, 如https://crontab.guru,https://crontab-generator.org等,其中cron.guru是Kubernetes官方推荐的Cron表达式生成器, 但是在国内访问速度稍微有点慢。

CronJob 限制

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

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

注意:

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

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

Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.

好了, 对于CronJob, 就学习到这里吧, 每天学习一点Kubernetes, 每天都有进步!

总结

本文中通过例子介绍了CronJob的用法,以及如何查看CronJob的执行情况;同时给出了手工执行CronJob的方法, 用来调试和验证CronJob;最后介绍了Cron表达式的写法, 以及CronJob的注意事项。

0 阅读:0

查理谈科技

简介:感谢大家的关注