We all know Docker, right? Running processes in Docker containers is nice and we can easily stop, start or restart the container with simple commands. However, you probably don’t want to “fully restart” a container all the time so sending signals to a Docker container becomes important.
A customer application
We’re running several applications for our customers in a Docker environment. We use Docker because it’s straight-forward to spin-up new applications, especially with a Docker reverse proxy and an SSL wildcard certificate in place. Most of the applications are Python– and Django-based and it’s quite easy to run them via gunicorn. However, you need to restart or reload your Python process (i.e. gunicorn) in order to reload the configuration file or any other changes on the source code.
Restarting vs. reloading
Of course we could easily restart our Docker container by using docker restart <container>. Unfortunately, when we restart the container we’ll produce a downtime. In our case the restart of the containers takes about 30 seconds, since we run database migrations and compress static files in advance for a performance boost. So it doesn’t make any sense to restart the whole application just for a simple config or source code change. Instead of restarting a container we only want to reload the process. Fortunately, gunicorn accepts a SIGHUP for reload.
Sending signals
Sending a signal like SIGHUP to a Linux process is quite easy. We can use kill or killall to send a signal to a process, but with Docker it gets a bit more tricky. Of course there are many ways to send signals to a Docker container. Here are some of
Option 1: Finding the PID of the container process
Since processes running inside a Docker container are also visible on the Docker host level, we can still use our well-known tools on the Docker host to send signals to the container processes. However, we need to find the right PID with:
docker inspect --format {{.State.Pid}} <container> kill -SIGHUP <PID>
Option 2: Executing kill inside the container
Instead of finding the PID we can also use docker exec to run kill (or killall) inside the Docker container:
docker exec <container> kill -SIGHUP 1
Because the Docker container is spawning your process (CMD or ENTRYPOINT) as init process with PID 1, you can always send the signal to PID 1 inside the container.
Option 3: Using docker kill
In my opinion, using the docker kill command is the most sexy way to send signals to a Docker container:
docker kill --signal=HUP <container>
CMD exec vs. shell form
Please pay attention to the CMD statement in your Dockerfile:
CMD ["/init.sh"] # exec form CMD /init.sh # shell form
Always use the exec form if you want Docker to forward signals to your (sub-)process. This is not only important for sending custom signals to a Docker container, it’s also important to properly stop (i.e. docker stop) a container.
16 Comments