出于某些目的,有时需要在Kubernetes的一个Pod中,连续依次运行多个Container。 这种有明确结束预期的运行,即Kubernetes的Job。 但是,虽然一个Job可以在一个Pod内运行多个Container,然而运行方式是并发的。
一种方法是在业务层处理。 比如,通过共享的本地Volume,使用文件锁的机制,可以实现多个并发的Container依次执行。 但这需要在业务逻辑中,把并发强行改为同步,增加了开发复杂度。 如果能使用Kubernetes本身的机制实现,则减免了很大的开发工作量。
以下是另外的三种方案。
Kubernetes Job
经过调查发现,虽然containers
不能依次运行,但是initContainers
可以。 它是在containers
运行前,执行的初始化操作,依次结束运行并且无异常后,正式的containers
才会运行。 利用这一点,可以实现多个任务的依次执行,把前面的任务写到initContainers
、最后一个任务写到containers
即可。
以下为三个Containter
依次执行的样例。
---
apiVersion: batch/v1
kind: Job
metadata:
name: sequential-jobs
spec:
backoffLimit: 0
template:
spec:
restartPolicy: Never
initContainers:
- name: job-1
image: alpine:3.11
command:
- 'sh'
- '-c'
- >
for i in 1 2 3;
do
echo "job-1 date
";
sleep 1s;
done;
echo code > /srv/input/code
volumeMounts:
- mountPath: /srv/input/
name: input
- name: job-2
image: alpine:3.11
command:
- 'sh'
- '-c'
- >
for i in 1 2 3;
do
echo "job-2 date
";
sleep 1s;
done;
cat /srv/input/code &&
echo artifact > /srv/input/output/artifact
resources:
requests:
cpu: 3
volumeMounts:
- mountPath: /srv/input/
name: input
- mountPath: /srv/input/output/
name: output
containers:
- name: job-3
image: alpine:3.11
command:
- 'sh'
- '-c'
- >
echo "job-1 and job-2 completed";
sleep 3s;
cat /srv/output/artifact
volumeMounts:
- mountPath: /srv/output/
name: output
volumes:
- name: input
emptyDir: {}
- name: output
emptyDir: {}
securityContext:
runAsUser: 2000
runAsGroup: 2000
fsGroup: 2000
backoffLimit
: 0,这句指定这个Job不要失败重启。volumes
这部分,使用了input
和output
两个emptyDir
,作为输入输出。securityContext
可以在镜像默认用户不确定的情况下,使用指定UID
进行Volume
操作,避免对root
的依赖。
运行完毕后,日志如下:
$ kubectl logs sequential-jobs-r4725 job-1
job-1 Tue Jul 28 07:50:10 UTC 2020
job-1 Tue Jul 28 07:50:11 UTC 2020
job-1 Tue Jul 28 07:50:12 UTC 2020
$ kubectl logs sequential-jobs-r4725 job-2
job-2 Tue Jul 28 07:50:13 UTC 2020
job-2 Tue Jul 28 07:50:14 UTC 2020
job-2 Tue Jul 28 07:50:15 UTC 2020
code
$ kubectl logs sequential-jobs-r4725 job-3
job-1 and job-2 completed
artifact
Volcano
Volcano
前身是kube-batch
,声称在调度和管理方面,对原生Job进行了优化。 但是在核心逻辑上,还是一样的,不能支持指定Container
顺序执行。
状态转移图如下:
在实际测试中,暂时没有发现在当前业务场景下,比原生Job有什么优势。 以下是实测配置。
---
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: volcano-sequential-jobs
spec:
minAvailable: 1
schedulerName: volcano
queue: default
tasks:
- replicas: 1
name: "task-1"
template:
spec:
restartPolicy: Never
initContainers:
- name: job-1
image: alpine:3.11
command:
- 'sh'
- '-c'
- >
for i in 1 2 3;
do
echo "job-1 date
";
sleep 1s;
done;
echo code > /srv/input/code
volumeMounts:
- mountPath: /srv/input/
name: input
- name: job-2
image: alpine:3.11
command:
- 'sh'
- '-c'
- >
for i in 1 2 3;
do
echo "job-2 date
";
sleep 1s;
done;
cat /srv/input/code &&
echo artifact > /srv/input/output/artifact
resources:
requests:
cpu: 3
volumeMounts:
- mountPath: /srv/input/
name: input
- mountPath: /srv/input/output/
name: output
containers:
- name: job-done
image: alpine:3.11
command:
- 'sh'
- '-c'
- >
echo "job-1 and job-2 completed";
sleep 3s;
cat /srv/output/artifact
volumeMounts:
- mountPath: /srv/output/
name: output
volumes:
- name: input
emptyDir: {}
- name: output
emptyDir: {}
securityContext:
runAsUser: 2000
runAsGroup: 2000
fsGroup: 2000
上面与原生相比,虽然多了tasks这一层概念,但是在功能上并无帮助。
运行完毕后,日志如下:
$ kubectl logs volcano-sequential-jobs-task-1-0 job-1
job-1 Tue Jul 28 07:53:17 UTC 2020
job-1 Tue Jul 28 07:53:18 UTC 2020
job-1 Tue Jul 28 07:53:20 UTC 2020
$ kubectl logs volcano-sequential-jobs-task-1-0 job-2
job-2 Tue Jul 28 07:53:21 UTC 2020
job-2 Tue Jul 28 07:53:22 UTC 2020
job-2 Tue Jul 28 07:53:23 UTC 2020
code
$ kubectl logs volcano-sequential-jobs-task-1-0 job-3
job-1 and job-2 completed
artifact
另外,Volcano
的文档缺失严重,与kube-batch
也不兼容。 目前看来有很多不清楚的问题。
argo
argo
是更合适按顺序、依赖关系执行的。 但是经评估,它有一个重大缺陷,不适合当前场景。
argo
的每个Task
都是独立的Pod
,不同Pod
未必在同一台机器上。 而Volume
则必须使用NFS
之类的网络存储位置,性能不符合某些需要密集本地IO
的场景。
总结
argo
是形式上最合适的,可以避免使用initContainers
这种邪道。 但是独立Pod
的问题导致它不适合这个场景。
目前看来,原生的Job
最合适,选用Volcano
还需要更深入的了解。
原文来自:https://note.qidong.name/2020/08/k8s-sequential-container-in-pod/
作者:匿蟒
本文链接:http://www.yunweipai.com/37123.html