在Dockerfile中CMD与ENTRYPOINT功能类似,但是又有不同。这篇文档就把这个说明白

在Docker中,CMD 和 ENTRYPOINT 都是用于指定容器启动时执行的命令。这个命令可以使用exec

CMD

  • CMD 指令用于为容器提供默认的命令和参数。
  • 如果 docker run 命令后面跟了其他命令,CMD 指定的命令会被忽略。
  • 如果 Dockerfile 中存在多个 CMD 指令,只有最后一个会被执行。
  • CMD 可以被 docker run 命令行中的参数所覆盖。

Dockerfile中CMD与ENTRYPOINT_Docker


ENTRYPOINT

  • ENTRYPOINT 指令配置容器启动时的可执行文件。
  • ENTRYPOINT 的目的与 CMD 类似,但 ENTRYPOINT 启动的程序不会被 docker run 命令行参数所指定的指令所覆盖,而 docker run 命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
  • 如果 Dockerfile 中存在多个 ENTRYPOINT 指令,只有最后一个会被执行。
  • 如果你想让 docker run 后面的参数被当做参数传递给 ENTRYPOINT,你可以使用 ENTRYPOINT ["executable", "param1", "param2"] 的exec形式。

Dockerfile中CMD与ENTRYPOINT_Dockerfile_02

Dockerfile中CMD与ENTRYPOINT_Docker_03


从逻辑上讲,ENTRYPOINT在Dockerfile中应该定义得更早,因为它定义了容器的主要运行行为。而CMD则可以作为这个行为的默认参数或在没有ENTRYPOINT时的替代命令。

但是,在Dockerfile的实际编写过程中,ENTRYPOINTCMD的先后顺序并不会直接影响它们的执行逻辑。Dockerfile中的指令是按照它们出现的顺序从上到下执行的,但CMDENTRYPOINT的执行逻辑并不是基于这种顺序的。

重要的是要理解这两个指令的用途和它们如何一起工作来定义容器的启动行为。通常,会首先设置ENTRYPOINT来定义容器的主程序或脚本,然后使用CMD来提供默认参数或在没有ENTRYPOINT时的默认命令。


关于命令数组exec形式

在Docker的CMDENTRYPOINT指令中,使用数组(通常被称为exec形式)而不是shell形式(即直接写命令)有几个重要的原因:

  1. 避免shell干扰
    当使用shell形式(例如CMD echo "Hello, World!")时,Docker实际上会在容器内部运行一个shell来解释这个命令。这意味着任何shell特定的语法或特性都可能影响你的命令。使用exec形式(例如CMD ["echo", "Hello, World!"])则直接运行指定的可执行文件,而不涉及任何shell解释。
  2. 信号传递
    当使用exec形式时,Docker可以正确地将Unix信号(如SIGTERM、SIGINT等)传递给容器内的主进程。然而,当使用shell形式时,信号可能会被shell捕获,而不是传递给你的主进程。这可能导致容器在接收到信号时无法正确关闭。
  3. 性能
    使用exec形式可以减少不必要的进程创建。当你使用shell形式时,Docker会创建一个shell进程来运行你的命令,这会增加一些额外的开销。使用exec形式则直接运行你的主进程,无需额外的shell进程。
  4. 参数传递
    当你想将docker run命令中的参数传递给容器内的程序时,使用exec形式会更容易。这是因为这些参数会作为容器内程序的参数直接传递,而不是作为shell命令的参数。
  5. 可读性
    虽然这在某些情况下可能因人而异,但使用exec形式通常会使Dockerfile更具可读性。数组形式的命令明确地展示了哪些是可执行文件,哪些是参数,这对于理解容器如何运行很有帮助。
  6. 跨平台兼容性
    由于Docker可以运行在多种操作系统上,使用shell形式可能会导致某些命令在某些平台上无法正常工作。使用exec形式可以避免这种情况,因为直接指定了可执行文件和参数,而不是依赖于shell来解释命令。

综上所述,虽然使用shell形式在某些情况下可能更简洁或方便,但在大多数情况下,使用exec形式(即数组形式)是更好的选择。