写在前面
本文一起看下使用k8s来进行作业和定时作业。
1:k8s的业务类型
如果是按照业务类型来划分的话,可以分为离线业务
和在线业务
,如下:
在线业务:容器启动之后就一直不退出的业务,如Nginx
离线业务:容器启动后执行一段时间就退出,如busybox
job:提供容器单次运行的能力
cronJob:提供容器多次运行的能力
busybox是一个集成了很多命令和工具的软件,进行了压缩,体积小,方便使用。
针对在线业务使用pod启动容器后,就在那里好好的运行
就行了,但是对于离线业务,怎么办呢?pod只具备编排容器的能力,但并不具备以某种运行方式
运行容器的能力,比如以某种固定的时间频率运行一组容器,那么我们能不能在pod原有功能的基础上对其改造让其具备这种能力呢?理论上是可以的,但是这就不符合面向对象的单一职责
原则了,毕竟k8s的apiserver的请求处理方式也是按照面向对象的思想来封装的,这怎么办呢?我们知道,有一种设计模式叫做装饰模式 ,通过组合原有的对象,即将原有对象作为自己的成员变量,这样在使用其固有能力的同时,也可以增加自己需要的增强逻辑了,比如我们这里对于pod装饰,如果是Job,则装饰后的伪代码可能如下:
class Job {
private Pod pod = new Pod();
// 任务执行设置信息
private JobSetting jobSetting = new JobSetting("任务设置信息");
public void run() {
// 满足job要求
if (满足jobSetting要求) {
// 通过pod编排容器,执行作业
pod.orchestrationContainers();
}
}
}
现在pod在job的增强下已经能够按照某种设置来执行离线作业了,但是如果是想要实现cronJob又该怎么办呢?依然是如此,继续装饰job即可,如下伪代码:
class CronJob {
private Job job = new Job();
// 设置执行频率的对象
private Cron cron = new Cron("*/1 * * * *");
public void run() {
while (true) {
if (cron判断又该执行了) {
// 通过job执行离线作业
job.run();
}
}
}
}
其实k8s也正是这么做的,接下来就一起看下。
2:Job
首先通过如下操作生成Job的yaml:
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl create job echo-job --image=busybox $out
apiVersion: batch/v1
kind: Job
metadata:
creationTimestamp: null
name: echo-job
spec:
template:
metadata:
creationTimestamp: null
spec:
containers:
- image: busybox
name: echo-job
resources: {}
restartPolicy: Never
status: {}
修改后最终如下:
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"]
然后创建job:
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl apply -f job.yml
job.batch/echo-job created
查看pod(因为是对pod的装饰或增强,所以底层还是要创建pod的)
,如下可以获取job:
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl get job
NAME COMPLETIONS DURATION AGE
echo-job 1/1 15s 10m
其中COMPLETIONS是1/1
说明作业已经完成了,DURATION
作业持续时长是15s。当然也可以看其内部的pod,如下:
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl get pod
NAME READY STATUS RESTARTS AGE
echo-job-rjq86 0/1 Completed 0 2m9s
可以看到pod的名字是echo-job-rjq86
,是在job的name后自动增加了一个随机后缀,这样我们就不需要在yaml中配置了,降低使用的复杂度,另外READY是0/1
,是因为这是一个离线任务,执行完毕后就结束了,如下可以看到job包装的pod中容器的输出信息:
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl logs -c echo-job echo-job-rjq86
hello world
我们在前面分析了job是对pod的装饰和增强,其实从yaml文件的结构也是可以看出来的,参考下图:
看到这里,你可能会想,job也不过如此,我直接用pod也可以实现,何必多此一举,但实际job能力远不止于此,它还提供了很多的配置参数,如下的几个:
activeDeadlineSeconds,设置 Pod 运行的超时时间。
backoffLimit,设置 Pod 的失败重试次数。
completions,Job 完成需要运行多少个 Pod,默认是 1 个。
parallelism,它与 completions 相关,表示允许并发运行的 Pod 数量,避免过多占用资源。
然后我们就可以将Job的参数设置成15秒超时,最多重试2次,总共需要运行完4个 Pod,但同一时刻最多并发2个Pod,yaml如下:
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
创建job:
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl apply -f sleepjob.yml
job.batch/sleep-job created
查看作业执行进度:
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl get job
NAME COMPLETIONS DURATION AGE
sleep-job 3/4 9s 9s
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl get job
NAME COMPLETIONS DURATION AGE
sleep-job 4/4 14s 14s
一共4个任务,最终变成4/4
即所有的作业都完成了,如下也可以查看执行的进度:
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl get pod -w
NAME READY STATUS RESTARTS AGE
sleep-job-6jdkh 1/1 Running 0 8s
sleep-job-cmwbm 0/1 Completed 0 8s
sleep-job-kgc9l 1/1 Running 0 4s
sleep-job-6jdkh 0/1 Completed 0 9s
sleep-job-6gd9l 0/1 Pending 0 0s
sleep-job-6gd9l 0/1 Pending 0 0s
sleep-job-6gd9l 0/1 ContainerCreating 0 0s
sleep-job-6jdkh 0/1 Completed 0 9s
sleep-job-6gd9l 1/1 Running 0 1s
sleep-job-kgc9l 0/1 Completed 0 9s
sleep-job-kgc9l 0/1 Completed 0 9s
sleep-job-6gd9l 1/1 Completed 0 6s
可以看到容器在不断的进行创建,运行,完成,这个其实就是job在根据我们的设置信息来不断的调用pod的功能的过程,这个不断的创建,运行,完成
也正是job对pod装饰的内容。
3:CronJob
上面我们看了job,再看cronjob就容易多了,cronjob就是对job进行了进一步的装饰,增加了按照固定周期执行job的功能,如下生成cronjob对应的yaml:
dongyunqi@dongyunqi-virtual-machine:~/test$ export out="--dry-run=client -o yaml" # 定义Shell变量
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl create cj echo-cj --image=busybox --schedule="" $out
apiVersion: batch/v1
kind: CronJob
metadata:
creationTimestamp: null
name: echo-cj
spec:
jobTemplate:
metadata:
creationTimestamp: null
name: echo-cj
spec:
template:
metadata:
creationTimestamp: null
spec:
containers:
- image: busybox
name: echo-cj
resources: {}
restartPolicy: OnFailure
schedule: ""
status: {}
修改完善后如下:
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"]
主要增加了schedule
表达式 用来设置job执行的频率,如下创建cronjob对象:
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl apply -f cronjob.yml
cronjob.batch/echo-cj created
这样就会按照每分钟一次的频率来执行作业了,如下查看生成的job和pod:
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl get job
NAME COMPLETIONS DURATION AGE
echo-cj-27884435 1/1 1s 2m4s
echo-cj-27884436 1/1 1s 64s
echo-cj-27884437 1/1 0s 4s
dongyunqi@dongyunqi-virtual-machine:~/test$ kubectl get pod
NAME READY STATUS RESTARTS AGE
echo-cj-27884435-j2mjg 0/1 Completed 0 2m8s
echo-cj-27884436-8fbxs 0/1 Completed 0 68s
echo-cj-27884437-5nqkc 0/1 Completed 0 8s
可以看到每个job都对应一个pod(通过pod名称前缀可以匹配到所属的job)
。最后看下此时cronjob对job的装饰结构:
写在后面
小节
本文先分析了面向对象中的装饰设计模式,后又介绍了在线任务和离线任务,然后进行类比分别引出了job对pod的装饰,cronjob对job的装饰,并分别看了具体的例子,希望能帮助到你。
参考文章列表
cron任务表达式 。