Stopping Docker containers Gracefully

Tweet about this on Twitter0Share on Facebook3Share on Google+3Share on LinkedIn19

I started to work with Docker containers two years ago. You can find my dockerfile examples here: https://github.com/komljen/dockerfile-examples

This was my playground for testing, but after I started to work on enterprise level applications deployment using Docker I find out that a lot of things I’m doing wrong. One of them is how I start application inside Docker.

Almost all my dockerfiles have some bash script at the end to do some minor changes inside container and to finally start application. I usually add this script to CMD instruction in Dockerfile. I think there isn’t anything wrong with that, except docker stop will not work as it should.

The problem is that when you run bash script it will get PID 1 and your application is a child process with PPID 1. Bash will not forward SIGTERM signal to you application when you run docker stop. Instead, container will be killed after 10 seconds of timeout which is default with docker stop command. This timeout can be adjusted.

There is an easy way to handle this with “exec” command inside bash script. It will replace the shell without creating a new process and your application will get PID 1. Let’s test both scenarios first.

For testing purposes I will use this simple redis dockerfile:

And here is the start.sh script which will change some recommended kernel settings for redis container (docker must be started with privileged set to true):

Now let’s build and run this container:

Then check what is running inside redis container:

Ok, so this is a problem. Now let’s try to stop this docker container:

After 10 seconds container is killed, not stopped gracefully. We can see this if we check the log. Last message will be that redis is ready to accept connections:

To make this working we need to change the last line in start.sh script and to rebuild the image. We are adding exec before /usr/bin/redis-server command:

Build, start and run ps -ef command again:

As you can see now redis is running as PID 1, and docker stop will work just fine. Lets try it first and check docker log again. You should see this message in redis log:

This is how I’m using exec with postgres and tomcat containers where processes are not running with root user:

Here processes will not be running with PID 1 because of sudo or su, however Docker stop works perfectly in both cases. The reason for this is that sudo and su commands will relay SIGTERM signal to child processes.

Tweet about this on Twitter0Share on Facebook3Share on Google+3Share on LinkedIn19
Posted in Docker and tagged .

Alen Komljen

I'm a DevOps/Cloud engineer with experience that spans a broad portfolio of skills, including cloud computing, software deployment, process automation, shell scripting and configuration management, as well as Agile development and Scrum. This allowed me to excel in solving challenges in cloud computing, and the entire IT infrastructure along with my deep interest in OpenStack, Ceph, Docker and the open-source community.