3

Kubernetes 设计模式笔记 —— Job & CronJob

 1 year ago
source link: https://rollingstarky.github.io/2023/06/19/kubernetes-patterns-reading-notes-job-and-cronjob/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Kubernetes 设计模式笔记 —— Job & CronJob

2023-06-19

| Linux

| 0

|

3.9k

|

0:04

Batch Job

Batch Job 模式适合处理隔离的原子化的工作任务,能够在分布式的环境中,可靠地运行 short-lived Pods,直到工作任务成功地结束。

在 Kubernetes 中,可以通过不同的方式创建 Pod:

  • Bare Pod:可以手动创建 Pod 来运行容器应用,但是当此类 Pod 所在的节点失效时,Pod 不会自动重启。除非用于开发或测试目的,此类方式并不推荐
  • ReplicaSet:当 Pod 应该长时间持续运行时(比如 web server),就适合用此方式来创建 Pod 和管理其生命周期。它会确保在任意时刻,运行着的 Pod 副本数量都是稳定的
  • DaemonSet:负责在每一个节点上都部署一个 Pod。通常情况下用于平台管理工作,比如监控、日志聚合、存储等

上述 Pod 有一个共同点,它们都代表着长时间运行的进程,并不是在一段时间后就需要被关掉。但是在某些场景下,仍需要执行一类预先定义好的、有限的工作流,当该工作流程可靠地完成后,再关闭对应的容器。

Kubernetes Job 类似于 ReplicaSet,它也会创建 1 个或者多个 Pods 并确保它们成功运行。区别在于,当特定数量的 Pods 成功终止后,Job 就变为完成状态,不会再有额外的 Pod 被启动。

apiVersion: batch/v1
kind: Job
metadata:
name: random-generator
spec:
completions: 5
parallelism: 2
template:
metadata:
name: random-generator
spec:
restartPolicy: OnFailure
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
command: [ "java", "-cp", "/", "RandomRunner", "/numbers.txt", "10000" ]

比如上面配置的 Job,会确保有 5 个 Pod 成功执行完毕,可以有两个 Pod 同时运行。此外,Job 配置文件中的 restartPolicy 是必需的,且其值只能是 OnFailureNever,不能是 Always

为什么不通过 bare Pods 来执行 Job 对应的任务呢?因为 Job 相比于 bare Pods,能够提供更多可靠性和扩展性方面的好处。

  • Job 并不是临时的 in-memory 任务,而是一个持久化的能够在集群重启后幸存的任务
  • Job 完成后并不会被删除,而是继续保留,方便以后追踪问题。只有当 bare Pods 是 restartPolicy: OnFailure 时,其才会拥有同样的特性
  • Job 可能需要执行多次,可以通过 .spec.completions 指定
  • 当任务确实需要完成多次时,Job 还支持扩展,即同一时间开启多个 Pods。可以通过 .spec.parallelism 指定
  • 若节点失效,或者 Pod 正在运行时因为某些原因被移除,由 Job 创建的 Pods 会被 scheduler 重新分配给健康的节点

两个字段对控制 Job 的行为发挥着关键作用:

  • .spec.completions:指定 Pod 的数量。当特定数量的 Pod 执行完毕后,当前 Job 才算完成
  • .spec.parallelism:指定可以并行执行的 Pod 副本数量

Parallel Batch Job with a fixed completion count

基于上述两个参数,Job 可以分为如下几种类型:

  • Single Pod Job:不设置 .spec.completions.spec.parallelism 的值,或者将它们设置为默认值 1。此类 Job 只会启动一个 Pod,当 Pod 成功退出后,Job 完成
  • Fixed completions count Jobs:.spec.completions 的值大于 1。当特定数量(.spec.completions)的 Pod 执行完毕后,Job 完成
  • Work queue Job:.spec.completions 不设置或者设为默认值,.spec.parallelism 大于 1。适用于工作队列中的 Job。当至少有一个 Pod 成功终止时,所有其他 Pod 也会自行终止。比如,一堆固定数量的待处理项目保存在某个队列中,并行的 Pod 可以按顺序获取并处理它们,当某个 Pod 检测到队列为空并成功退出后,Job controller 等待其他 Pod 终止运行

Job 帮助我们将隔离的工作单元变成一个可靠的、可扩展的执行单元。并不是所有的服务都需要一直运行,比如某些服务可能需要按需运行,某些必须在特定的时间窗口运行,某些必须按照计划重复执行。
通过 Job 可以只在需要的时候运行 Pod,且任务完成后就退出。使用 Job 处理 short-lived 任务可以节约系统资源。

Periodic Job

Periodic Job 是对 Batch Job 的扩展,为其添加了时间维度,同时允许临时的事件触发工作流的执行。
在分布式系统的世界里,有一种比较清晰的倾向,借助 HTTP 和轻量的消息系统实现实时、事件驱动的应用。不考虑软件开发中的此类倾向,计划任务仍然是一种历史悠久且至今常用的手段。
它们通常用于自动化的系统维护工作或者管理员任务,在商业应用方面的场景比如文件同步、发送邮件、清理和归档旧文件等。

传统的处理 Periodic Job 的方式是借助专门的计划任务软件比如 Cron。但是 Cron jobs 运行在单一的服务器上,难以维护且有发生单点故障的风险。
这也是为什么很多开发者会尝试实现自己的方案,比如 Java 中的 Quartz、Spring Batch 等。但是类似于 Cron,它们也会遇到弹性和高可用性方面的挑战,导致较高的资源使消耗。此外在这类方案里,Job 调度器是应用的一部分,为了获得高可用,通常就需要运行多个应用实例,同时还需要确保同一时刻下只有一个实例是活跃的。从而引入 leader election 等分布式系统问题。

面对以上的一些问题,Kubernetes 实现了 CronJob,允许开发者以广为熟知的 Cron 格式将 Job 设置为计划任务。

apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: random-generator
spec:
# Every three minutes
schedule: "*/3 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
command: [ "java", "-cp", "/", "RandomRunner", "/numbers.txt", "10000" ]
restartPolicy: OnFailure

与 Job 相比,CronJob 有一些额外的字段:

  • .spec.schedule:指定 Job 的 schedule 模式(如 0 * * * * 表示每个小时触发一次)
  • .spec.startingDeadlineSeconds:Job 启动时的截止时间。有些时候由于资源不够或者缺少其他依赖,Job 错过了预定的触发时间。此字段用于指定错过多少秒后就直接跳过此次执行
  • .spec.concurrencyPolicy:用于控制同一个 CronJob 的并发执行。默认值为 Allow,即使前一个 Job 并未结束,也允许新的 Job 实例被创建;可以指定为 Forbid,若当前 Job 并未结束,则跳过下一次执行;或者改为 Replace,取消当前还未结束的 Job 并启动一个新的 Job 实例
  • .spec.suspend:暂停所有后续执行,但不影响已经开始的执行
  • .spec.successfulJobsHistoryLimit.spec.failedJobsHistoryLimit:应保留多少已完成和失败的 Job 作为审计数据

CronJob 其实是一个非常简单的原语,在现有的 Job 定义中添加类似 Cron 的行为。但是当它与 Kubernetes 提供的其他原语比如 Pods、资源隔离结合起来时,就成为一个非常强大的任务调度系统。
它的调度行为是平台的一部分,实现在应用的外部,使得开发者能够专注于应用的业务逻辑,无需在应用内部额外设计一套调度逻辑。同时提供了高可用、高弹性、高容积以及由策略驱动的 Pod 部署等特性。
当然,和 Job 一样,CronJob 容器在部署时,也需要考虑所有的特殊情况,比如重复执行、未触发、并发执行和任务取消等。

Kubernetes Patterns


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK