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
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;
}
}
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"]
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"]
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
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)