Running multiple services in Docker container
Docker is amazing in application testing or when we need run something in isolated environment.
But sometimes needed to run daemons (such as sshd or nginx). And there is some problems begin, because in ideology of Docker when process is finished, the container will stop. This is good for single application, we run some code, see results and container stops.
So, is there a solution? Yes, and the answer is supervisord.
It's a python-based tool for controlling processes (including restarting on crash and much more).
In a nutshell is something like init for our container, supervisor has well-documented manual for config files.
Ok, it's a game time!
I'm using Gentoo (3.16.2 kernel) and Docker 1.2.0 in this example
Let's create container for sshd service, and build it using docker build
command:
create temporary directory, and write config files here
[sloun@heaven ~ ] cd $(mktemp -d)
in Dockerfile I'll specify what packages needed to install, and what directories needed to create for sshd
[sloun@heaven /tmp/tmp.Fvl9y73yhl ] cat Dockerfile
# vim: set syntax=dockerfile:
#sshd template
FROM debian:stable
MAINTAINER sloun@roundside
RUN apt-get update && apt-get -y upgrade \
&& apt-get -y install openssh-server supervisor \
&& echo 'root:toor' | chpasswd \
&& sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config\
&& mkdir /var/run/supervisor && mkdir /var/run/sshd
#supervisord config
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
EXPOSE 22
CMD ["/usr/bin/supervisord"]
Now in detail:
- use debian stable (wheezy so far) template
- specify maintainer for template
- update & upgrade packages to latest versions
- set 'toor' as root password
- if root login is not allowed, fix it using sed
- copy supervisord.conf to /etc/supervisor/conf.d/
- expose 22 port (more about it below)
- run supervisord
The reason to use expose
is to make this port available in a container immediately. If not expose port, sshd also will be available, but it will take some time (up to minute!). Read more about this here.
Now, create config file for supervisor (supervisord.conf), simple config for sshd looks like this:
[supervisord]
nodaemon=true
[program:sshd]
command=/usr/sbin/sshd -D
Ok. We have Dockerfile and supervisord.conf in directory:
[sloun@heaven /tmp/tmp.Fvl9y73yhl ] l
total 8
-rw-r--r-- 1 sloun sloun 706 Nov 18 03:36 Dockerfile
-rw-r--r-- 1 sloun sloun 166 Nov 18 03:14 supervisord.conf
Time for creating container:
[sloun@heaven /tmp/tmp.Fvl9y73yhl ] docker build -t debian:sshd .
about tag
-t is a tag option to specify local repository for this container
That's all. Start container and expose local port to it:
[sloun@heaven /tmp/tmp.Fvl9y73yhl ] docker run -d -p 127.0.0.1:1030:22 debian:sshd
Sshd now available at 127.1:1030
Mysqld and sshd in one container
Run mysql in that way is also very easy. But there are some pitfalls:
- mysqld run on loopback
- no users by default
- remote root login is forbidden
So, my easiest Dockerfile looks like this:
# vim: set syntax=dockerfile:
#sshd-mysqld template
FROM debian:stable
MAINTAINER sloun@roundside
RUN apt-get update && apt-get -y upgrade \
&& apt-get -y install openssh-server mysql-server supervisor \
&& echo 'root:toor' | chpasswd \
&& sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config \
&& sed -i 's/bind-address.\+/bind-address=0.0.0.0/' /etc/mysql/my.cnf \
&& mkdir /var/run/supervisor && mkdir /var/run/sshd
#supervisord config
COPY ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf
#ports
EXPOSE 22
EXPOSE 3306
#stuff for mysql
COPY ./mysql.sh /opt/mysql.sh
#run supervisord
CMD ["/usr/bin/supervisord"]
- First, bind mysqld on all available interfaces using sed
- expose mysqld port
- add little shell scipt (mysql.sh, must be executable) for adding remote root login
mysql.sh:
#!/usr/bin/env bash
echo "GRANT ALL ON *.* TO root@'%' IDENTIFIED BY 'toor' WITH GRANT OPTION; FLUSH PRIVILEGES" | mysql
And updated supervisord.conf:
[supervisord]
nodaemon=true
[program:sshd]
command=/usr/sbin/sshd -D
[program:mysqld]
command=/usr/bin/mysqld_safe
[program:mysql-configure]
command=/opt/mysql.sh
Build and run.
[sloun@heaven /tmp/tmp.Fvl9y73yhl ] docker build -t debian:sshd_mysqld .
[sloun@heaven /tmp/tmp.Fvl9y73yhl ] docker run -d -p 127.0.0.1:1040:22 -p 127.0.0.1:1041:3306 debian:sshd_mysqld
Look in docker ps
:
[sloun@heaven /tmp/tmp.Fvl9y73yhl ] docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9e197bc92b64 debian:sshd_mysqld "/usr/bin/supervisor 30 minutes ago Up 30 minutes 127.0.0.1:1040->22/tcp, 127.0.0.1:1041->3306/tcp insane_franklin
Now, mysql root login is available at 127.1:4041, and ssh on :4040.
Also, linking containers together is also cool for this!
Thanks to http://txt.fliglio.com/2013/11/creating-a-mysql-docker-container/