CMD 容器启动命令

CMD 指令的格式和 RUN 相似,也是两种格式:

  • shell 格式:CMD <命令> ;如果使用 shell 格式的话,实际的命令会被包装为 sh -c 的形式执行。
  • exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
  • 参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。

镜像一般有一个默认命令。比如centos 的默认命令是/bin/bash 。如果使用CMD,会把CMD作为默认命令,替换原来的默认命令。

ENTRYPOINT 入口点

ENTRYPOINT 的格式也和 RUN 指令格式一样,分为 exec 格式和 shell 格式。
ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要繁琐一点,需要通过 docker run 的参数 --entrypoint 来指定。
当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时:

  1. ENTRYPOINT executeable
  2. CMD ...
  3. # 将变为
  4. ENTRYPOINT ["executeable", "<CMD>"]

有了 CMD ,为什么还要有 ENTRYPOINT

Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令是用于指定默认的容器主进程的启动命令的。
注意上面说的是”默认命令”,既然是默认命令,意味着可替换。
Example:

FROM centos
CMD curl www.baidu.com

Example会打印百度首页的html文档。
对于curl而言,如果我们想获取HTTP RESPONSE报文,可以加上-i参数,即curl www.baidu.com -i
但是Example无法追加参数。如果使用docker run Example -i启动,会报docker: Error response from deamon..... ERRO[0012] 。这是因为启动参数-i替换了整个curl www.baidu.com,而$PATH 环境变量下没有单独的-i命令。
如果使用ENTRYPOINT的话
Example2:

FROM centos
ENTRYPOINT curl www.baidu.com
$ docker run Example2
<!DOCTYPE html>
<html>......</html>

$ docker run Example2 -i
HTTP/1.1 200 OK
......(response header)

<!DOCTYPE html>
<html>......</html>

如上,Example2成功接收了-i参数。

PS:Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。