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

eug*_*eug 9 kubernetes

我需要从工作队列中获取工作项,然后依次运行一系列容器来处理每个工作项.这可以使用initContainers完成(/sf/answers/3281645741/)

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

谢谢!

Jan*_*art 11

乔布斯应该被用于与工作队列的工作.当使用工作队列,你应该不设置.spec.comletions(或者将其设置为null).在这种情况下,Pods将继续创建,直到其中一个Pod成功退出.从(主)容器退出有点尴尬有故障状态,但这是规范..spec.parallelism无论此设置如何,您都可以根据自己的喜好进行设置; 我把它设置1为看起来你不想要任何并行性.

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

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

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

有一个asciinema,如果有人希望在没有部署redis等的情况下看到这个.

Redis的

要测试它,您至少需要创建一个redis Pod和一个服务.我正在使用来自精细并行处理工作队列的示例.您可以部署它:

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
Run Code Online (Sandbox Code Playgroud)

此解决方案的其余部分要求您redis在与作业相同的命名空间中具有服务名称,并且不需要身份验证和调用Pod redis-master.

插入物品

要在工作队列中插入一些项目,请使用此命令(为此,您需要使用bash):

echo -ne "rpush job "{1..10}"\n" | kubectl exec -it redis-master -- redis-cli
Run Code Online (Sandbox Code Playgroud)

无限版

如果队列为空,则此版本等待,因此它将永远不会完成.

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
Run Code Online (Sandbox Code Playgroud)

有限版

如果队列为空,此版本将停止作业.注意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
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的回答。我在等待新项目的无限版本之后 - 这种将 restartPolicy 设置为 Never 然后使 pod 失败的方法对我来说是新的 - 但由此产生的错误状态并不是很好,因为它们会干扰监控并使其更难查看实际错误.. (2认同)
  • 是的,我不喜欢那种行为.你想要处理一分钟的物品有多少?我问的原因是,因为如果它每分钟只说10个项目你就可以设置'完成次数:1000000000`(10亿),足够大约190年(1000000000/10/60/24/365).然后,您可以从"完成"容器中成功退出. (2认同)

Art*_*aev 1

在这种情况下,最简单的方法是使用CronJob. 按照时间表CronJob运行。Jobs有关更多信息,请参阅文档

这是一个例子(我从这里获取并修改了它)

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
Run Code Online (Sandbox Code Playgroud)

然而他的解决方案有一些局限性:

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