DEV Community

Teclado
Teclado

Posted on • Edited on

Adding other services to a Docker container

If you are about to dockerize a production-ready infrastructure in order to save server-related costs, you may find a problem with certain images that are enough complex to be a pain to override but does not fulfill your requeriments completly.

In that case the common roadmap is to extend that image until you are comfortable with it. But, what if we want or need to add some other services? Simply overriding the ENTRYPOINT layer is often both a risk and a pain too, and you would have to be aware of the changes in the original image. For that we can look after the existence of supervisord.

Learning by example

An example of this is the official Redmine image. This image serves by default the Redmine app in the port 3000 using HTTP. But we want to use HTTPS because we want to use it in a production environment! Then we need a HTTP server acting as a proxy where we configure HTTPS.

Well, that's not an issue, we just extend the image in a Dockerfile like the following:

FROM redmine:5

RUN apt-get update && \
    apt-get install -y \
    nginx \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

COPY conf/default.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
EXPOSE 443
Enter fullscreen mode Exit fullscreen mode

Being conf/default.conf the Nginx config file, something like the following:

server {
    listen       80;
    listen      [::]:80;
    server_name  redmine.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen      443 ssl;
    listen      [::]:443 ssl;
    server_name redmine.example.com;

    ssl_certificate     /path/to/certificate.crt;
    ssl_certificate_key /path/to/certificate.key;

    location / {
        proxy_pass http://127.0.0.1:3000;
    }

}
Enter fullscreen mode Exit fullscreen mode

Ok, but that's not launching Nginx at all yet. That's why we need supervisord. If we inspect the Redmine Dockerfile, we can see the following lines:

WORKDIR /usr/src/redmine
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["rails", "server", "-b", "0.0.0.0"]
Enter fullscreen mode Exit fullscreen mode

Thats all the information we need to configure supervisord to launch Redmine. But first, we need to install it. For that we edit our Dockerfile so it finally remains like the following:

FROM redmine:5

RUN apt-get update && \
    apt-get install -y \
    supervisor \
    nginx \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

COPY conf/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY conf/default.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
EXPOSE 443

ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
Enter fullscreen mode Exit fullscreen mode

We have added the supervisor package to the apt-get install command, and the copy of the configuration file of it. As we want supervisord to be our new entrypoint we added the last line too, passing the configuration file to the command.

Then the conf/supervisor.conf file will have to be something like this:

[supervisord]
nodaemon=true
user=root

[program:nginx]
user=root
command=nginx

[program:redmine]
user=redmine
directory=/usr/src/redmine
command=/docker-entrypoint.sh rails server -b 127.0.0.1
Enter fullscreen mode Exit fullscreen mode

The first section is the configuration of the supervisor daemon itself. We simply set the user to be root and indicate that it have to run in foreground with nodaemon=true.

With the second section we just start Nginx using the default configuration file (the one we copied in the Dockerfile).

With the last section we demand supervisord to start Redmine. First we change to the dir /usr/src/redmine, as the Redmine Dockerfile states with the WORKDIR layer. And we start the application linking the ENTRYPOINT and the CMD layers of the original Dockerfile. We also change the IP Redmine will listen on to 127.0.0.1 in order to avoid direct connections from outside the container.

Conclusion

We have tweaked a Docker image to fit the need of other services inside the same container without changing a word of the original image.

You can see more about supervisor in the Debian man page.

Top comments (0)