当前位置:   article > 正文

【k8s】Kubernetes基于Pod的设计理念Job/CronJob(四)_kubernet pod和job

kubernet pod和job


在线业务和离线业务

Kubernetes 的业务可以分为两大类:在线业务和离线业务。

  • 在线业务:像 Nginx 、MySQL 这样长时间运行的业务,这些应用一旦运行起来,除非出错或者停止,它的容器进程会一直保持在 Running 状态
  • 离线业务:短时间运行的业务,或者是定时任务,这种业务在计算完成后就直接退出了;它们一般不直接服务于外部用户,只对内部用户有意义,比如日志分析、数据建模、视频转码等等,虽然计算量很大,但只会运行一段时间;也就是说,它们的特点是必定会退出,因此我们需要考虑运行超时、状态检查、失败重试、获取计算结果等管理事项

在上篇中我们也看到了,Kubernetes 基于 Pod 延伸出了很多表示各种业务的其他资源对象。那为什么不直接在 Pod 中添加功能来处理这些业务需求?

这篇笔记会简要阐述 Kubernetes 基于 Pod 的设计理念,也是上面问题的解答。下面先从 Kubernetes 最简单的两种对象 Job 和 CronJob 开始。

一、Pod 功能背后的理念和原则

Kubernetes 使用 YAML 来描述资源,把业务简化成了一个个的对象,内部有属性,外部有联系,也需要互相协作,只不过我们不需要编程,完全由 Kubernetes 自动处理。

面向对象的设计有许多基本原则,其中有两条比较恰当地描述了 Kubernetes 对象设计思路,一个是单一职责,另一个是组合优于继承

  • 单一职责:对象应该只专注于做好一件事情,保持足够小的粒度才更方便复用和管理
  • 组合优于继承:尽量让对象在运行时产生联系,保持松耦合,而不要用硬编码的方式固定对象的关系

因为 Pod 已经是一个相对完善的对象,专门负责管理容器,那么我们就不应该再画蛇添足地盲目为它扩充功能,而是要保持它的独立性,容器之外的功能就需要定义其他的对象,把 Pod 作为它的一个成员组合进去。每种 Kubernetes 对象就可以只关注自己的业务领域,只做自己最擅长的事情,其他的工作交给其他对象来处理,既不缺位也不越位,既有分工又有协作。

二、Job 和 CronJob

“离线业务”也可以分为两种。一种是“临时任务”,运行完成就结束了,如果有需要可以再次安排;另一种是“定时任务”,可以按时按点周期运行,不需要过多干预。为了实现对离线业务的处理,Kubernetes 组合了 Pod 推出两种新的对象 JobCronJob,“临时任务”就是 API 对象 Job,“定时任务”就是 API 对象 CronJob,使用这两个对象我们就能够在 Kubernetes 里调度管理任意的离线业务了。

YAML 文件的“头部”:

  • apiVersion: batch/v1
  • kind: Job,这与对象的名字是一致的
  • metadata: 里面仍要有 name 标记名字,也可以用 labels 添加任意的标签

当然我们也可以用 kubectl create 来生成 YAML 模板:

$ kubectl create job echo-job --image=busybox --dry-run=client -o yaml
  • 1

注意:想要生成 YAML 样板文件的话不能使用 kubectl run,因为 kubectl run 只能创建 Pod,要创建 Pod 以外的其他 API 对象,需要使用命令 kubectl create,再加上对象的类型名

下面是我们生成的 Job 对象的 YAML 文件(修改后的):

apiVersion: batch/v1
kind: Job
metadata:
  name: echo-job

spec:
  template:
    spec:
      restartPolicy: OnFailure
      containers:
      - image: busybox
        name: echo-job
        imagePullPolicy: IfNotPresent
        command: ["/bin/echo"]
        args: ["hello", "world"]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

可以看出,JobPod 主要的区别就在 spec 字段里,多了一个 template 字段,然后又是一个 spec
它其实就是在 Job 对象里应用了组合模式,template 字段定义了一个“应用模板”,里面嵌入了一个 Pod,这样 Job 就可以从这个模板来创建出 Pod。

而这个 Pod 因为受 Job 的管理控制,不直接和 apiServer 打交道,也就没必要重复 apiVersion 等“头字段”,只需要定义好关键的 spec,描述清楚容器相关的信息就可以了,可以说是一个“无头部”的 Pod 对象。

apiVersion 字段是 batch/v1,表明它不属于核心对象组(core group),而是属于批处理对象组(batch group)

在这里插入图片描述

这个 Pod 工作非常简单,在 containers 里写好名字和镜像,command 执行 /bin/echo,输出“hello world”。

因为 Job 业务的特殊性,所以我们还要在 spec 里多加一个字段 restartPolicy,确定Pod 运行失败时的策略,OnFailure 是失败原地重启容器,而Never 则是不重启容器,让 Job 去重新调度生成一个新的 Pod

1、在 Kubernetes 里面操作 Job

使用下面的命令来创建 Job:

$ kubectl apply -f job.yml
job.batch/echo-job created
  • 1
  • 2

然后我们可以查看 Job、Pod 的状态:

$ kubectl get jobs
NAME       COMPLETIONS   DURATION   AGE
echo-job   1/1           13s        26s
$ kubectl get pods
NAME             READY   STATUS      RESTARTS   AGE
echo-job-vr84n   0/1     Completed   0          29s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

因为 Pod 被 Job 管理,它就不会反复重启报错了,而是会显示为 Completed 表示任务完成,而 Job 里也会列出运行成功的作业数量,这里只有一个作业,所以就是 1/1。Pod 被自动关联了一个名字,用的是 Job 的名字(echo-job)再加上一个随机字符串。

最后我们查看一下 Pod 的输出:

$ kubectl logs echo-job-vr84n
hello world
  • 1
  • 2

Job 在运行结束后,为了方便获取处理结果,不会立即删除。但是积累过多的已完成的 Job 也会消耗系统资源,我们可以使用 ttlSecondsAfterFinished 设置一个保留时限。参阅已完成 Job 的自动清理

2、几个离线作业的重要字段

上面我们操作了一个最简单的 Job,其实 Kubernetes 还支持在Job 级别、Pod 级别添加任意的字段来定制业务。


apiVersion: batch/v1
kind: Job
metadata:
  name: sleep-job

spec:
  activeDeadlineSeconds: 15
  backoffLimit: 2
  completions: 4
  parallelism: 2

  template:
    spec:
      restartPolicy: OnFailure
      containers:
      - image: busybox
        name: echo-job
        imagePullPolicy: IfNotPresent
        command:
          - sh
          - -c
          - sleep $(($RANDOM % 10 + 1)) && echo done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

这里是几个控制离线作业的重要字段,其他更详细的信息可以参考 Job 文档

activeDeadlineSeconds - 设置 Pod 运行的超时时间
backoffLimit - 设置 Pod 的失败重试次数
completions - Job 完成需要运行多少个 Pod,默认是 1 个
parallelism - 它与 completions 相关,表示允许并发运行的 Pod 数量,避免过多占用资源

这 4 个字段并不在 template 字段下,而是在 spec 字段下,所以它们是属于 Job 级别的,用来控制模板里的 Pod 对象。

“声明式”的 Job 对象让离线业务的描述变得非常直观,简单的几个字段就可以很好地控制作业的并行度和完成数量,不需要我们去人工监控干预,Kubernetes 把这些都自动化实现了。

3、使用 YAML 描述 CronJob

CronJob 是定时任务,在 Kubernetes 中简称CronJobcj (前面提到过可以通过 kubectl api-resources 命令查看)。下面我们使用命令来创建一个 CronJob 的 YAML 模板,因为是定时任务,在命令行里还需要指定参数 --schedule 这个参数就是用来定义哪个时间运行任务:

kubectl create cj echo-cj --image=busybox --schedule="" --dry-run=client -o yaml
  • 1

然后稍微编辑一下,就生成一个描述 CronJob 对象的 YAML 文件:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: echo-cj

spec:
  schedule: '*/1 * * * *'
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - image: busybox
            name: echo-cj
            imagePullPolicy: IfNotPresent
            command: ["/bin/echo"]
            args: ["hello", "world"]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

除了名字不同,CronJob 和 Job 的用法几乎是一样的,使用 kubectl apply 创建 CronJob,使用 kubectl get cj、kubectl get pod 来查看状态:

$ kubectl apply -f cronjob.yml
$ kubectl get cj
$ kubectl get pod
  • 1
  • 2
  • 3

这个 YAML 连续有三个 spec 嵌套层次:

  • 第一个 spec 是 CronJob 自己的对象规格声明
  • 第二个 spec 从属于“jobTemplate”,它定义了一个 Job 对象
  • 第三个 spec 从属于“template”,它定义了 Job 里运行的 Pod

在这里插入图片描述

除了定义 Job 对象的jobTemplate字段之外,CronJob 还有一个新字段就是schedule,用来定义任务周期运行的规则。它使用的是标准的 Cron 语法,指定分钟、小时、天、月、周,和 Linux 上的 crontab 是一样的。

出于节约资源的考虑,CronJob 不会无限期地保留已经运行的 Job,它只会保留最近三个执行结果,当然我们也可以用successfulJobsHistoryLimit 改变保留的数量。参阅 使用 CronJob 运行自动化任务
其余的用法可以参考 CronJob 文档


总结

  1. Pod 是 Kubernetes 的最小调度单元,但为了保持它的独立性,不应该向它添加多余的功能。
  2. Kubernetes 为离线业务提供了 Job 和 CronJob 两种 API 对象,分别处理“临时任务”和“定时任务”。
  3. Job 的关键字段是 spec.template,里面定义了用来运行业务的 Pod 模板,其他的重要字段有 completions、parallelism 等
  4. CronJob 的关键字段是 spec.jobTemplate 和 spec.schedule,分别定义了 Job 模板和定时运行的规则。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/563771
推荐阅读
相关标签
  

闽ICP备14008679号