docker-compose如何解析command字符串?案例与源码问询
问题背景与现象
我执行了以下命令:
docker-compose -p foo -f - up <<YAML version: "3.8" services: main: image: alpine command: echo x && y YAML
预期结果
[+] Running 1/0 ⠿ Container foo-main-1 Created 0.0s Attaching to foo-main-1 foo-main-1 | x && y foo-main-1 exited with code 0
实际结果
[+] Running 1/0 ⠿ Container foo-main-1 Created 0.0s Attaching to foo-main-1 foo-main-1 | x foo-main-1 exited with code 0
我了解Dockerfile的CMD支持exec格式与shell格式,原本预期docker-compose.yml的command配置会和Dockerfile CMD表现一致,但实际docker-compose似乎采用特殊方式处理command字符串。
command | 输出 |
|---|---|
| echo x y z | x y z |
| echo x && y | x |
| echo x | y | x |
| echo x; y | x |
技术问题
- docker-compose是否仅通过正则表达式移除;、&&、|后的内容?
- 若并非如此,docker-compose是如何处理command字符串的?
同时希望能提供解析command字符串的源码参考(仓库地址:https://github.com/docker/compose)。
环境信息
λ docker -v Docker version 20.10.22, build 3a2c30b λ docker-compose -v Docker Compose version v2.15.1
问题解答
不是,docker-compose并非通过正则表达式移除
;、&&、|后的内容。Docker Compose处理
command字符串的逻辑如下:- 当
command以字符串形式配置时,Compose会先通过YAML解析拿到完整的命令字符串,再根据镜像的默认shell(通常是/bin/sh -c)将其包装为shell执行命令,即最终传递给容器的是["sh", "-c", "你配置的command字符串"],这和Dockerfile的CMD shell格式逻辑一致。 - 你观察到的现象本质是shell解析命令的结果:比如
command: echo x && y会被shell解析为两个命令,先执行echo x(输出x),再执行y。如果y是存在且无输出的命令,容器就会输出x后正常退出(退出码0);如果y不存在,容器会输出x后报错退出(退出码非0)。你的预期(输出x && y)是错误的,若要让echo输出完整的x && y字符串,需要用exec模式配置command:command: ["echo", "x && y"],这种形式下不会启动shell,直接将参数传递给echo命令。 - 表格中其他案例的现象也能以此解释:
echo x | y被shell解析为管道命令,echo x的输出传给y,若y无输出则只看到x;echo x; y是顺序执行两个命令,同样只显示echo x的结果;只有echo x y z会被shell解析为echo接收三个参数,输出完整的x y z。
- 当
源码参考
Compose中处理command解析与转换的核心代码位于以下文件:
pkg/compose/convert.go:ConvertCommand函数负责将YAML中的字符串/列表形式的command转换为可执行的参数数组。pkg/container/parse.go:ParseCommand函数负责判断是否需要用shell包裹字符串形式的command,生成最终的执行参数。
内容的提问来源于stack exchange,提问作者Weihang Jian
相关产品推荐
相关产品推荐

