Kubernetes job并行处理,使用模版展开
在这个例子里,我们将运行多个Kubernetes Jobs,配置文件从同一个模版展开,然后创建多个jobs任务。
你需要首先了解 Jobs 的用法。
- Kubernetes中的Job和CronJob批量任务执行,https://my.oschina.net/u/2306127/blog/1784978
基本Template展开
首先,下载job的模版,文件名为 job-tmpl.yaml
application/job/job-tmpl.yaml |
---|
|
与 pod template不同,我们的 job template不是Kubernetes API 的样子。这是 yaml格式的Job object 代表,同时里面有一些占位符,在后面进行填充,这里的$ITEM
占位符语法对 Kubernetes 来说是没有意义的。
这个例子中,容器唯一的处理只是 echo
一个字符串然后 sleep 一会儿。在真实场景下,处理可能是一个耗时的计算,如渲染一个电影或处理数据库里的一部分数据。这里 $ITEM
参数可用于指示帧数或者数据的行列数。
该 Job 和它的 Pod 模版有一个label: jobgroup=jobexample
. 这对于系统没有什么特殊的意义,只是操作所有的job时作为一个组更为方便。我们将该标签放到所有的 pod template, 就可以使用单个命令检查所有与该job相关的Pods 。当job创建后,系统会加入更多的标签,以将Job的pod与其它的区分开来。注意,这个 label key jobgroup
对 Kubernetes没有特殊意义,你也可以使用自己的标签机制。
下一步,扩展template为多个文件,每一个 item 将被处理。如下所示:
- # Expand files into a temporary directory
- $ mkdir ./jobs
- $ for i in apple banana cherry
- do
- cat job-tmpl.yaml | sed "s/\$ITEM/$i/" > ./jobs/job-$i.yaml
- done
检查一下结果:
- $ ls jobs/
- job-apple.yaml
- job-banana.yaml
- job-cherry.yaml
这里,我们使用sed
替换了字符串 $ITEM,通过循环变量进行。
你可以使用任何template 语言 (jinja2, erb) 或者写一段代码来创建这个Job对象。
下一步,使用kubectl 命令创建所有的jobs对象,如下:
- $ kubectl create -f ./jobs
- job "process-item-apple" created
- job "process-item-banana" created
- job "process-item-cherry" created
检查所有的jobs状态:
- $ kubectl get jobs -l jobgroup=jobexample
- NAME DESIRED SUCCESSFUL AGE
- process-item-apple 1 1 31s
- process-item-banana 1 1 31s
- process-item-cherry 1 1 31s
使用 -l
选项来选中jobs组中的所有对象 (There might be other unrelated jobs in the system that we do not care to see.)
检查同一组标签的pods:
- $ kubectl get pods -l jobgroup=jobexample
- NAME READY STATUS RESTARTS AGE
- process-item-apple-kixwv 0/1 Completed 0 4m
- process-item-banana-wrsf7 0/1 Completed 0 4m
- process-item-cherry-dnfu9 0/1 Completed 0 4m
没有一个单个命令可以看到所有jobs的输出,通过循环来做也不难,如下:
- $ for p in $(kubectl get pods -l jobgroup=jobexample -o name)
- do
- kubectl logs $p
- done
- Processing item apple
- Processing item banana
- Processing item cherry
多个Template参数
在上面的例子中,模版使用了单一参数,而且作为label。 但是 label keys 有一定的限制,参见 what characters they can contain.
稍微复杂一点的例子,使用 jinja2 template 语言来创建我们的job objects。使用单行的python script转换template到文件。
首先, 拷贝、粘贴下列Job object到文件名为 job.yaml.jinja2
:
- {%- set params = [{ "name": "apple", "url": "http://www.orangepippin.com/apples", },
- { "name": "banana", "url": "https://en.wikipedia.org/wiki/Banana", },
- { "name": "raspberry", "url": "https://www.raspberrypi.org/" }]
- %}
- {%- for p in params %}
- {%- set name = p["name"] %}
- {%- set url = p["url"] %}
- apiVersion: batch/v1
- kind: Job
- metadata:
- name: jobexample-{{ name }}
- labels:
- jobgroup: jobexample
- spec:
- template:
- metadata:
- name: jobexample
- labels:
- jobgroup: jobexample
- spec:
- containers:
- - name: c
- image: busybox
- command: ["sh", "-c", "echo Processing URL {{ url }} && sleep 5"]
- restartPolicy: Never
- ---
- {%- endfor %}
上面的 template 定义了每一个job objects的参数,使用python dicts 的 list (lines 1-4)。然后, 循环处理参数集合,产生job的yaml object。多个 yaml 可以通过 ---
符号进行分隔,因此我们将其内容输出到一个job文件,用于kubectl 的后续操作。
你需要 jinja2 package,可以通过命令安装: pip install --user jinja2
。
现在,使用单行python 程序来扩充这个模版:
alias render_template='python -c "from jinja2 import Template; import sys; print(Template(sys.stdin.read()).render());"'
输出被保存为文件, 如下操作:
cat job.yaml.jinja2 | render_template > jobs.yaml
或者直接发送给kubectl, 如下:
cat job.yaml.jinja2 | render_template | kubectl create -f -
可选方法
如果你有大量的job objects, 很快会发现:
- 使用labels来管理大量的Job objects是很累人的事情。
- 一次性创建大量的job,有可能导致资源使用超量。
- 一次性创建超大量的job,可能导致Kubernetes apiserver, controller, 以及 scheduler超出负荷。
这种情况下,你应该考虑使用其它的 job patterns 了。