使用扩展进行并行处理

    首先,将以下作业模板下载到名为 的文件中。

    与 *pod 模板*不同,我们的 *job 模板*不是 Kubernetes API 类型。它只是 Job 对象的 yaml 表示, YAML 文件有一些占位符,在使用它之前需要填充这些占位符。$ITEM 语法对 Kubernetes 没有意义。

    在这个例子中,容器所做的唯一处理是 echo 一个字符串并睡眠一段时间。 在真实的用例中,处理将是一些重要的计算,例如渲染电影的一帧,或者处理数据库中的若干行。这时,$ITEM 参数将指定帧号或行范围。

    这个 Job 及其 Pod 模板有一个标签: jobgroup=jobexample。这个标签在系统中没有什么特别之处。 这个标签使得我们可以方便地同时操作组中的所有作业。 我们还将相同的标签放在 pod 模板上,这样我们就可以用一个命令检查这些 Job 的所有 pod。 创建作业之后,系统将添加更多的标签来区分一个 Job 的 pod 和另一个 Job 的 pod。 注意,标签键 jobgroup 对 Kubernetes 并无特殊含义。您可以选择自己的标签方案。

    下一步,将模板展开到多个文件中,每个文件对应要处理的项。

    1. # 下载 job-templ.yaml
    2. curl -L -s -O https://k8s.io/examples/application/job/job-tmpl.yaml
    3. # 创建临时目录,并且在目录中创建 job yaml 文件
    4. mkdir ./jobs
    5. for i in apple banana cherry
    6. do
    7. cat job-tmpl.yaml | sed "s/\$ITEM/$i/" > ./jobs/job-$i.yaml
    8. done

    检查是否工作正常:

    1. ls jobs/

    输出类似以下内容:

    1. job-apple.yaml
    2. job-banana.yaml
    3. job-cherry.yaml

    在这里,我们使用 sed 将字符串 $ITEM 替换为循环变量。 您可以使用任何类型的模板语言(jinja2, erb) 或编写程序来生成 Job 对象。

    1. kubectl create -f ./jobs

    输出类似以下内容:

    现在,检查这些作业:

    输出类似以下内容:

    1. NAME COMPLETIONS DURATION AGE
    2. process-item-apple 1/1 14s 20s
    3. process-item-cherry 1/1 12s 20s

    在这里,我们使用 -l 选项选择属于这组作业的所有作业。(系统中可能还有其他不相关的工作,我们不想看到。)

    使用同样的标签选择器,我们还可以检查 pods:

    1. kubectl get pods -l jobgroup=jobexample

    输出类似以下内容:

    1. NAME READY STATUS RESTARTS AGE
    2. process-item-apple-kixwv 0/1 Completed 0 4m
    3. process-item-banana-wrsf7 0/1 Completed 0 4m
    4. process-item-cherry-dnfu9 0/1 Completed 0 4m

    我们可以使用以下操作命令一次性地检查所有作业的输出:

    输出内容为:

    1. Processing item apple
    2. Processing item banana
    3. Processing item cherry

    这个稍微复杂一点的示例使用 jinja2 模板语言来生成我们的对象。 我们将使用一行 python 脚本将模板转换为文件。

    首先,粘贴 Job 对象的以下模板到一个名为 job.yaml.jinja2 的文件中:

    1. {%- set params = [{ "name": "apple", "url": "https://www.orangepippin.com/varieties/apples", },
    2. { "name": "banana", "url": "https://en.wikipedia.org/wiki/Banana", },
    3. { "name": "raspberry", "url": "https://www.raspberrypi.org/" }]
    4. %}
    5. {%- for p in params %}
    6. {%- set name = p["name"] %}
    7. {%- set url = p["url"] %}
    8. apiVersion: batch/v1
    9. metadata:
    10. name: jobexample-{{ name }}
    11. jobgroup: jobexample
    12. spec:
    13. template:
    14. metadata:
    15. name: jobexample
    16. labels:
    17. jobgroup: jobexample
    18. spec:
    19. containers:
    20. - name: c
    21. image: busybox
    22. command: ["sh", "-c", "echo Processing URL {{ url }} && sleep 5"]
    23. restartPolicy: Never
    24. ---
    25. {%- endfor %}

    上面的模板使用 python 字典列表(第 1-4 行)定义每个作业对象的参数。 然后使用 for 循环为每组参数(剩余行)生成一个作业 yaml 对象。 我们利用了多个 yaml 文档可以与 --- 分隔符连接的事实(倒数第二行)。 我们可以将输出直接传递给 kubectl 来创建对象。

    如果您还没有 jinja2 包则需要安装它: pip install --user jinja2。 现在,使用这个一行 python 程序来展开模板:

    1. alias render_template='python -c "from jinja2 import Template; import sys; print(Template(sys.stdin.read()).render());"'

    输出可以保存到一个文件,像这样:

    1. cat job.yaml.jinja2 | render_template > jobs.yaml

    或直接发送到 kubectl,如下所示:

    如果您有大量作业对象,您可能会发现:

    • 即使使用标签,管理这么多 Job 对象也很麻烦。
    • 在一次创建所有作业时,您超过了资源配额,可是您也不希望以递增方式创建 Job 并等待其完成。
    • 同时创建大量作业会使 Kubernetes apiserver、控制器或者调度器负压过大。

    在这种情况下,您可以考虑其他的作业模式