Even though the common practice states that one must create containers that have a single process running, it's common so see people facing the need for a multi-process approach.
A pretty good solution that i've found is S6 (https://skarnet.org/software/s6/) "a collection of utilities revolving around process supervision and management, logging, and system initialization" (from the description) β after reading a blog post from Tutum (https://blog.tutum.co/2014/12/02/docker-and-s6-my-new-favorite-process-supervisor/).
My context was simple; needed to run several processes and ensure that:
- if process A fails, process A must be restarted
- processes A, B and C are supposed to not be ran as daemons and might occasionally fork (creating subprocesses)
- doesn't require many configuration files
- SIGTERM should be properly handled
A sample demonstrating the end result can be found here: https://github.com/beldpro-ci/s6-entrypoint.
Going straight to the demonstration, the directory structure:
.
βββ Dockerfile
βββ Makefile
βββ README.md
βββ etc // added to `/etc` of image
βββ bin
β βββ my-binary // main executable
βββ s6
βββ lala
β βββ finish // lala βon-failβ script
β βββ run // lala service start-up script
βββ lulu
βββ finish // lulu βon-failβ script
βββ run // lulu start-up script
As S6 has the capabilities of a proper *init*, the Dockerfile is pretty simple: just fetches S6 and then sets the entrypoint:
FROM alpineRUN apk add β update s6 bashADD ./etc /etcENTRYPOINT [ β/bin/s6-svscanβ, β/etc/s6β ]`
/etc/s6 indicates a scan directory: a directory with a list of service directories β where scripts related to a given service reside. For instance, say that *lala* is a service (like nginx) that has a start script and that we also have *lulu*, another service, like rsyslog, which also has a start script. We'd create a directory (in this case i created /etc/s6 β could have any name!) and then, for each service, add a directory (with the name of the service). Each service directory then receives a *run* script (name used by s6 to locate a start script).
And that's it! That's the enough to have your processes being supervised and its zombies taken care of. In the end, it looks like this:
s6-docker-demo git:(master) β makedocker run s6testSpawning lalaSpawning lulu
The two processes are spawn concurrently, with a little trick of having *s6-supervise* processes taking care of our services:
~ docker top f5993ea33b59PID USER TIME COMMAND3136 root 0:00 /bin/s6-svscan /etc/s63156 root 0:00 s6-supervise lala3157 root 0:00 s6-supervise lulu3158 root 0:00 {my-binary} /bin/sh /etc/bin/my-binary3160 root 0:00 {my-binary} /bin/sh /etc/bin/my-binary3217 root 0:00 sleep 13218 root 0:00 sleep 1
In the repository (https://github.com/beldpro-ci/s6-entrypoint) you can find more information as each little detail got documented over there.
What about you? How have you been doing multi-processes containers with Docker (if so)? Let me know if you've got a good solution!
Hey, also, please let me know if i stated something incorrectly. I'll appreciate a lot! Thanks!