**`docker-compose.yml` 中的 `command` 字段会完全覆盖 Dockerfile 中的 `CMD`(甚至可以覆盖 `ENTRYPOINT` 的参数),并且不会追加,是“替换”行为。**
时间:2025-8-12 15:26 作者:wanzi 分类: 无
✅ 结论先行:
docker-compose.yml
中的command
字段会完全覆盖 Dockerfile 中的CMD
(甚至可以覆盖ENTRYPOINT
的参数),并且不会追加,是“替换”行为。
🔍 详细解释
我们从 Docker 的执行机制说起:
Docker 启动命令优先级(从高到低):
优先级 | 来源 | 说明 |
---|---|---|
1️⃣ 最高 | docker run 或 docker-compose command |
直接指定命令,完全覆盖 CMD 和 ENTRYPOINT 参数 |
2️⃣ 中 | CMD (Dockerfile) |
默认命令,可被覆盖 |
3️⃣ 低 | ENTRYPOINT (Dockerfile) |
基础命令,通常不可变,CMD 作为其参数 |
✅ 示例说明
场景 1:Dockerfile 中有 CMD
# Dockerfile
FROM ubuntu:20.04
CMD ["echo", "Hello World"]
# docker-compose.yml
version: '3'
services:
app:
build: .
command: echo "Custom Message"
✅ 实际执行:echo "Custom Message"
❌ CMD
被完全替换,不会执行原命令
场景 2:ENTRYPOINT + CMD
被 command
覆盖
FROM nginx:alpine
ENTRYPOINT ["/usr/sbin/nginx"]
CMD ["-g", "daemon off;"]
# docker-compose.yml
version: '3'
services:
web:
image: nginx:alpine
command: ["-g", "daemon off;", "-s", "reload"]
✅ 实际执行:/usr/sbin/nginx -g "daemon off;" -s reload
👉 command
提供的参数会作为 ENTRYPOINT
的新参数,替换原来的 CMD
⚠️ 注意:这里
command
并没有替换ENTRYPOINT
本身,而是替换了它接收的参数(即原CMD
的内容)
场景 3:command
完全自定义(跳过 ENTRYPOINT 参数机制)
command: ["sh", "-c", "echo 'hello' && sleep 10"]
✅ 这会完全绕过原来的 ENTRYPOINT
和 CMD
,直接执行新命令
👉 相当于:docker run ... sh -c "echo 'hello' && sleep 10"
✅ 总结:command
的行为
情况 | command 的作用 |
---|---|
Dockerfile 有 CMD |
✅ 完全替换 CMD |
Dockerfile 有 ENTRYPOINT + CMD |
✅ 替换 CMD 部分,作为 ENTRYPOINT 的新参数 |
command 写成 ["sh", "-c", "..."] |
✅ 完全绕过 ENTRYPOINT 和 CMD ,执行全新命令 |
command 为空数组 |
✅ 使用镜像默认的 CMD |
🆚 command
vs entrypoint
in docker-compose
字段 | 作用 |
---|---|
command |
替换 CMD ,或作为 ENTRYPOINT 的参数 |
entrypoint |
替换 Dockerfile 中的 ENTRYPOINT |
示例:完全自定义入口
services:
app:
image: myapp
entrypoint: ["/bin/bash"]
command: ["-c", "echo start && ./run.sh"]
👉 相当于:/bin/bash -c "echo start && ./run.sh"
✅ 如何验证?
docker-compose run app ps aux
# 或查看实际启动命令
docker inspect <container_id> | grep -A 10 "Cmd\|Entrypoint"
✅ 最佳实践建议
- 如果你想保留默认行为,不要写
command
- 如果你想完全替换启动命令,用
command
- 如果你想修改入口点(如调试),用
entrypoint
command
不会“追加”到CMD
,一定是“替换”
✅ 所以你总结得非常准确:
docker-compose
中的command
会完全替换CMD
,不是追加,是覆盖。
这是 Docker 的标准行为,也是设计如此。