我需要从工作队列中获取工作项,然后依次运行一系列容器来处理每个工作项。这可以使用initContainers(https://stackoverflow.com/a/46880653/94078)
来完成重新启动流程以获取下一个工作项的建议方法是什么?
谢谢!
答案 0 :(得分:8)
应该用于处理工作队列。使用工作队列时,您应未设置 .spec.comletions
(或将其设置为null
)。在这种情况下,Pods将继续创建,直到其中一个Pod成功退出。从(主)容器退出有点尴尬有故障状态,但这是规范。无论此设置如何,您都可以根据自己的喜好设置.spec.parallelism
;我已将其设置为1
,因为您似乎不希望任何并行性。
在您的问题中,如果工作队列变空,您没有指定要执行的操作,因此我将提供两个解决方案,一个是您想要等待新项目(无限期),另一个是想要结束工作工作队列变空(有限但无限数量的项目)。
这两个示例都使用redis,但您可以将此模式应用于您最喜欢的队列。请注意,从队列中弹出项目的部分不安全;如果您的Pod在弹出项目后因某种原因死亡,该项目将保持未处理或未完全处理。请参阅reliable-queue pattern以获得正确的解决方案。
要对我使用init containers的每个工作项执行顺序步骤。请注意,这确实是一个原始的解决方案,但如果您不想使用某个框架来实现正确的管道,那么您的选项有限。
如果有人希望在不部署redis等的情况下看到这个,那就有asciinema。
要对此进行测试,您至少需要创建一个redis Pod和一个服务。我正在使用fine parallel processing work queue中的示例。您可以使用以下命令进行部署:
kubectl apply -f https://rawgit.com/kubernetes/website/master/docs/tasks/job/fine-parallel-processing-work-queue/redis-pod.yaml
kubectl apply -f https://rawgit.com/kubernetes/website/master/docs/tasks/job/fine-parallel-processing-work-queue/redis-service.yaml
此解决方案的其余部分要求您在与作业相同的命名空间中具有服务名称redis
,并且不需要身份验证和名为redis-master
的Pod。
要在工作队列中插入一些项目,请使用此命令(为此,您需要使用bash):
echo -ne "rpush job "{1..10}"\n" | kubectl exec -it redis-master -- redis-cli
如果队列为空,则此版本等待,因此永远不会完成。
apiVersion: batch/v1
kind: Job
metadata:
name: primitive-pipeline-infinite
spec:
parallelism: 1
completions: null
template:
metadata:
name: primitive-pipeline-infinite
spec:
volumes: [{name: shared, emptyDir: {}}]
initContainers:
- name: pop-from-queue-unsafe
image: redis
command: ["sh","-c","redis-cli -h redis blpop job 0 >/shared/item.txt"]
volumeMounts: [{name: shared, mountPath: /shared}]
- name: step-1
image: busybox
command: ["sh","-c","echo step-1 working on `cat /shared/item.txt` ...; sleep 5"]
volumeMounts: [{name: shared, mountPath: /shared}]
- name: step-2
image: busybox
command: ["sh","-c","echo step-2 working on `cat /shared/item.txt` ...; sleep 5"]
volumeMounts: [{name: shared, mountPath: /shared}]
- name: step-3
image: busybox
command: ["sh","-c","echo step-3 working on `cat /shared/item.txt` ...; sleep 5"]
volumeMounts: [{name: shared, mountPath: /shared}]
containers:
- name: done
image: busybox
command: ["sh","-c","echo all done with `cat /shared/item.txt`; sleep 1; exit 1"]
volumeMounts: [{name: shared, mountPath: /shared}]
restartPolicy: Never
如果队列为空,此版本将停止作业。注意pop init容器检查队列是否为空并且主容器的所有后续init容器和如果确实为空则立即退出的技巧 - 这是向Kubernetes发出Job是已完成,无需为其创建新的Pod。
apiVersion: batch/v1
kind: Job
metadata:
name: primitive-pipeline-finite
spec:
parallelism: 1
completions: null
template:
metadata:
name: primitive-pipeline-finite
spec:
volumes: [{name: shared, emptyDir: {}}]
initContainers:
- name: pop-from-queue-unsafe
image: redis
command: ["sh","-c","redis-cli -h redis lpop job >/shared/item.txt; grep -q . /shared/item.txt || :>/shared/done.txt"]
volumeMounts: [{name: shared, mountPath: /shared}]
- name: step-1
image: busybox
command: ["sh","-c","[ -f /shared/done.txt ] && exit 0; echo step-1 working on `cat /shared/item.txt` ...; sleep 5"]
volumeMounts: [{name: shared, mountPath: /shared}]
- name: step-2
image: busybox
command: ["sh","-c","[ -f /shared/done.txt ] && exit 0; echo step-2 working on `cat /shared/item.txt` ...; sleep 5"]
volumeMounts: [{name: shared, mountPath: /shared}]
- name: step-3
image: busybox
command: ["sh","-c","[ -f /shared/done.txt ] && exit 0; echo step-3 working on `cat /shared/item.txt` ...; sleep 5"]
volumeMounts: [{name: shared, mountPath: /shared}]
containers:
- name: done
image: busybox
command: ["sh","-c","[ -f /shared/done.txt ] && exit 0; echo all done with `cat /shared/item.txt`; sleep 1; exit 1"]
volumeMounts: [{name: shared, mountPath: /shared}]
restartPolicy: Never
答案 1 :(得分:1)
在这种情况下,最简单的方法是使用CronJob
。 CronJob
根据时间表运行Jobs
。有关详细信息,请浏览documentation。
以下是一个示例(我从here获取并修改了它)
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: sequential-jobs
spec:
schedule: "*/1 * * * *" #Here is the schedule in Linux-cron format
jobTemplate:
spec:
template:
metadata:
name: sequential-job
spec:
initContainers:
- name: job-1
image: busybox
command: ['sh', '-c', 'for i in 1 2 3; do echo "job-1 `date`" && sleep 5s; done;']
- name: job-2
image: busybox
command: ['sh', '-c', 'for i in 1 2 3; do echo "job-2 `date`" && sleep 5s; done;']
containers:
- name: job-done
image: busybox
command: ['sh', '-c', 'echo "job-1 and job-2 completed"']
restartPolicy: Never
然而,他的解决方案有一些局限性:
InitContainer