Dockerfile之CMD

本文将介绍Dockerfile的CMD指令,该指令设置容器启动时执行的操作。

CMD指令用来设置容器启动时执行的操作。CMD 指令的格式和 RUN 相似,也是两种格式:

shell 格式:

CMD <命令>

exec 格式:

CMD ["可执行文件", "参数1", "参数2"...]

Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。

在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,ubuntu 镜像默认的 CMD 是 /bin/bash,如果我们直接 docker run -it ubuntu 的话,会直接进入 bash。如下:

[root@localhost ~]# docker run -it ubuntu
root@cd5b845cf72f:/#

我们也可以在运行时指定运行别的命令,如:docker run -it ubuntu cat /etc/os-release。如下:

[root@localhost ~]# docker run -it ubuntu cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.2 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
[root@localhost ~]#

这就是用 cat /etc/os-release 命令替换了默认的 /bin/bash 命令了,输出了系统版本信息。

在指令格式上,一般推荐使用 exec 格式,这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号("),而不要使用单引号(')。如果使用 shell 格式的话,实际的命令会被包装为 sh -c 的参数的形式进行执行。比如:

 CMD echo $HOME

在实际执行中,会将其变更为:

 CMD [ "sh", "-c", "echo $HOME" ]

这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。

提到 CMD 就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 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;"]
我们常常听人说,人们因工作过度而垮下来,但是实际上十有八九是因为饱受担忧或焦虑的折磨。 —— 卢伯克.J.
0 不喜欢
说说我的看法 -
全部评论(

在 Docker 中,一个容器可以同时启动多个服务吗?例如,使用一个容器同时运行 MySQL、Redis 和 Nginx。

回复:

Docker 容器可以同时启动多个服务。

Docker容器是独立运行的轻量级虚拟化单元,可以在其中运行各种应用程序和服务。要在Docker容器中同时启动多个服务,有几种常见的方法:
(1)使用多个容器:每个服务使用一个独立的Docker容器。这是最常见的做法,每个容器都专注于运行一个特定的服务。可以使用Docker Compose等工具来管理和编排多个容器。
(2)在同一个容器中运行多个服务:有时,多个服务可以在同一个容器中同时运行。这可以通过在容器中运行一个进程管理器(如supervisor)来实现,该进程管理器负责启动和管理多个服务。
(3)使用容器内部的进程管理:在某些情况下,容器内部的进程管理工具(如systemd)可以用来同时启动和管理多个服务。这需要在容器镜像中预先配置好相应的进程管理工具。
无论选择哪种方法,都需要确保容器中的各个服务之间不会发生端口冲突或资源争用。此外,还应该考虑容器的资源限制和隔离性,以确保各个服务能够正常运行并相互独立。

关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号