论docker中 CMD 与 ENTRYPOINT 的区别

Apr 14, 2018

CMD ENTRYPOINT 都有两种格式:数组类型, 列表类型(个人理解)

CMD ["executable","param1","param2"]           ##数组模式
CMD command param1 param2                      ##列表模式
ENTRYPOINT ["executable", "param1", "param2"]  ##数组模式 
ENTRYPOINT command param1 param2               ##列表模式

两种类型的区别是:数组类型会做为命令直接执行,作为容器中 PID=1 的主进程。而列表形式为进程号1的进程是  /bin/sh -c 的进程。

二者区别:

  •   如果同时存在ENTRYPOINT和CMD,CMD中的参数会追加到 ENTRYPOINT 的参数之后,即:ENTRYPOINT的优先级比CMD更高,而且与 dockerfile 文件中二者的编码顺序无关
  •    ENTRYPOINT出现多次,或者CMD出现多次,dockerfile 编码顺序靠后的会覆盖前面的
  •    docker run 命令的参数(如:docker run -it --rm ubuntu ps auxps aux 参数)会覆盖掉 CMD 命令的所有参数(包括如果是列表模式的时候的 /bin/sh -c参数),如果没有 dockerfile 中没有CMD则会忽略掉 run 命令中的参数(前面实例中的 ps aux
  •    dockerfile FROM 应用的时候也适用前面规则
  •    附加一条规则:ENTRYPOINT在数组模式的时候CMD的参数才有效,否则忽略。

举例

FROM ubuntu
ENTRYPOINT ["ps", "aux"]

执行 sudo docker build . -t test && sudo docker run --rm test 结果:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  2.0  0.0  25964  1212 ?        Rs   18:37   0:00 ps aux

FROM ubuntu
CMD ["ps", "aux"]

执行docker build . -t test && sudo docker run --rm test 结果:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  25964  1212 ?        Rs   18:40   0:00 ps aux

执行: docker build . -t test && sudo docker run --rm test -ef 结果

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 18:40 ?        00:00:00 ps -ef


FROM ubuntu
CMD ps aux

执行:sudo docker build . -t test && sudo docker run --rm test 结果

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   4492   644 ?        Ss   18:46   0:00 /bin/sh -c ps aux
root         5  0.0  0.0  34412  1432 ?        R    18:46   0:00 ps aux

FROM ubuntu
ENTRYPOINT ["ps"]
CMD ["aux"]

执行:docker build . -t test && sudo docker run --rm test 结果

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  25964  1212 ?        Rs   18:50   0:00 ps aux

执行:docker build . -t test && sudo docker run --rm test -ef 结果

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 18:52 ?        00:00:00 ps -ef

如果 ENTRYPOINT 使用列表模式拼接CMD格式例如 dockerfile 如下:

FROM ubuntu
ENTRYPOINT "ps" "aux"
CMD echo "hello"

执行 sudo docker build . -t test && sudo docker run --rm test 结果是:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   4492   644 ?        Ss   18:23   0:00 /bin/sh -c "ps" "aux" /bin/sh -c echo "hello"
root         5  0.0  0.0  34412  1432 ?        R    18:23   0:00 ps aux

这时 CMD 的参数会被忽略。如果执行 sudo docker build . -t test && sudo docker run --rm test hello 结果是

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   4492   644 ?        Ss   18:26   0:00 /bin/sh -c "ps" "aux" hello
root         5  0.0  0.0  34412  1428 ?        R    18:26   0:00 ps aux

这时 run 中的参数也会被忽略(注意/bin/sh -c未出现) 总结就是:

  •    只有在 ENTRYPOINT ["executable", "param1", "param2"] 数组模式的时候CMD的参数和docker run后的参数才有效。

另外 数组模式的好处是到容器被关机的时候(docker stop …), 进程 PID=1 会获取到中断信号,应用可以做优雅的关机操作,而列表模式应用进程 PID!=1,无法获取到中断信号

最后建议 如果作为基础容器被其他容器 FROM 建议使用 CMD ,而不使用 ENTRYPOINT。 如果使用 ENTRYPOINT 则应该使用 数组模式,并使用CMD的数组模式。