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


96

我已经从Dockerfile建立了一个名为centos + ssh的基础映像。在centos + ssh的Dockerfile中,我使用CMD运行ssh服务。

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

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

要启动rabbitmq容器,请运行:

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

但是ssh服务无法正常工作,它感觉到Rabbitmq的Dockerfile CMD覆盖了centos的CMD。

  1. CMD如何在docker映像中工作?
  2. 如果要运行多个服务,该怎么办?使用主管?

Answers:


62

即使将CMD记录在Dockerfile中,它实际上也是运行时信息。就像EXPOSE一样,但是与RUN和ADD相反。通过这个,我的意思是您可以稍后在扩展的Dockerfile中覆盖它,或者在您正在运行的run命令中简单地覆盖它。在任何时候,只能有一个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-遗产/


谢谢,主管是个好主意,但我想知道CMD如何在
docker

2
您问了两个问题,关于运行多个服务。在想知道CMD如何工作时,请详细说明您想知道的内容。我已经提到过它是运行时信息,并且会被任何新的CMD覆盖。
qkrijger 2014年

118

没错,第二个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

和这样的文件:

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

1
谢谢,我认为使用主管更好。但是为什么码头工人只运行一个CMD?内部发生了什么?
edwardsbean 2014年

1
我不知道里面发生了什么。但是我认为它就是这样设计的。当您拥有图像并在其中运行命令时(例如,使用CMD),它将启动一个容器。只要命令运行,容器就会运行。一旦命令完成,容器也会停止。因此,每个容器代表一个单独的(运行)命令。
Thomas Uhrig 2014年

我觉得也许是因为LCX或某事的极限
edwardsbean

2
@ Tyguy7 .. 因为 ................吗?
StartupGuy

1
&&该技术仅适用于非交互式服务(可以在后台启动),否则仅运行第一个。
noraj

26

虽然我尊重qkrijger的回答,解释了如何解决此问题,但我认为我们可以了解到这里的更多信息...

实际回答您的“ 为什么 ”的问题...我认为这对您了解docker stop命令的工作原理以及应该彻底关闭所有进程以防止在尝试重新启动它们时发生问题(文件损坏等)很有帮助。

问题:如果码头工人没有从它的命令开始SSH 从泊坞文件启动的RabbitMQ?“ docker stop命令首先尝试通过向容器中的根进程(PID 1)发送SIGTERM信号来停止正在运行的容器。 ” docker跟踪哪个进程作为PID 1来获取SIGTERM?是SSH还是Rabbit?“根据Unix进程模型,init进程-PID 1-继承了所有孤立的子进程,必须获得它们。大多数Docker容器都没有正确执行此操作的init进程,结果,它们的容器被填充了随着时间的流逝僵尸进程。”

答:泊坞窗简单地取,去年CMD作为一个将得到推出,根进程与PID 1,并从SIGTERM docker stop

建议的解决方案:您应该使用(或创建)专门用于运行多个服务的基础映像,例如 phusion / baseimage。

重要的是要注意 正是由于这个原因,tini确实存在,并且从Docker 1.13开始,tini正式成为Docker的一部分,这告诉我们在Docker中运行多个进程是有效的 ..即使有人声称这样做对Docker 更加熟练,并坚持认为您这样做是荒谬的,但知道您并非如此。这样做是完全有效的情况。

很高兴知道:


3

Docker官方回答在容器中运行多个服务

它说明了如何使用init系统(systemd,sysvinit,upstart),脚本(CMD ./my_wrapper_script.sh)或管理程序(例如supervisord

&&解决方法可以启动后台(守护进程)服务只工作或将很快执行没有互动,释放提示。使用交互式服务(保留提示)来执行此操作,只有第一个服务会启动。


0

为了解决为什么CMD设计为每个容器仅运行一项服务的问题,让我们意识到,如果在同一容器中运行的辅助服务器不是琐碎/辅助而是“主要”(例如,与前端应用程序捆绑在一起的存储),将会发生什么情况。对于初学者来说,它将破坏几个重要的容器化功能,例如节点之间的水平(自动)缩放和重新计划,这两个功能都假定每个容器只有一个应用程序(CPU负载的来源)。然后是漏洞的问题-容器中暴露的服务器越多,意味着CVE的修补越频繁...

因此,让我们承认,这是Docker(和Kubernetes / Openshift)设计师朝着良好实践的“推动”,我们不应重新发明变通办法(SSH是没有必要的-我们已docker exec / kubectl exec / oc rsh设计用来替代它)。

  • 更多信息

/devops/447/why-it-is-recommended-to-run-only-one-process-in-a-container

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.