docker_practice/image/dockerfile/cmd.md

50 lines
2.9 KiB
Go
Raw Normal View History

# CMD 容器启动命令
`CMD` 指令的格式和 `RUN` 相似也是两种格式
* `shell` 格式`CMD <命令>`
* `exec` 格式`CMD ["可执行文件", "参数1", "参数2"...]`
* 参数列表格式`CMD ["参数1", "参数2"...]`在指定了 `ENTRYPOINT` 指令后 `CMD` 指定具体的参数
之前介绍容器的时候曾经说过Docker 不是虚拟机容器就是进程既然是进程那么在启动容器的时候需要指定所运行的程序及参数`CMD` 指令就是用于指定默认的容器主进程的启动命令的
在运行时可以指定新的命令来替代镜像设置中的这个默认命令比如`ubuntu` 镜像默认的 `CMD` `/bin/bash`如果我们直接 `docker run -it ubuntu` 的话会直接进入 `bash`我们也可以在运行时指定运行别的命令 `docker run -it ubuntu cat /etc/os-release`这就是用 `cat /etc/os-release` 命令替换了默认的 `/bin/bash` 命令了输出了系统版本信息
在指令格式上一般推荐使用 `exec` 格式这类格式在解析时会被解析为 JSON 数组因此一定要使用双引号 `"`而不要使用单引号
如果使用 `shell` 格式的话实际的命令会被包装为 `sh -c` 的参数的形式进行执行比如
```docker
CMD echo $HOME
```
在实际执行中会将其变更为
```docker
CMD [ "sh", "-c", "echo $HOME" ]
```
这就是为什么我们可以使用环境变量的原因因为这些环境变量会被 shell 进行解析处理
提到 `CMD` 就不得不提容器中应用在前台执行和后台执行的问题这是初学者常出现的一个混淆
2019-03-08 04:21:07 +00:00
Docker 不是虚拟机容器中的应用都应该以前台执行而不是像虚拟机物理机里面那样 `systemd` 去启动后台服务容器内没有后台服务的概念
一些初学者将 `CMD` 写为
```docker
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` 可执行文件并且要求以前台形式运行比如
```docker
CMD ["nginx", "-g", "daemon off;"]
```