本文由 CNCF + Alibaba 云原生技术公开课 整理而来
Job
?Kubernetes 中最小的调度单元是 Pod
。可以直接通过 Pod
来运行任务进程,但这样做会产生以下问题:
1. 如何保证 Pod 内进程正确的结束?
2. 如何保证进程运行失败后重试?
3. 如何管理多个任务,且任务之间有依赖关系?
4. 如何并行运行任务,并管理任务的队列大小?
Kubernetes 的 Job
就是为解决以上问题而产生的,它提供以下功能:
1. Job 是管理任务的控制器,它可以创建指定数量的 Pod,并监控它们是否成功地运行或终止
2. 跟踪 Pod 状态,根据配置及时重试失败的 Pod
3. 可以根据依赖关系,保证上一个任务运行完成之后再运行下一个任务
4. 可以控制任务的并行度,根据并行度来确保 Pod 运行过程中的并行次数和总体完成大小
Job
语法:pi Job
yaml 文件示例:
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
completions: 10
parallelism: 2
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4
文件解析:
apiVersion: batch/v1 表示 Job 当前所属的组是 batch,版本是 v1
kind 表示 Kubernetes 资源类型是 Job
metadata 表示 Job 的元数据,元数据通常包含 name 、namespace 等
spec 表示 Job 的期望状态,completions 表示 Job 执行的次数;parallelism 表示并行执行的 Pod 个数;backoffLimit 表示 Job 重试的次数
template 表示 Pod 的模板,模板中也有 Pod 的 spec,restartPolicy 表示 Pod 的重启策略
Pod
的重启策略有 3 种:
Never 无论怎样都不重启
OnFailure 在运行失败时重启
Always 无论怎样都会重启
Job
状态:当创建出一个 Job
,可以通过 kubectl get job
命令查看 Job
的状态。具体可以看到这些字段:
COMPLETIONS 执行完成的 Pod 数量
DURATION Job 实际业务运行的时长
AGE Job 创建的时长
Job
:对于需要并行执行的任务,可以通过设置 Job
的参数来完成:
completions:指定Job 执行的次数
parallelism:指定并行执行的 Pod 个数
以上面示例为例,这个计算圆周率的 Job
需要执行 10 次,每次并行运行 2 个 Pod
,这样一共会执行 5 次。
CronJob
语法:还有一种 Job
是 CronJob
,它主要用于定时任务,和 Job
唯一的不同点在于它可以设置一个时间,和 Linux 的 crontab 时间格式相同(分时日月周),CronJob
会在指定的时间定时执行任务。
hello CronJob
yaml 文件示例:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args: ["/bin/sh", "-c", "echo 'Hello'"]
restartPolicy: OnFailure
schedule: "*/1 * * * *"
startingDeadlineSeconds: 10
concurrencyPolicy: Allow
successfulJobsHistoryLimit: 3
CronJob
和 Job
相比会多一些字段:
schedule:设置定时执行的时间,时间格式和 Linux crontab 相同
startingDeadlineSeconds:Job 最长启动时间,超过该时间会停止 Job,单位是秒
concurrencyPolicy:是否允许并行运行。Allow:允许并发运行;JobForbid:禁止并发运行;Replace:重建,新创建的 Job 替代旧的 Job
successfulJobsHistoryLimit:允许留存的历史 Job 个数
这里的并发运行指的是,如果每分钟执行一次任务,但 Job
执行完成的时间超过 1 分钟,这样的话会同时存在多个 Job
。设置为 Allow
即允许多个 Job
同时存在,不管前面的 Job
是否执行完成,新的 Job
都会运行。
Job
管理模式:1. Job Controller 负责根据配置创建 Pod
2. Job Controller 跟踪 Job 状态,根据配置及时重试 Pod 或继续创建
3. Job Controller 会自动添加 label 来追踪对应的 Pod,并根据配置并行或串行地创建 Pod
Job
控制器:Job
控制器会 Watch
API Server
的状态,每次提交的 Job
的 yaml 文件都会经过 API Server
传递到 etcd
中,然后 Job
控制器会注册几个 Handler
,每当有添加、更新、删除等操作时,它会通过一个内存消息队列发送到 Job
。通过 Job
控制器检查当前是否有运行的 Pod
,如果没有则会通过 Scale up
创建,如果有或大于指定的数量则会对它进行 Scale down
,如果 Pod
发生变化也会及时更新它的状态。
同时 Job
控制器会检查是并行或串行的 Job
,根据设置的并行度,及时地把 Pod
创建出来。最后,它会把 Job
的状态更新到 API Server
中。
DaemonSet
?在使用 Kubernetes 时可能会有这些需求:
1. 如何让集群每个节点都运行且只运行一个 Pod?
2. 如何感知加入集群的新节点,并在其上部署一个 Pod 进行初始化?
3. 如何在节点退出集群时删除该节点上的 Pod?
4. 如何监控集群节点及 Pod 的状态,并做汇报工作?
DaemonSet
守护进程控制器:DaemonSet
也是 Kubernetes 提供的一个 default controller,它实际是一个守护进程的控制器,有以下作用:
1. 能够保证集群内的每一个节点都运行相同的 Pod
2. 能够根据节点状态保证新加入的节点自动创建对应的 Pod
3. 在移除节点时,能删除对应的 Pod
4. 而且能追踪每个 Pod 的状态,能在出现异常时及时恢复
DaemonSet
语法:fluentd-elasticsearch DaemonSet
yaml 文件示例:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
app: fluentd-logging
spec:
selector:
matchLabels:
app: fluentd-logging
template:
metadata:
labels:
app: fluentd-logging
spec:
containers:
- name: fluentd-elasticsearch
image: fluent/fluentd:v1.4-1
文件解析:
apiVersion: apps/v1 表示 DaemonSet 当前所属的组是 apps,版本是 v1
kind 表示 Kubernetes 资源类型是 DaemonSet
metadata 表示 DaemonSet 的元数据,元数据通常包含 name、namespace、labels、annotations 等
spec 表示 DaemonSet 的期望状态,selector 表示 Pod 选择器,选择带相同 label 的 Pod;
template 表示 Pod 的模板,模板中也有 Pod 的 metadata 和 spec
DaemonSet
常用的场景有这些:
1. 存储,如 Gluster 或 Ceph 等,需要在每个节点上都运行一个类似 Agent 的东西,DaemonSet 可以很好地满足
2. 日志收集,如 logstash 或 fluentd 等,需要在每个节点都运行一个 Agent
3. 监控,需要在每个节点运行 Agent 进行监控,如 Prometheus 等
DaemonSet
状态:当创建出一个 Job
,可以通过 kubectl get DaemonSet
查看 DaemonSet
的状态。DaemonSet
的返回和 Deployment
类似。具体可以看到这些字段:
DESIRED 需要创建的 Pod 数量
CURRENT 当前实际的 Pod 数量
UP-TO-DATE 到达期望版本的 Pod 数量
AVAILABLE 运行中可用的 Pod 数量
AGE DaemonSet 创建的时长
DaemonSet
:DaemonSet
有 2 种更新策略:
RollingUpdate 滚动更新,先生成新 Pod,就绪后移除旧 Pod,然后生成第二个 Pod,依次类推,直到更新完毕
OnDelete 模板更新之后,Pod 只有通过手动删除才会更新,便于手动控制更新
DaemonSet
管理模式:1. DaemonSet Controller 负责根据配置创建 Pod
2. DaemonSet Controller 跟踪 DaemonSet 状态,根据配置及时重试 Pod 或继续创建
3. DaemonSet Controller 会自动添加 affinity 和 label 来追踪对应的 Pod,并根据配置在每个节点或适合条件的部分节点创建 Pod
DaemonSet
控制器:DaemonSet
控制器和 Job
控制器做的事情类似,都需要 Wtach
API Server
的状态。不同之处在于,DaemonSet
控制器还需要去 Wtach
节点的状态,但其实节点的状态也是通过 API Server
传递到 etcd
的。
当节点的状态发生变化时,它会通过一个内存消息队列发进来,然后 DaemonSet
控制器会去 Watch
这个状态,看一下各节点上是否有对应的 Pod
。如果没有的话就去创建;如果有的话就会比较版本,然后看是否需要 RollingUpdate
或 Ondelete
,决定是否更新或创建对应 Pod
。完成之后,DaemonSet
控制器会把 DaemonSet
的状态更新到 API Server
中。