Why can't I CTRL-C a sleep infinity in docker when it runs as PID 1
Asked Answered
A

2

9

Case: we have a docker container that runs a bash script that needs to "block" forever (because it exposes a volume for another container, but there are other reasons why we sometimes want this).

I thought this could work then:

exec sleep infinity;

ps aux then gives "sleep" as PID 1. Great, I thought, then it will receive signals we send it from outside the container. For example:

docker kill -s INT container_name

But that doesn't work, container keeps running (also for SIGTERM). A normal kill does work, but I don't understand why there's a difference (which annoys me greatly):

docker kill container_name

Why can't I kill "sleep" with SIGINT/SIGTERM when it runs as PID 1 in my container? I believe I can kill other things (like bash scripts) with SIGINT/SIGTERM when they run as PID 1 in a container.

Alviani answered 17/7, 2017 at 15:42 Comment(1)
What command started the container? What version Docker? What host OS? Can we see the Dockerfile?Jonathanjonathon
C
7

Would this be of any use? https://www.fpcomplete.com/blog/2016/10/docker-demons-pid1-orphans-zombies-signals

Basically the problem is process number 1. Linux/unix kernels are reluctant to signal that process the regular way, as it is supposed to be init. If init process dies, the system issues a panic immediately and reboots. If your process 1 does not have a handler to a signal, the signal just gets dropped. Sleep does not have handlers for any signals but you can build one to bash script.

Basically what you need to do is use exec form in your dockerfile, and split your sleep infinity into a loop as bash traps do not get triggered while shell is executing a command. This sends a signal to the running process 1 and catches it:

Dockerfile:

FROM ubuntu
ADD foo.sh /tmp
RUN ["/tmp/foo.sh"]

foo.sh:

#!/bin/bash

trap "echo signal;exit 0" SIGINT 

while :
do
    sleep 1
done

This will react to docker kill --signal=SIGINT.

Chicken answered 17/7, 2017 at 16:48 Comment(3)
Thanks this pointed me in the right direction. After some reading and Googling I also found this, which seems to be a nice solution and probably a good idea when running docker containers: docs.docker.com/engine/reference/run/#specify-an-init-processAlviani
I can confirm this. I wrote a small C program that catches all (almost all) signals and I checked that when used in ENTRYPOINT ["/my-signal-catcher"] it does receive SIGKILL and is capable of simply exiting upon it. The difference with sleep seems to be that it doesn't add any handlers for the signal.Gittern
@Alviani referred to this text which has since been updated: web.archive.org/web/20170627071753/https://docs.docker.com/… The current text no longer makes mention of --init.Cynara
G
1

Use this script as init process:

trap "echo Shutting down; exit 0" SIGTERM SIGINT SIGKILL
/bin/sleep infinity &
wait

E.g: with ENTERYPOINT ["/bin/bash", "-c", "trap \"echo Shutting down; exit 0\" SIGTERM SIGINT SIGKILL; /bin/sleep infinity & wait"]

Goosander answered 23/1 at 5:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.