为什么我不能多次使用 Docker CMD 来运行多个服务?

我从 Dockerfile 构建了一个名为 centos + ssh 的基本映像,在 centos + ssh 的 Dockerfile 中,我使用 CMD 来运行 ssh 服务。

然后,我想建立一个映像运行其他名为 rabbitmq 的服务,Dockerfile:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD /opt/mq/sbin/rabbitmq-server start

To start rabbitmq container,run:

docker run -d -p 222:22 -p 4149:4149 rabbitmq

但是 ssh 服务不工作,它感应 Rabbitmq 的 Dockerfile CMD 覆盖 centos 的 CMD。

  1. How does CMD work inside docker image?
  2. 如果我想运行多个服务,如何? 使用主管?
202790 次浏览

您是对的,第二个 Dockerfile 将覆盖第一个 Dockerfile 的 CMD命令。Docker 将始终运行一个命令,而不是更多。因此,在 Dockerfile 的末尾,可以指定要运行的 命令。不会再多了。

但是您可以在一行中执行这两个命令:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD service sshd start && /opt/mq/sbin/rabbitmq-server start

如果你想让你的 Dockerfile 更干净一点,你可以把你的 CMD 命令放到一个额外的文件中:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD sh /home/centos/all_your_commands.sh

And a file like this:

service sshd start &
/opt/mq/sbin/rabbitmq-server start

Even though CMD is written down in the Dockerfile, it really is runtime information. Just like EXPOSE, but contrary to e.g. RUN and ADD. By this, I mean that you can override it later, in an extending Dockerfile, or simple in your run command, which is what you are experiencing. At all times, there can be only one CMD.

如果你想运行多个服务,我确实会使用主管。您可以为每个服务创建一个管理员配置文件,在一个目录中添加这些配置文件,然后用 supervisord -c /etc/supervisor运行管理员以指向一个管理员配置文件,该文件加载您的所有服务并且看起来像

[supervisord]
nodaemon=true


[include]
files = /etc/supervisor/conf.d/*.conf

如果你想知道更多的细节,我在这里写了一篇关于这个主题的博客: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image-inheritance/

虽然我尊重 qkrijger 的回答,解释如何解决这个问题,但我认为我们可以了解更多这里发生的事情... ..。

To actually answer your question of "为什么" ... I think it would for helpful for you to understand how the docker stop command works and that 所有进程应干净地关闭 to prevent problems when you try to restart them (file corruption etc).

问题: 如果 Docker 是的从它的命令 还有启动 SSH 从 Docker 文件启动 RabbitMQ 会怎么样?“ Docker stop 命令首先通过向容器中的根进程(PID 1)发送 SIGTERM 信号来尝试停止正在运行的容器。”哪个进程作为 PID 1跟踪,将获得 SIGTERM?是 SSH 还是 Rabbit? ?”根据 Unix 进程模型,init 进程—— PID 1——继承所有孤立的子进程,并且必须收获它们。大多数 Docker 容器都没有正确执行此操作的 init 进程,因此,随着时间的推移,它们的容器会变得充满僵尸进程。”

答: Docker 只是将最后一个 CMD 作为 ,它将以 根进程的形式启动,PID 为1,并从 docker stop获得 SIGTERM。

Suggested solution: You should use (or create) a base image specifically made for running more than one service, such as 伪影/基本影像

值得注意的是,提尼正是因为这个原因而存在的,从 Docker 1.13及以上版本开始,tini 正式成为 Docker 的一部分,这告诉我们在 Docker 有效中运行多个进程。.因此,即使有人 声称自己技术更高超关于多克,并坚持认为你荒谬的想法这样做,知道你不是。这样做有完全合理的情况。

很高兴知道:

正式码头答复 在一个容器中运行多个服务

它解释了如何使用 init 系统(systemd、 sysvinit、 upstart)、脚本(CMD ./my_wrapper_script.sh)或者像 supervisord这样的主管来完成。

&&解决方案只能用于在后台启动的服务(守护进程) ,或者在没有交互的情况下快速执行并释放提示符的服务。使用交互式服务(保持提示)执行此操作,并且只启动第一个服务。

To address why CMD is designed to run only one service per container, let's just realize what would happen if the secondary servers run in the same container are not trivial / auxiliary but "major" (e.g. storage bundled with the frontend app). For starters, it would break down several important containerization features such as horizontal (auto-)scaling and rescheduling between nodes, both of which assume there is only one application (source of CPU load) per container. Then there is the issue of vulnerabilities - more servers exposed in a container means more frequent patching of CVEs...

因此,让我们承认,这是 Docker (以及 Kubernetes/Openshift)设计师对良好实践的“推动”,我们不应该重新发明变通方法(SSH 是不必要的——我们有 docker exec / kubectl exec / oc rsh设计来取代它)。

  • 更多信息

Https://devops.stackexchange.com/questions/447/why-it-is-recommended-to-run-only-one-process-in-a-container