CMD 与 ENTRYPOINT 的差异

参考:Entrypoint 和 CMD in Docker

两者都会用到

在 Dockerfile 中,Entrypoint 和 CMD 都会在 docker run 的时候被用到。具体的被用的方式是:Entrypoint CMD
也就是说如果你同时指定了 Entrypoint 和 CMD,那么 Docker 就会将 Entrypoint 的内容作为主体,然后后面附加 CMD 的内容,例如这么一段:
image.png
那么当你执行 docker run test 的时候,实际上 docker 运行的进程就会是:

  1. /bin/sh -c "cat /etc/passwd"

ENTRYPOINT 有默认值

  • 不主动指定 Dockerfile 中的 Entrypoint,docker 默认就会使用 /bin/sh -c。
  • 但是 CMD 的没有默认值,也就是说如果你不主动填写 CMD,那么就没有 CMD 的值;

    CMD 可以被替换

    ENTRYPOINT 和 CMD 的差异之二:ENTRYPOINT 不会被运行时替换,也不能被运行时替换,但是 CMD 会。CMD 中的参数不一定执行。

    CMD 可以是纯参数模式

    链接:https://stackoverflow.com/questions/21553353/what-is-the-difference-between-cmd-and-entrypoint-in-a-dockerfile

    The ENTRYPOINT is the program that will be run, and the value passed to the container will be appended to it. The > ENTRYPOINT can be overridden by specifying an > --entrypoint flag, followed by the new entry point you want to use. ENTRYPOINT 是程序将要执行的命令,从 container 传入的值会添加到 ENTRYPOINT 后面。
    ENTRYPOINT 会被 --entrypoint flag 覆盖。

    sleep 10 秒的镜像

    创建一个启动时休眠 10 秒的镜像:

    1. FROM ubuntu
    2. CMD sleep 10

    build 并 启动镜像:

    1. docker build -t custom_sleep .
    2. docker run custom_sleep
    3. # sleeps for 10 seconds and exits

    休眠 N 秒的镜像

    使用 ENTRYPOINT 达到休眠 N 秒的目的:

    1. FROM ubuntu
    2. ENTRYPOINT sleep

    启动:

    1. docker run custom_sleep 20

    休眠 N 秒的镜像增加默认值

    What about a default value? Well, you guessed it right:

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

    不同参数模式

    注:此部分没看懂。

    1. CMD ["executable", "param1", "param2"]
    2. CMD command param1 param2

    那么既然有两种方式,那么肯定是有所差异的,他们之间的差异又是什么呢?首先在执行方式层面,他们就不一样,第一种 exec 模式,hi 被 docker 使用 fork-exec 的方式执行,这是推荐的方式,这样做的好处有:xxx;而第二种,会被放在 /bin/sh 中执行,好处是支持用户交互。如果从系统层面来看,通过 exec 方式运行,那么将不会关注到 Dockerfile 中执行的环境变量等,而通过 shell 方式运行的却是可以使用到 ENV 设置的环境变量;还有一个差别就是通过 exec 模型运行,那么进程在 Docker 中的 PID 就是 1,可以收到 docker 外部触发的系统信号;而通过 shell 运行的进程则收不到系统进程。
    所以这里就存在一定的问题,因为有的时候我们的应用不能简单直白得就通过一个 exec 模式直接运行在 Docker 中,可能还需要处理一些环境相关的设置或者错误处理和故障恢复之类的,但是又系统能够很好得接受和处理系统信号,为了兼顾 exec 和 shell 两种模式的优点,一个被广泛使用的最佳实践就是通过一个 entrypoint.sh 的脚本作为 ENTRYPOINT,然后再 entrypoint.sh 中运行期望中的程序以及做信号处理等事情,这样就兼顾到了程序和环境的友好。例如这一个 postgres 的 Dockerfile 就是采用这种方式,而且他的 entrypoint.sh 也不复杂,有兴趣可以看一下:postgres entrypoint.sh