为什么我不能总是使用 Ctrl-C 终止 docker 进程?

Dav*_*ave 0 docker

我有一个脚本,我想选择在容器中运行。我观察到,如果我运行一个中间脚本,它可以被杀死Ctrl-C,但是如果我不这样做,它就不能。
这是一个例子
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
Run Code Online (Sandbox Code Playgroud)

test2.sh:

#!/bin/bash

/test1.sh true $@
Run Code Online (Sandbox Code Playgroud)

basic-Dockerfile:

FROM alpine:3.7

RUN apk add --no-cache bash
COPY test1.sh test2.sh /
ENTRYPOINT ["bash"]
Run Code Online (Sandbox Code Playgroud)

运行./test1.sh true foo bar会愉快地打印出true foo bar,并且运行./test1.sh foo bar会在容器中执行相同的操作。发送Ctrl-C将终止进程并按预期删除容器。但是,如果我尝试通过更改
为来消除对额外文件的需要:/test2.sh $@/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
Run Code Online (Sandbox Code Playgroud)

那么该进程就不能再用 终止Ctrl-C,而必须用 停止docker kill

为什么会发生这种情况?

在 WSL 中的 Windows 10 上运行的 Docker 版本 18.06.1-ce

Ign*_*lán 5

这是 docker 中的一个常见误解,但这是有充分理由的。

当进程在 Linux 中以 PID 1 运行时,其行为会略有不同。具体来说,它会忽略 SIGTERM 信号(您在按下 Ctrl-C 时发送),除非脚本被编码为这样做。当 PID > 1 时,不会发生这种情况。

这就是为什么你的第二个场景有效(PID 1是script2.sh,它委托script1.sh中的信号,它停止,因为它不是PID1)但第一个场景不起作用(script1.sh是PID 1,因此它不工作) t 以 SIGTERM 停止)。

要解决这个问题,您可以在 script1.sh 中捕获信号并退出:

exit_func() {
        echo "SIGTERM detected"            
        exit 1
}
trap exit_func SIGTERM SIGINT
Run Code Online (Sandbox Code Playgroud)

或者告诉docker run使用不同的进程(PID 1)来初始化容器。具体来说,如果您添加--init到 docker run 且没有更多参数,它会使用默认程序tini来处理这些情况:

docker run --rm -it --init $(docker build -f basic-Dockerfile -q .) /test1.sh true $@
Run Code Online (Sandbox Code Playgroud)