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:

Finding a container PID

Shell

1

2

dockerinspect--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:

Using kill inside the container

Shell

1

docker exec<container>kill-SIGHUP1

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:

Using docker kill to send signals

Shell

1

docker kill--signal=HUP<container>

CMD exec vs. 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.

2 Comments

Assuming you’re running Phusion baseimage-docker… (the my_init script doesn’t support HUP right now but seems doable, but they are using runit so we can use that). (maybe someone will modify it, it’s only 300 lines of python)

From Runit FAQ:
I want to send a service daemon the HUP signal, to have it re-read its configuration, or I want to send it the INT signal. How can a send signals to a service daemon?
Answer: Use the sv program. E.g., to send the dhcp service the HUP signal, do:

Yeah sv is also working fine to send signals. However, you need to make sure that sv is installed in your container. Unfortunately, all of my images/containers haven’t installed sv, so I can’t use that one.