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

时间:2014-05-16 04:06:20

标签: docker

我已经从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 image中工作?
  2. 如果我想运行多项服务,怎么办?使用主管?

5 个答案:

答案 0 :(得分:91)

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

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

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

你还可以做些什么来使你的Docker文件更清洁一点,你可以将你的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 :(得分:55)

即使在Dockerfile中写下了CMD,它确实是运行时信息。就像EXPOSE一样,但与例如运行和添加。通过这个,我的意思是你可以稍后在扩展的Dockerfile中覆盖它,或者在你运行的命令中简单地覆盖它,这正是你所经历的。在任何时候,只能有一个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/

答案 2 :(得分:24)

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

要实际回答您的问题“为什么”...我认为这对您了解for x in a_list: print(x) 命令的工作原理以及所有进程应该是有帮助的干净地关闭以防止在尝试重新启动它们时出现问题(文件损坏等)。

问题:如果docker 从它的命令启动SSH并且从Docker文件启动RabbitMQ怎么办? “The docker stop command attempts to stop a running container first by sending a SIGTERM signal to the root process (PID 1) in the container.”哪个进程是docker跟踪PID 1将获得SIGTERM?它会是SSH还是兔子? "According to the Unix process model, the init process -- PID 1 -- inherits all orphaned child processes and must reap them. Most Docker containers do not have an init process that does this correctly, and as a result their containers become filled with zombie processes over time."

答案:Docker只将最后一个CMD作为一个,将其作为根进程以PID 1启动,并从docker stop获取SIGTERM。

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

重要的是要注意tini完全存在这个原因,从Docker 1.13开始,tini正式成为Docker的一部分,它告诉我们在Docker中运行多个进程是有效的 ..所以即使有人claims to be more skilled关于Docker,并且坚持认为你这样做是荒谬的,也要知道你不是。这样做非常有效。

很高兴知道:

答案 3 :(得分:0)

码头工人对Run multiple services in a container的回答。

它说明了如何使用初始化系统(systemd,sysvinit,upstart),脚本(CMD ./my_wrapper_script.sh)或诸如supervisord的管理程序来完成此操作。

&&解决方法仅适用于在后台启动的服务(守护程序),或者无需交互即可快速执行并释放提示的服务。使用交互式服务(保留提示)来执行此操作,只有第一个服务会启动。

答案 4 :(得分:0)

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

因此,让我们承认,这是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