Docker Container: Uncaught Kill Signal
Manish Demblani
Posted on August 8, 2018
Has it ever happened, that you are unable to terminate/stop a running Docker container instance. Trying to press the Ctrl+C (Cmd+C) in your terminal multiple times, but being hapless all the time.
Ultimately you resort to killing the Docker process and in this way, resulting in your container stopping successfully with the famous exit code 0
(if you are lucky) or it getting killed forcefully with an exit error.
In-case an exit error occurs due to killing the container, it results in corruption of the data in the volume associated with that container and hence, you have to re-build your containers.
There are two reasons due to which this happens:
- The container does not listen to the kill signals such as SIGINT that is generated by Ctrl+C (Cmd+C) key combination
- The container shutdown process exceeds the timeout time specified by the docker process which it allots a container to shutdown, resulting in the docker process forcibly killing the container and hence the corruption.
Solution
Now there are two known ways to solve the above stated problem:
- Increase the Timeout
- Patch the Entry Script
Increase the Timeout
In this case, you simply inform the docker process to wait for some more time until the container performs a graceful shutdown. The value be which the timeout should be increased, should be a little more than the time the container takes to shutdown after detecting the signal. To get started, you can set the timeout to around 30 seconds as a safe-bet.
docker stop -t 30 CONTAINER_NAME
Patch the Entry Script
In this method, we basically monkey-patch the entry file of the container with custom code, that allows us to detect the SIGINT
signal sent to the container.
To patch the entry script, we will have to create a listener file(signal-listener.sh
):
#!/bin/bash
# A wrapper around /entrypoint.sh to trap the SIGINT signal (Ctrl+C) and forwards it to the mysql daemon
# In other words : traps SIGINT and SIGTERM signals and forwards them to the child process as SIGTERM signals
signalListener() {
"$@" &
pid="$!"
trap "echo 'Stopping PID $pid'; kill -SIGTERM $pid" SIGINT SIGTERM
# A signal emitted while waiting will make the wait command return code > 128
# Let's wrap it in a loop that doesn't end before the process is indeed stopped
while kill -0 $pid > /dev/null 2>&1; do
wait
done
}
signalListener /entrypoint.sh $@
Make sure the file is in the same folder as the Dockerfile
you will build.
The next step, is to wrap the entrypoint.sh
file with the signal-listener.sh
file. In your Dockerfile
add the following lines at the very end:
COPY signal-listener.sh /run.sh
# Entrypoint overload to catch the ctrl+c and stop signals
ENTRYPOINT ["/bin/bash", "/run.sh"]
CMD [ADD_THE_DEFAULT_DOCKER_CMD_IF_ANY]
Now if you observe, after running the docker container, you could press the Ctrl+C(Cmd+C) combination and pass it the SIGINT command. This command would now be detected by the container and it would terminate gracefully.
Credits:
This post is based on the solution provided in the following Github issue: Container does not catch signals and exit (Ctrl+C). Thanks to user Jérémy VIGNELLES for the solution provided.
Posted on August 8, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.