为什么我不能总是用Ctrl-C杀死docker进程? [英] Why can't I always kill a docker process with Ctrl-C?
问题描述
我有一个脚本,可以选择在容器中运行。我观察到,如果我运行一个中间脚本,可以使用 Ctrl-C
将其杀死,但是如果我不这样做,它将无法执行。
这是一个示例:
test1.sh
:
I have a script which I want to optionally run within a container. I have observed that if I run an intermediate script it can be killed with Ctrl-C
, however if I do not then it can't.
Here is an example:
test1.sh
:
#!/bin/bash
if [ "${1}" = true ]; then
while true; do echo "args: $@"; sleep 1; done
else
docker run --rm -it $(docker build -f basic-Dockerfile -q .) /test2.sh $@
fi
test2.sh
:
#!/bin/bash
/test1.sh true $@
基本Dockerfile
:
FROM alpine:3.7
RUN apk add --no-cache bash
COPY test1.sh test2.sh /
ENTRYPOINT ["bash"]
运行。/test1.sh true foo bar
会很高兴地打印出来 true foo bar
,并运行。/test1.sh foo bar
在容器中也可以执行相同的操作。发送 Ctrl-C
将终止该进程并按预期方式删除该容器。
但是,如果我尝试通过更改 /test2.sh $ @
到 /test1.sh true $ @
:
test1.sh
Running ./test1.sh true foo bar
will happily print out true foo bar
, and running ./test1.sh foo bar
will do the same in a container. Sending Ctrl-C
will kill the process and delete the container as expected.
However if I try to remove the need for an extra file by changing /test2.sh $@
to /test1.sh true $@
:
test1.sh
#!/bin/bash
if [ "${1}" = true ]; then
while true; do echo "args: $@"; sleep 1; done
else
docker run --rm -it $(docker build -f basic-Dockerfile -q .) /test1.sh true $@
fi
然后不能再使用 Ctrl-C
终止该过程,而必须被 docker kill
停止。
then the process can no longer be terminated with Ctrl-C
, and instead must be stopped with docker kill
.
为什么会这样?
在Windows 10中以WSL运行的Docker版本18.06.1-ce
Docker version 18.06.1-ce running on Windows 10 in WSL
推荐答案
这是常见的误解在docker中,但这是有充分理由的。
That's a common misunderstanding in docker but it's for a good reason.
当进程在Linux中以PID 1运行时,其行为会有所不同。具体来说,除非脚本经过编码,否则它将忽略信号为SIGTERM(在按Ctrl-C时发送)。当PID> 1时不会发生这种情况。
When a process run as PID 1 in Linux it behaves a little different. Specifically, it ignores signals as SIGTERM (which you send when hitting Ctrl-C), unless the script is coded to do so. This doesn't occur when PID > 1.
这就是为什么您的第二种情况有效(PID 1是script2.sh,它在script1.sh中委派了信号,之所以停止,是因为它不是PID1),而不是第一个(script1.sh是PID 1,因此不会因SIGTERM而停止)。
And that's why your second scenario works (The PID 1 is script2.sh, which delegates the signal in script1.sh, which stops because it is not PID1) but not the first one (script1.sh is PID 1 and thus it doesn't stop with SIGTERM).
要解决这个问题,您可以在script1.sh中捕获信号并退出:
To solve that, you can trap the signal in script1.sh and exit:
exit_func() {
echo "SIGTERM detected"
exit 1
}
trap exit_func SIGTERM SIGINT
或者告诉 docker run
使用与PID 1不同的进程来初始化容器。具体来说,如果将-init
添加到docker run没有更多参数,它使用默认程序 tini ,它已准备好处理以下情况:
Or tell docker run
to init the container with a different process as PID 1. Specifically, if you add --init
to docker run with no more arguments, it uses a default program, tini, prepared to handle these situations:
docker run --rm -it --init $(docker build -f basic-Dockerfile -q .) /test1.sh true $@
这篇关于为什么我不能总是用Ctrl-C杀死docker进程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!