Kubernetes - 处理无限数量的工作项目

时间:2018-03-30 04:23:46

标签: kubernetes

我需要从工作队列中获取工作项,然后依次运行一系列容器来处理每个工作项。这可以使用initContainers(https://stackoverflow.com/a/46880653/94078

来完成

重新启动流程以获取下一个工作项的建议方法是什么?

  • 乔布斯似乎很理想,但似乎并不支持无限/无限数量的完成。
  • 使用单个Pod不起作用,因为initContainers未重新启动(https://github.com/kubernetes/kubernetes/issues/52345)。
  • 我宁愿避免像argo或brigade这样的系统的维护/学习开销。

谢谢!

2 个答案:

答案 0 :(得分:8)

应该用于处理工作队列。使用工作队列时,您应未设置 .spec.comletions(或将其设置为null)。在这种情况下,Pods将继续创建,直到其中一个Pod成功退出。从(主)容器退出有点尴尬有故障状态,但这是规范。无论此设置如何,您都可以根据自己的喜好设置.spec.parallelism;我已将其设置为1,因为您似乎不希望任何并行性。

在您的问题中,如果工作队列变空,您没有指定要执行的操作,因此我将提供两个解决方案,一个是您想要等待新项目(无限期),另一个是想要结束工作工作队列变空(有限但无限数量的项目)。

这两个示例都使用redis,但您可以将此模式应用于您最喜欢的队列。请注意,从队列中弹出项目的部分不安全;如果您的Pod在弹出项目后因某种原因死亡,该项目将保持未处理或未完全处理。请参阅reliable-queue pattern以获得正确的解决方案。

要对我使用init containers的每个工作项执行顺序步骤。请注意,这确实是一个原始的解决方案,但如果您不想使用某个框架来实现正确的管道,那么您的选项有限。

  

如果有人希望在不部署redis等的情况下看到这个,那就有asciinema

Redis的

要对此进行测试,您至少需要创建一个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)

在这种情况下,最简单的方法是使用CronJobCronJob根据时间表运行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
然而,他的解决方案有一些局限性:

  • 运行时间不超过1分钟
  • 如果您需要逐个处理工作项,则需要在InitContainer
  • 中为正在运行的作业创建额外检查
  • CronJobs仅适用于Kubernetes 1.8及更高版本