Why can't I use Docker CMD multiple times to run multiple services?
Asked Answered
C

5

128

I have built a base image from Dockerfile named centos+ssh. In centos+ssh's Dockerfile, I use CMD to run ssh service.

Then I want to build a image run other service named rabbitmq,the 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

but ssh service doesn't work, it sense rabbitmq's Dockerfile CMD override centos's CMD.

  1. How does CMD work inside docker image?
  2. If I want to run multiple service, how to? Using supervisor?
Chinkiang answered 16/5, 2014 at 4:6 Comment(0)
M
73

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.

If you want to run multiple services, I indeed would use supervisor. You can make a supervisor configuration file for each service, ADD these in a directory, and run the supervisor with supervisord -c /etc/supervisor to point to a supervisor configuration file which loads all your services and looks like

[supervisord]
nodaemon=true

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

If you would like more details, I wrote a blog on this subject here: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image-inheritance/

Macruran answered 18/5, 2014 at 11:17 Comment(2)
Thanks,supervisor is a good idea,but i'm wonder how does CMD work inside docker imageChinkiang
You asked two question, 2. on running multiple services. On wondering how CMD works, please elaborate on what you want to know specifically. I already mentioned it being runtime information and being overwritten by any new CMD.Macruran
R
162

You are right, the second Dockerfile will overwrite the CMD command of the first one. Docker will always run a single command, not more. So at the end of your Dockerfile, you can specify one command to run. Not more.

But you can execute both commands in one line:

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

What you could also do to make your Dockerfile a little bit cleaner, you could put your CMD commands to an extra file:

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
Reorder answered 16/5, 2014 at 6:21 Comment(7)
thanks, i think use supervisor is better.but why docker only run one CMD?what happen inside?Chinkiang
I do not know what is happening inside. But I think it is just designed like that. When you have an image and run a command in it (e.g. with CMD), it starts a container. The container runs as long as the command runs. And as soon as the command finishes, the container also stops. So each container represents one single (running) command.Reorder
i think maybe it because of lcx or something's limitChinkiang
Executing commands on one line using && really helped me. Thanks!Hardened
@edwardsbean, my answer above should explain to you "why". Hope it helps.Sleety
@Tyguy7 .. because ................ ?Sleety
&& technique will work only with non-interactive services (that can start in background) else only the first one will run.Calyx
M
73

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.

If you want to run multiple services, I indeed would use supervisor. You can make a supervisor configuration file for each service, ADD these in a directory, and run the supervisor with supervisord -c /etc/supervisor to point to a supervisor configuration file which loads all your services and looks like

[supervisord]
nodaemon=true

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

If you would like more details, I wrote a blog on this subject here: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image-inheritance/

Macruran answered 18/5, 2014 at 11:17 Comment(2)
Thanks,supervisor is a good idea,but i'm wonder how does CMD work inside docker imageChinkiang
You asked two question, 2. on running multiple services. On wondering how CMD works, please elaborate on what you want to know specifically. I already mentioned it being runtime information and being overwritten by any new CMD.Macruran
S
29

While I respect the answer from qkrijger explaining how you can work around this issue I think there is a lot more we can learn about what's going on here ...

To actually answer your question of "why" ... I think it would for helpful for you to understand how the docker stop command works and that all processes should be shutdown cleanly to prevent problems when you try to restart them (file corruption etc).

Problem: What if docker did start SSH from it's command and started RabbitMQ from your Docker file? "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." Which process is docker tracking as PID 1 that will get the SIGTERM? Will it be SSH or Rabbit?? "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."

Answer: Docker simply takes that last CMD as the one that will get launched as the root process with PID 1 and get the SIGTERM from docker stop.

Suggested solution: You should use (or create) a base image specifically made for running more than one service, such as phusion/baseimage

It should be important to note that tini exists exactly for this reason, and as of Docker 1.13 and up, tini is officially part of Docker, which tells us that running more than one process in Docker IS VALID .. so even if someone claims to be more skilled regarding Docker, and insists that you absurd for thinking of doing this, know that you are not. There are perfectly valid situations for doing so.

Good to know:

Sleety answered 22/1, 2016 at 19:54 Comment(0)
C
6

The official docker answer to Run multiple services in a container.

It explains how you can do it with an init system (systemd, sysvinit, upstart) , a script (CMD ./my_wrapper_script.sh) or a supervisor like supervisord.

The && workaround can work only for services that starts in background (daemons) or that will execute quickly without interaction and release the prompt. Doing this with an interactive service (that keeps the prompt) and only the first service will start.

Calyx answered 11/11, 2019 at 17:10 Comment(0)
U
0

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...

So let's admit that it is a 'nudge' from Docker (and Kubernetes/Openshift) designers towards good practices and we should not reinvent workarounds (SSH is not necessary - we have docker exec / kubectl exec / oc rsh designed to replace it).

  • More info

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

Upbraid answered 8/1, 2020 at 9:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.