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.

qkrijger
  • 26,686
  • 6
  • 36
  • 37
  • By the way. I'm now (for development purposes) using the container by starting it, attaching to it, and then starting Riak command line. – qkrijger Jul 01 '13 at 08:42

6 Answers6

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.

Andy
  • 17,423
  • 9
  • 52
  • 69
Gigablah
  • 1,361
  • 15
  • 9
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.

jamesmstone
  • 397
  • 10
  • 29
sesm
  • 1,218
  • 12
  • 21
  • 3
    That looks promising. If you already have experience using that in combination with docker, would you care to share a short example here? – qkrijger Oct 10 '13 at 08:39
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.

qkrijger
  • 26,686
  • 6
  • 36
  • 37
  • 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? – Gibbs Jan 16 '15 at 11:30
  • @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 happens – qkrijger Jan 17 '15 at 19:10
  • If process crashes, tailf continues to run. Same story as @damick – Daniel Andrei Mincă Oct 28 '16 at 11:41
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.

damick
  • 1,055
  • 1
  • 10
  • 17
  • 3
    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. – qkrijger Nov 09 '13 at 16:10
  • Not a good solution. What will you do if process exits, tailf will continue running, container will not exit. – Daniel Andrei Mincă Oct 28 '16 at 11:40
  • @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. – damick Nov 03 '16 at 18:48
  • 1
    Another option would be to use `dumb-init` , the init system for containers, as stated here https://engineeringblog.yelp.com/2016/01/dumb-init-an-init-for-docker.html – Daniel Andrei Mincă Nov 03 '16 at 22:53
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.

Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
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.

Tim Chaubet
  • 498
  • 1
  • 7
  • 15