Tibor's Musings

Running Multiple Daemon Processes in Docker

A Docker container is usually dedicated to running one daemon process, such as Apache to serve a web application. If the application needs a cache, or a database, then the container running the application is linked to another containing running the cache, and yet another container running the database. However, what if we need (or want) to run several daemon applications inside the same single container?

The use case

While it is a kind of anti-pattern to run several daemons inside the same container, instead of running several containers for each daemon and then cross-linking them, it may be sometimes useful. A concrete example from the Invenio digital library software world: we would like to fully emulate what users get when they run e.g. Invenio v1.0.5 on a vanilla CentOS 5 server system. This means running then-available Python-2.4, with then-available version of MySQL-5.0 and then-available pre-packaged version of MySQL-python library.

Creating an Invenio docker image that relies on CentOS 5 and runs everything inside the same container will allow us to achieve this emulation. (Theoretically, we could create several CentOS 5 based docker images and linked containers, one for running the Apache, one for running the MySQL, etc. However, we may just as well run everything inside the same image, considering that we can use the same kick-start installation scripts to provision the box, and considering that providing support to older installations in this way is relatively rare.)

The technique

Let's assume then that we'd like to run an MUA daemon process such as Exim, a web server process such as Apache, and a database server process such as MySQL all inside the same CentOS 5 based container.

The trick to use supervisord and run the supervisord daemon that will take care of keeping all the other wanted daemons alive.

Here is a minimal Dockerfile to test the idea:

FROM centos:5

RUN yum install -y epel-release && \
    yum update -y && \
    yum install -y exim \
                   httpd \
                   mysql-server \
                   supervisor && \
    yum clean all

RUN /sbin/service mysqld start && \
    mysqladmin -u root password ''

RUN echo "[supervisord]" > /etc/supervisord.conf && \
    echo "nodaemon=true" >> /etc/supervisord.conf && \
    echo "" >> /etc/supervisord.conf && \
    echo "[program:exim]" >> /etc/supervisord.conf && \
    echo "command=/usr/sbin/exim -bd -q1h" >> /etc/supervisord.conf && \
    echo "" >> /etc/supervisord.conf && \
    echo "[program:mysqld]" >> /etc/supervisord.conf && \
    echo "command=/usr/bin/mysqld_safe" >> /etc/supervisord.conf && \
    echo "" >> /etc/supervisord.conf && \
    echo "[program:httpd]" >> /etc/supervisord.conf && \
    echo "command=/usr/sbin/apachectl -D FOREGROUND" >> /etc/supervisord.conf

CMD ["/usr/bin/supervisord"]

Here is corresponding docker-compose.yml:

web:
  build: .
  command: /usr/bin/supervisord

The verification

Let us build the image and start the container:

$ docker-compose build
$ docker-compose up
web_1 | 2015-02-11 20:56:56,265 CRIT Supervisor running as root (no user in config file)
web_1 | 2015-02-11 20:56:56,282 INFO supervisord started with pid 1
web_1 | 2015-02-11 20:56:56,283 INFO spawned: 'httpd' with pid 6
web_1 | 2015-02-11 20:56:56,284 INFO spawned: 'mysqld' with pid 7
web_1 | 2015-02-11 20:56:56,285 INFO spawned: 'exim' with pid 8
web_1 | 2015-02-11 20:56:57,282 INFO success: httpd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
web_1 | 2015-02-11 20:56:57,283 INFO success: mysqld entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
web_1 | 2015-02-11 20:56:57,285 INFO success: exim entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)

Let us connect to the running container to confirm that the daemons are well up and running:

$ docker exec -i -t 6cc431e69c5f bash

[root@6cc431e69c5f /]# ps aux | grep mysql
root         7  0.1  0.0  10844  2168 ?        S    20:56   0:00 /bin/sh /usr/bin/mysqld_safe
mysql       83  0.3  0.3 188400 28532 ?        Sl   20:56   0:00 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --user=mysql --pid-file=/var/run/mysqld/mysqld.pid --skip-external-locking --log-error=/var/log/mysqld.log --socket=/var/lib/mysql/mysql.sock
root       105  0.0  0.0  61256  1792 ?        S+   20:57   0:00 grep mysql

[root@6cc431e69c5f /]# ps aux | grep httpd
root        10  0.0  0.0 174412  7076 ?        S    20:56   0:00 /usr/sbin/httpd -D FOREGROUND
apache      21  0.0  0.0 174544  3704 ?        S    20:56   0:00 /usr/sbin/httpd -D FOREGROUND
apache      22  0.0  0.0 174544  3704 ?        S    20:56   0:00 /usr/sbin/httpd -D FOREGROUND
apache      23  0.0  0.0 174544  3704 ?        S    20:56   0:00 /usr/sbin/httpd -D FOREGROUND
apache      24  0.0  0.0 174544  3704 ?        S    20:56   0:00 /usr/sbin/httpd -D FOREGROUND
apache      25  0.0  0.0 174544  3704 ?        S    20:56   0:00 /usr/sbin/httpd -D FOREGROUND
apache      26  0.0  0.0 174544  3704 ?        S    20:56   0:00 /usr/sbin/httpd -D FOREGROUND
apache      27  0.0  0.0 174544  3704 ?        S    20:56   0:00 /usr/sbin/httpd -D FOREGROUND
apache      28  0.0  0.0 174544  3704 ?        S    20:56   0:00 /usr/sbin/httpd -D FOREGROUND
root       107  0.0  0.0  61256  1884 ?        S+   20:57   0:00 grep httpd

[root@6cc431e69c5f /]# ps aux | grep exim
exim         8  0.0  0.0  79924  6388 ?        S    20:56   0:00 /usr/sbin/exim -bd -q1h

docker