CMD
指令的格式和 RUN
相似,也是两种格式:
shell
格式:CMD <命令>
exec
格式:CMD ["可执行文件", "参数1", "参数2"...] #方括号
Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD
指令就是用于指定默认的容器主进程的启动命令的。
例子: #Dockfile FROM centos:centos6 CMD echo $HOME 生成image: docker build -t dockfile:test_cmd . 测试image(不带命令): docker run dockfile:test_cmd 输出: /root
测试image(带命令):
docker run dockerfile:test echo "hi"
输出:
hi
CMD echo $HOME
在实际执行中,会将其变更为:
CMD [ "sh", "-c", "echo $HOME" ]
bash -c string If the -c option is present, then commands are read from string.
这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。
在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,ubuntu
镜像默认的 CMD
是 /bin/bash
,如果我们直接 docker run -it ubuntu
的话,会直接进入 bash
。
我们也可以在运行时指定运行别的命令,如 docker run -it ubuntu cat /etc/os-release
Docker 不是虚拟机,容器就是进程。
Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。
一些初学者将 CMD
写为:
CMD service nginx start
然后发现容器执行后就立即退出了。甚至在容器内去使用 systemctl
命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。
对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。
而使用 service nginx start
命令,则是希望 upstart 来以后台守护进程形式启动 nginx
服务。而刚才说了 CMD service nginx start
会被理解为 CMD [ "sh", "-c", "service nginx start"]
,因此主进程实际上是 sh
。
那么当 service nginx start
命令结束后,sh
也就结束了,sh
作为主进程退出了,自然就会令容器退出。
正确的做法是直接执行 nginx
可执行文件,并且要求以前台形式运行。比如:
CMD ["nginx", "-g", "daemon off;"] 方括号
nginx -g directives : set global directives out of configuration file
=====================
FROM centos:centos6 #xxx CMD ["/bin/bash"]
即使Dockerfile里面的CMD写的是/bin/bash,
但如果 docker run centos:v1 ,也是不会进入shell的
你需要docker run -it centos:v1 才行
docker run :创建一个新的容器并运行一个命令
docker create :创建一个新的容器但不启动它
docker exec :在运行的容器中执行命令