bashdockersleepsigintsigkill

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


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.


Solution

  • 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.