What is the difference between CMD and ENTRYPOINT in a Dockerfile?

What is the difference between CMD and ENTRYPOINT in a Dockerfile?

技术背景

在使用 Docker 构建和运行容器时,CMDENTRYPOINTDockerfile 中两个重要的指令,它们都与容器启动时执行的命令有关。最初,Docker 有默认的入口点 /bin/sh -c,但没有默认命令。随着需求的发展,为了实现更灵活的定制,引入了 ENTRYPOINT--entrypoint

实现步骤

CMD 指令

CMD 用于为容器设置默认命令和/或参数,用户可以在运行容器时轻松覆盖这些默认值。如果 Dockerfile 中有多个 CMD 指令,只有最后一个会生效。
示例:

1
2
FROM centos:8.1.1911
CMD ["echo", "Hello Docker"]

运行容器:

1
2
3
4
$ sudo docker run <image-id>
Hello Docker
$ sudo docker run <image-id> hostname # hostname 用于覆盖 CMD
244be5006f32

ENTRYPOINT 指令

ENTRYPOINT 用于定义容器启动时始终执行的命令,通常用于将容器作为可执行文件使用。除非使用 --entrypoint 标志,否则在启动容器时不能覆盖 ENTRYPOINT
示例:

1
2
FROM centos:8.1.1911
ENTRYPOINT ["echo", "Hello Docker"]

运行容器:

1
2
3
4
$ sudo docker run <image-id>
Hello Docker
$ sudo docker run <image-id> hostname # hostname 作为参数传递给 ENTRYPOINT
Hello Docker hostname

CMDENTRYPOINT 结合使用

在很多情况下,结合使用 CMDENTRYPOINT 是最佳解决方案。ENTRYPOINT 定义可执行文件,CMD 则指定默认参数。
示例:

1
2
3
FROM centos:8.1.1911
ENTRYPOINT ["echo", "Hello"]
CMD ["Docker"]

运行容器:

1
2
3
4
$ sudo docker run <image-id>
Hello Docker
$ sudo docker run <image-id> Ben
Hello Ben

核心代码

以下是几个不同使用场景的 Dockerfile 示例:

仅使用 CMD

1
2
FROM ubuntu
CMD ["sleep", "5"]

仅使用 ENTRYPOINT

1
2
FROM ubuntu
ENTRYPOINT ["sleep"]

ENTRYPOINTCMD 结合使用

1
2
3
FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["10"]

最佳实践

  • 当需要默认命令且用户可轻松覆盖时:使用 CMD。例如,创建一个包含各种工具的通用镜像,用户可以根据需要执行不同的命令。
  • 当将容器作为可执行文件使用时:使用 ENTRYPOINT。例如,创建一个专门用于执行 ping 命令的镜像。
  • 结合使用 CMDENTRYPOINT:让 ENTRYPOINT 定义主要命令,CMD 提供默认参数。这样可以在保持主要功能的同时,允许用户灵活调整参数。

常见问题

1. 不指定 ENTRYPOINTCMD 会怎样?

如果不指定 ENTRYPOINTCMD,Docker 将使用 /bin/sh -c 作为默认入口点,并在运行容器时使用用户传递的命令行参数(如果定义了 CMD,则使用 CMD 的值)。

2. 如何覆盖 ENTRYPOINTCMD

  • 覆盖 CMD:在运行容器时提供额外的参数,例如 docker run my-image foo bar 会将 CMD 覆盖为 ["foo", "bar"]
  • 覆盖 ENTRYPOINT:使用 --entrypoint 标志,例如 docker run my-image --entrypoint foo 会将 ENTRYPOINT 覆盖为 foo

3. CMDENTRYPOINT 采用不同格式(shell 形式和 exec/JSON 形式)有什么区别?

  • shell 形式:ENTRYPOINT "mycommand arg1" 会被转换为 ENTRYPOINT ["/bin/sh", "-c", "\"mycommand arg1\""]
  • exec/JSON 形式:ENTRYPOINT ["mycommand", "arg1"] 保持不变。建议使用 exec/JSON 形式,以避免信号处理和其他边缘情况的问题。

What is the difference between CMD and ENTRYPOINT in a Dockerfile?
https://119291.xyz/posts/2025-05-12.difference-between-cmd-and-entrypoint-in-dockerfile/
作者
ww
发布于
2025年5月12日
许可协议