出于某些目的,有时需要在 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
ttlSecondsAfterFinished: 3600
template:
spec:
activeDeadlinesSeconds: 60
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 的依赖。
- activeDeadlinesSeconds 指定了 Job 内 Pod 的超时时间。
- 这个字段同样可以给到Job。
- ttlSecondsAfterFinished 指定了在多久以后,Job会被自动删除。
运行完毕后,日志如下:
$ kubectl logs sequential-jobs-r4725 job-1job-1 Tue Jul 28 07:50:10 UTC 2020job-1 Tue Jul 28 07:50:11 UTC 2020job-1 Tue Jul 28 07:50:12 UTC 2020$ kubectl logs sequential-jobs-r4725 job-2job-2 Tue Jul 28 07:50:13 UTC 2020job-2 Tue Jul 28 07:50:14 UTC 2020job-2 Tue Jul 28 07:50:15 UTC 2020code
$ kubectl logs sequential-jobs-r4725 job-3job-1 and job-2 completed
artifact
Volcano
Volcano前身是kube-batch,声称在调度和管理方面,对原生Job进行了优化。但是在核心逻辑上,还是一样的,不能支持指定 Container 顺序执行。

状态转移图如下:
stateDiagram [] → Pending Pending → Aborted Pending → Running Aborted → Pending Running → Aborted Running → Completed Running → Terminated Completed → [ *** ] Terminated → []
在实际测试中,暂时没有发现在当前业务场景下,比原生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-1job-1 Tue Jul 28 07:53:17 UTC 2020job-1 Tue Jul 28 07:53:18 UTC 2020job-1 Tue Jul 28 07:53:20 UTC 2020$ kubectl logs volcano-sequential-jobs-task-1-0 job-2job-2 Tue Jul 28 07:53:21 UTC 2020job-2 Tue Jul 28 07:53:22 UTC 2020job-2 Tue Jul 28 07:53:23 UTC 2020code
$ kubectl logs volcano-sequential-jobs-task-1-0 job-3job-1 and job-2 completed
artifact
另外,Volcano 文档缺失严重,与 kube-batch 也不兼容。目前看来有很多不清楚的问题。
argo
argo是更合适按顺序、依赖关系执行的。但是经评估,它有一个重大缺陷,不适合当前场景。
argo的每个Task都是独立的Pod,不同Pod未必在同一台机器上。而Volume则必须使用NFS之类的网络存储位置,性能不符合某些需要密集本地IO的场景。
总结
argo 是形式上最合适的,可以避免使用 initContainers 这种邪道。但是独立 Pod 因为问题导致它不适合这个场景。
目前看来,原生的 Job 最合适。
选用Volcano还需要更深入的了解。
网友评论