AWS Batch 是如何向 Docker 容器传递参数

AWS Batch 提供了简单有效的方式来运行 Docker 镜像,在单纯执行一个计算任务时比 ECS 使用起来要方便许多。AWS Batch 在提交任务时可以执行 command, environment 和 parameters, 那么它将如何传递那些参数给 Docker 容器呢?


首先看一下提交任务的脚本
1aws batch submit-job \
2  --job-name test-job \
3  --job-queue test-job-queue \
4  --job-definition test-job-definition \
5  --container-overrides='command=echo,hello,environment=[{name=JAVA_OPTS,value=-Xmx4G}]'

注:aws cli 命令参数中有 - 时需要用  --parameters='--name=Spring' 等号的格式

我们将用上面的脚本提交一个任务,然后用 docker inspect <container-id> 观察 Docker 容器收到了什么参数

也没什么意外的,inspect 容器后我们看到
 1    "Config": {
 2        .......
 3        "Env": [
 4            ......
 5            "JAVA_OPTS=-Xmx4G",
 6        ],
 7        "Cmd": [
 8            "echo",
 9            "hello"
10        ],

这个 Cmd 将与我们定义的 ENTRYPOINT 构成完整的执行入口,也可以从容器的 inspect 中看到
1    "Path": "/bin/sh",
2    "Args": [
3        "-c",
4        "java $JAVA_OPTS -jar /app.jar $0 $@",
5        "echo",
6        "hello"
7    ],

基于我们在 Dockerfile 中是下面那么定义的 ENTRYPOINT
ENTRYPOINT java $JAVA_OPTS -jar /app.jar $0 $@
很明显,虽然 AWS Batch submitJob 有一个  --parameters 那样的参数(后面会讲到),但实际要向应用传递参数的办法还是必须依赖于 Job definition 的 Environment 中的 Command

或者是提交任务时定义在  --container-overrides='command=param1,param2  进 Job definition 中的 Command 进行覆盖。

那么提交任务的 --parameters 是什么呢?它其实与 Docker 容器本身没有关系,只是用来替换 Job definition 中的占位符,所以 --parameters 后的参数是一个 map。

关于 --parameters  的用法应该看官方的这两篇文章: Using Parameter Substitution  和  AWS Batch Parameters。 大致介绍的是在 command 中使用  Ref::codec 作为占位符,然后传参的时候用
"parameters": {"codec": "mp4"}
用下面的脚本提交任务后
1aws batch submit-job \
2  --job-name test-job \
3  --job-queue test-queue \
4  --job-definition test-definition \
5  --parameters='app_name=default_app,is_debug=false' \
6  --container-overrides='command=[Ref::app_name,debug=Ref::is_debug],environment=[{name=JAVA_OPTS,value=-Xmx4G}]'

docker inspect <container-id> 看到片断
 1    "Path": "/bin/sh",
 2    "Args": [
 3        "-c",
 4        "java $JAVA_OPTS -jar /app.jar $0 $@",
 5        "default_app",
 6        "debug=Ref::is_debug"
 7    ],
 8    .......
 9
10        "Cmd": [
11            "default_app",
12            "debug=Ref::is_debug"
13        ],

从上面看到 Ref::app_name 被替换成了 default_app, 而 debug=Ref::is_debug 未被替换,所以参数的替换必须是 command 中的一个完整参数,而不能为局部。

都不奏效,把 command 部分移到 Job 定义中也没有用。不过初步来看,有 command 来向 ENTRYPOINT 传递参数就足够了。

或是在 Job Definition 中预定好  Command 为 --name= Ref::app_name debug=Ref::is_debug

注意 --name= Ref::app_name 等号后的空格会把 --name= 和 Ref::app_name 分割成两个独立的参数,--parameters 只针对一个完整参数的替换。

然后只覆盖 parameters
1aws batch submit-job \
2  --job-name yanbin-test-job \
3  --job-queue yanbin-test-queue \
4  --job-definition yanbin-test-definition \
5  --parameters='app_name=my_app_name,is_debug=false' \
6  --container-overrides='environment=[{name=JAVA_OPTS,value=-Xmx4G}]'

Docker 容器启动后 inspect 它,看到的 Cmd 替换后的结果
"Cmd": [
    "--name=",
    "my_app_name",
    "debug=Ref::is_debug"
],

总结:

AWS Batch 任务的参数还是要靠 Cmd(command) 来传递, Dockerfile 的  ENTRYPOINT 可以写成 shell 或 exec 两种格式
ENTRYPOINT java $JAVA_OPTS -jar /app.jar $0 $@
或者
ENTRYPOINT ["java", "-jar", "/app.jar"]
提交任务时通过
--container-overrides='command=param1,param2,param3'
来向 ENTRYPOINT 提供附加的参数,或是用  $0, $@ 来拾取全部的 command 作为参数。

--parameters 并不是真正干这个事的,它是启动容器之前的替换行为。

补充(2018-04-06)

更为严格的的 $0 和 $@ 使用方式是就应该用引号括起来,即最终效果是
ENTRYPOINT java $JAVA_OPTS -jar /app.jar "$0" "$@"
这参避免参数中含空格的问题,详细的解释请参见上一篇 如何向 Docker 容器传递参数 - 补充部分 永久链接 https://yanbin.blog/how-aws-batch-pass-parameters-to-docker-container/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。