Run a service automatically in a docker container
Asked Answered
H

6

40

I'm setting up a simple image: one that holds Riak (a NoSQL database). The image starts the Riak service with riak start as a CMD. Now, if I run it as a daemon with docker run -d quintenk/riak-dev, it does start the Riak process (I can see that in the logs). However, it closes automatically after a few seconds. If I run it using docker run -i -t quintenk/riak-dev /bin/bash the riak process is not started (UPDATE: see answers for an explanation for this). In fact, no services are running at all. I can start it manually using the terminal, but I would like Riak to start automatically. I figure this behavior would occur for other services as well, Riak is just an example.

So, running/restarting the container should automatically start Riak. What is the correct approach of setting this up?


For reference, here is the Dockerfile with which the image can be created (UPDATE: altered using the chosen answer):

FROM ubuntu:12.04
RUN apt-get update
RUN apt-get install -y openssh-server curl 
RUN curl http://apt.basho.com/gpg/basho.apt.key | apt-key add -
RUN bash -c "echo deb http://apt.basho.com precise main > /etc/apt/sources.list.d/basho.list"
RUN apt-get update
RUN apt-get -y install riak
RUN perl -p -i -e 's/(?<=\{http,\s\[\s\{")127\.0\.0\.1/0.0.0.0/g' /etc/riak/app.config
EXPOSE 8098 
CMD /bin/riak start && tail -F /var/log/riak/erlang.log.1

EDIT: -f changed to -F in CMD in accordance to sesm his remark


MY OWN ANSWER

After working with Docker for some time I picked up the habit of using supervisord to tun my processes. If you would like example code for that, check out https://github.com/Krijger/docker-cookbooks. I use my supervisor image as a base for all my other images. I blogged on using supervisor here.

Hyperbole answered 22/6, 2013 at 15:31 Comment(1)
By the way. I'm now (for development purposes) using the container by starting it, attaching to it, and then starting Riak command line.Hyperbole
K
45

To keep docker containers running, you need to keep a process active in the foreground.

So you could probably replace that last line in your Dockerfile with

CMD /bin/riak console

Or even

CMD /bin/riak start && tail -F /var/log/riak/erlang.log.1

Note that you can't have multiple lines of CMD statements, only the last one gets run.

Kisner answered 16/7, 2013 at 9:43 Comment(1)
I'm now using the second option. Thank you for your feedback!Hyperbole
P
32

Using tail to keep container alive is a hack. Also, note, that with -f option container will terminate when log rotation happens (this can be avoided by using -F instead).

A better solution is to use supervisor. Take a look at this tutorial about running Riak in a Docker container.

Pyrometallurgy answered 9/10, 2013 at 13:39 Comment(1)
That looks promising. If you already have experience using that in combination with docker, would you care to share a short example here?Hyperbole
H
5

The explanation for:

If I run it using docker run -i -t quintenk/riak-dev /bin/bash the riak process is not started

is as follows. Using CMD in the Dockerfile is actually the same functionality as starting the container using docker run {image} {command}. As Gigablah remarked only the last CMD is used, so the one written in the Dockerfile is overwritten in this case.

By using CMD /bin/riak start && tail -f /var/log/riak/erlang.log.1 in the Buildfile, you can start the container as a background process using docker run -d {image}, which works like a charm.

Hyperbole answered 29/7, 2013 at 16:0 Comment(3)
Similarly, I am trying to dockerize CDH. In that case, i am starting service using RUN command. It starts and exits after that RUN command. What could be the reason?Chassidychassin
@GopsAB probably there is some kind of error that prevents the main process from (keeping) running. Check your logs or try your CMD manually by starting the container with /bin/bash and see what happensHyperbole
If process crashes, tailf continues to run. Same story as @FabulousSecundines
F
5

"If I run it using docker run -i -t quintenk/riak-dev /bin/bash the riak process is not started"

It sounds like you only want to be able to monitor the log when you attach to the container. My use case is a little different in that I want commands started automatically, but I want to be able to attach to the container and be in a bash shell. I was able to solve both of our problems as follows:

In the image/container, add the commands you want automatically started to the end of the /etc/bash.bashrc file.

In your case just add the line /bin/riak start && tail -F /var/log/riak/erlang.log.1, or put /bin/riak start and tail -F /var/log/riak/erlang.log.1 on separate lines depending on the functionality desired.

Now commit your changes to your container, and run it again with: docker run -i -t quintenk/riak-dev /bin/bash. You'll find the commands you put in the bashrc are already running as you attach.

Fabulous answered 9/11, 2013 at 5:44 Comment(4)
That's actually a very nice solution :) Note that 0.6.5 added that docker run -a option for supervisors compatibility. You might want to chack that out as well.Hyperbole
Not a good solution. What will you do if process exits, tailf will continue running, container will not exit.Secundines
@MincăDanielAndrei You're right in part. This is not a production ready solution, it's not sustainable for the reason you mention. It's best if at all possible to have the entrypoint or cmd of your image be the process you want to run itself. Often this means you need to find the --no-daemon option for said process to keep the container from exiting when the entrypoint backgrounds itself and exits, and to make it log to stderr/stdout.Fabulous
Another option would be to use dumb-init , the init system for containers, as stated here engineeringblog.yelp.com/2016/01/…Secundines
W
3

Because I want a clean way to have the process exit later I make the last command a call to the shell's read which causes that process to block until I later attach to it and hit enter.

arthur@macro:~/docker$ sudo docker run -d -t -i -v /raid:/raid -p 4040:4040 subsonic /bin/bash -c 'service subsonic start && read -p "waiting"'
WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: [8.8.8.8 8.8.4.4]
f27229a260c9

arthur@macro:~/docker$ sudo docker ps                                                                                                                                     
[sudo] password for arthur: 
ID                  IMAGE               COMMAND                CREATED              STATUS              PORTS
35f253bdf45a        subsonic:latest     /bin/bash -c service   2 days ago          Up 2 days           4040->4040

arthur@macro:~/docker$ sudo docker attach 35f253bdf45a

arthur@macro:~/docker$ sudo docker ps                                                                                                                                     
ID                  IMAGE               COMMAND             CREATED             STATUS              PORTS

as you can see the container exits after you attach to it and unblock the read. You can of course use a more sophisticated script than read -p if you need to do other clean up, such as stopping services and saving logs etc.

Wyatt answered 14/10, 2013 at 17:15 Comment(0)
B
0

I use a simple trick whenever I start building a new docker container. To keep it alive, I use a ping in the entrypoint script.

So in the Dockerfile, when using debian, for instance, I make sure I can ping. This is btw, always nice, to check what is accessible from within the container.

...
RUN DEBIAN_FRONTEND=noninteractive apt-get update \
 && apt-get install -y iputils-ping 
...
ENTRYPOINT ["entrypoint.sh"]

And in the entrypoint.sh file

#!/bin/bash
...
ping 10.10.0.1 >/dev/null 2>/dev/null

I use this instead of CMD bash, as I always wind up using a startup file.

Behindhand answered 22/3, 2018 at 8:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.