为什么我不能总是用Ctrl-C杀死docker进程? [英] Why can't I always kill a docker process with Ctrl-C?

查看:591
本文介绍了为什么我不能总是用Ctrl-C杀死docker进程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个脚本,可以选择在容器中运行。我观察到,如果我运行一个中间脚本,可以使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆