在Dockerfile中CMD与ENTRYPOINT功能类似,但是又有不同。这篇文档就把这个说明白
在Docker中,CMD
和 ENTRYPOINT
都是用于指定容器启动时执行的命令。这个命令可以使用exec
CMD
CMD
指令用于为容器提供默认的命令和参数。- 如果
docker run
命令后面跟了其他命令,CMD
指定的命令会被忽略。 - 如果
Dockerfile
中存在多个CMD
指令,只有最后一个会被执行。 CMD
可以被docker run
命令行中的参数所覆盖。
ENTRYPOINT
ENTRYPOINT
指令配置容器启动时的可执行文件。ENTRYPOINT
的目的与CMD
类似,但ENTRYPOINT
启动的程序不会被docker run
命令行参数所指定的指令所覆盖,而docker run
命令行参数会被当作参数送给ENTRYPOINT
指令指定的程序。- 如果
Dockerfile
中存在多个ENTRYPOINT
指令,只有最后一个会被执行。 - 如果你想让
docker run
后面的参数被当做参数传递给ENTRYPOINT
,你可以使用ENTRYPOINT ["executable", "param1", "param2"]
的exec形式。
从逻辑上讲,ENTRYPOINT
在Dockerfile中应该定义得更早,因为它定义了容器的主要运行行为。而CMD
则可以作为这个行为的默认参数或在没有ENTRYPOINT
时的替代命令。
但是,在Dockerfile的实际编写过程中,ENTRYPOINT
和CMD
的先后顺序并不会直接影响它们的执行逻辑。Dockerfile中的指令是按照它们出现的顺序从上到下执行的,但CMD
和ENTRYPOINT
的执行逻辑并不是基于这种顺序的。
重要的是要理解这两个指令的用途和它们如何一起工作来定义容器的启动行为。通常,会首先设置ENTRYPOINT
来定义容器的主程序或脚本,然后使用CMD
来提供默认参数或在没有ENTRYPOINT
时的默认命令。
关于命令数组exec形式
在Docker的CMD
和ENTRYPOINT
指令中,使用数组(通常被称为exec形式)而不是shell形式(即直接写命令)有几个重要的原因:
- 避免shell干扰:
当使用shell形式(例如CMD echo "Hello, World!"
)时,Docker实际上会在容器内部运行一个shell来解释这个命令。这意味着任何shell特定的语法或特性都可能影响你的命令。使用exec形式(例如CMD ["echo", "Hello, World!"]
)则直接运行指定的可执行文件,而不涉及任何shell解释。 - 信号传递:
当使用exec形式时,Docker可以正确地将Unix信号(如SIGTERM、SIGINT等)传递给容器内的主进程。然而,当使用shell形式时,信号可能会被shell捕获,而不是传递给你的主进程。这可能导致容器在接收到信号时无法正确关闭。 - 性能:
使用exec形式可以减少不必要的进程创建。当你使用shell形式时,Docker会创建一个shell进程来运行你的命令,这会增加一些额外的开销。使用exec形式则直接运行你的主进程,无需额外的shell进程。 - 参数传递:
当你想将docker run
命令中的参数传递给容器内的程序时,使用exec形式会更容易。这是因为这些参数会作为容器内程序的参数直接传递,而不是作为shell命令的参数。 - 可读性:
虽然这在某些情况下可能因人而异,但使用exec形式通常会使Dockerfile
更具可读性。数组形式的命令明确地展示了哪些是可执行文件,哪些是参数,这对于理解容器如何运行很有帮助。 - 跨平台兼容性:
由于Docker可以运行在多种操作系统上,使用shell形式可能会导致某些命令在某些平台上无法正常工作。使用exec形式可以避免这种情况,因为直接指定了可执行文件和参数,而不是依赖于shell来解释命令。
综上所述,虽然使用shell形式在某些情况下可能更简洁或方便,但在大多数情况下,使用exec形式(即数组形式)是更好的选择。