Sending SIGHUP
with
kill -HUP <pid>
to a busybox sh
process on my native system works as expected and the shell hangs up. However, if I use docker kill
to send the signal to a container with
docker kill -s HUP <container>
it doesn’t do anything. The Alpine container is still running:
$ CONTAINER=$(docker run -dt alpine:latest) $ docker ps -a --filter "id=$CONTAINER" --format "{{.Status}}" Up 1 second $ docker kill -s HUP $CONTAINER 4fea4f2dabe0f8a717b0e1272528af1a97050bcec51babbe0ed801e75fb15f1b $ docker ps -a --filter "id=$CONTAINER" --format "{{.Status}}" Up 7 seconds
By the way, with an Ubuntu container (which runs bash
) it does work as expected:
$ CONTAINER=$(docker run -dt debian:latest) $ docker ps -a --filter "id=$CONTAINER" --format "{{.Status}}" Up 1 second $ docker kill -s HUP $CONTAINER 9a4aff456716397527cd87492066230e5088fbbb2a1bb6fc80f04f01b3368986 $ docker ps -a --filter "id=$CONTAINER" --format "{{.Status}}" Exited (129) 1 second ago
Sending SIGKILL
does work, but I’d rather find out why SIGHUP
does not.
Update: I’ll add another example. Here you can see that busybox sh
generally does hang up on SIGHUP
successfully:
$ busybox sh -c 'while true; do sleep 10; done' & [1] 28276 $ PID=$! $ ps -e | grep busybox 28276 pts/5 00:00:00 busybox $ kill -HUP $PID $ [1]+ Hangup busybox sh -c 'while true; do sleep 10; done' $ ps -e | grep busybox $
However, running the same infinite sleep loop inside the docker container doesn’t quit. As you can see, the container is still running after SIGHUP
and only exits after SIGKILL
:
$ CONTAINER=$(docker run -dt alpine:latest busybox sh -c 'while true; do sleep 10; done') $ docker ps -a --filter "id=$CONTAINER" --format "{{.Status}}" Up 14 seconds $ docker kill -s HUP $CONTAINER 31574ba7c0eb0505b776c459b55ffc8137042e1ce0562a3cf9aac80bfe8f65a0 $ docker ps -a --filter "id=$CONTAINER" --format "{{.Status}}" Up 28 seconds $ docker kill -s KILL $CONTAINER 31574ba7c0eb0505b776c459b55ffc8137042e1ce0562a3cf9aac80bfe8f65a0 $ docker ps -a --filter "id=$CONTAINER" --format "{{.Status}}" Exited (137) 2 seconds ago $
Advertisement
Answer
(I don’t have Docker env at hand for a try. Just guessing.)
For your case, docker run
must be running busybox/sh
or bash
as PID 1.
According to Docker doc:
Note: A process running as PID 1 inside a container is treated specially by Linux: it ignores any signal with the default action. So, the process will not terminate on
SIGINT
orSIGTERM
unless it is coded to do so.
For the differece between busybox/sh and bash regarding SIGHUP
—
On my system (Debian 9.6, x86_64), the signal masks for busybox/sh
and bash
are as follows:
busybox/sh:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 82817 0.0 0.0 6952 1904 pts/2 S+ 10:23 0:00 busybox sh PENDING (0000000000000000): BLOCKED (0000000000000000): IGNORED (0000000000284004): 3 QUIT 15 TERM 20 TSTP 22 TTOU CAUGHT (0000000008000002): 2 INT 28 WINCH
bash:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 4871 0.0 0.1 21752 6176 pts/16 Ss 2019 0:00 /usr/local/bin/bash PENDING (0000000000000000): BLOCKED (0000000000000000): IGNORED (0000000000380004): 3 QUIT 20 TSTP 21 TTIN 22 TTOU CAUGHT (000000004b817efb): 1 HUP 2 INT 4 ILL 5 TRAP 6 ABRT 7 BUS 8 FPE 10 USR1 11 SEGV 12 USR2 13 PIPE 14 ALRM 15 TERM 17 CHLD 24 XCPU 25 XFSZ 26 VTALRM 28 WINCH 31 SYS
As we can see busybox/sh does not handle SIGHUP
so the signal is ignored. Bash catches SIGHUP
so docker kill
can deliver the signal to Bash and then Bash will be terminated because, according to its manual, “the shell exits by default upon receipt of a SIGHUP
“.
UPDATE 2020-03-07 #1:
Did a quick test and my previous analysis is basically correct. You can verify like this:
[STEP 104] # docker run -dt debian busybox sh -c 'trap exit HUP; while true; do sleep 1; done' 331380090c59018dae4dbc17dd5af9d355260057fdbd2f2ce9fc6548a39df1db [STEP 105] # docker ps CONTAINER ID IMAGE COMMAND CREATED 331380090c59 debian "busybox sh -c 'trap…" 11 seconds ago [STEP 106] # docker kill -s HUP 331380090c59 331380090c59 [STEP 107] # docker ps CONTAINER ID IMAGE COMMAND CREATED [STEP 108] #
As I showed earlier, by default busybox/sh
does not catch SIGHUP
so the signal will be ignored. But after busybox/sh
explicitly trap SIGHUP
, the signal will be delivered to it.
I also tried SIGKILL
and yes it’ll always terminate the running container. This is reasonable since SIGKILL
cannot be caught by any process so the signal will always be delivered to the container and kill it.
UPDATE 2020-03-07 #2:
You can also verify it this way (much simpler):
[STEP 110] # docker run -ti alpine / # ps PID USER TIME COMMAND 1 root 0:00 /bin/sh 7 root 0:00 ps / # kill -HUP 1 <-- this does not kill it because linux ignored the signal / # / # trap 'echo received SIGHUP' HUP / # kill -HUP 1 received SIGHUP <-- this indicates it can receive SIGHUP now / # / # trap exit HUP / # kill -HUP 1 <-- this terminates it because the action changed to `exit` [STEP 111] #