entrypoint决定容器真正执行的命令,比cmd更固定;推荐使用exec形式(json数组),可透传参数、支持信号、避免shell注入,shell形式则无法传递参数且pid1为shell。

ENTRYPOINT 有两种写法:Shell 形式和 Exec 形式
Shell 形式:ENTRYPOINT command param1 param2
这种写法会把整个命令塞进 /bin/sh -c 中执行,**无法传递 CMD 或 docker run 的参数**,适合简单固定命令(比如只启动一个服务且不接受额外参数)。
Exec 形式(推荐):ENTRYPOINT ["executable", "param1", "param2"]
这是 JSON 数组写法,不会经过 shell 解析,能正确接收后续参数,也更安全(避免 shell 注入),是生产环境的标准写法。
- 错误示例:
ENTRYPOINT python app.py→ 启动后无法传参,比如docker run myimg --help会被忽略 - 正确示例:
ENTRYPOINT ["python", "app.py"]→docker run myimg --help实际执行python app.py --help
ENTRYPOINT 和 CMD 配合使用才灵活
当 ENTRYPOINT 是 exec 形式时,CMD 的内容会作为参数追加到 ENTRYPOINT 命令末尾,相当于默认参数。
-
ENTRYPOINT ["nginx", "-g"]CMD ["daemon off;"]
→ 容器启动执行:nginx -g "daemon off;" - 运行时指定新 CMD:
docker run -it myimg "-c /etc/nginx/nginx.conf"
→ 实际执行:nginx -g "-c /etc/nginx/nginx.conf"(覆盖了原 CMD)
注意:CMD 必须是 exec 形式(数组),否则与 ENTRYPOINT 拼接时会出错;如果只用 ENTRYPOINT 不写 CMD,就完全没默认参数,必须靠 docker run 显式传参。
常见陷阱和绕过方式
有时候你只想临时调试、替换入口命令(比如进容器 bash),但 ENTRYPOINT 锁死了怎么办?
- 加
--entrypoint覆盖:docker run --entrypoint /bin/bash myimg - 用
docker run --rm -it --entrypoint sh myimg -c "ls -l"快速执行任意命令 - 别在 ENTRYPOINT 里写
exec "$@"除非你真需要透传——这通常是为支持自定义命令设计的“包装脚本”场景
例如写一个通用启动脚本 entrypoint.sh:
#!/bin/sh
set -e
if [ "${1#-}" != "${1}" ] || [ -z "$1" ]; then
exec /usr/local/bin/myapp "$@"
else
exec "$@"
fi
再在 Dockerfile 中:COPY entrypoint.sh /entrypoint.sh && chmod +x /entrypoint.shENTRYPOINT ["/entrypoint.sh"]
这样既保留默认行为,又支持 docker run myimg /bin/sh 进入交互 shell。
什么时候该用 ENTRYPOINT,什么时候用 CMD?
原则很明确:镜像是为运行某个特定程序而构建的,就用 ENTRYPOINT;只是提供默认命令建议,允许用户轻松覆盖,就用 CMD。
- 数据库镜像(如 postgres):用 ENTRYPOINT 启动
postgres主进程,因为它是核心职责 - 基础系统镜像(如 ubuntu):只用 CMD 设为
["/bin/bash"],因为用户预期是进 shell,不是跑固定服务 - 工具类镜像(如 curl、jq):ENTRYPOINT 设成工具本身,CMD 设成常用目标 URL 或参数,方便直接
docker run curlimages/curl https://example.com











