我有一个脚本,我想选择在容器中运行。我观察到,如果我运行一个中间脚本,它可以被杀死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
这是 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)
| 归档时间: |
|
| 查看次数: |
3808 次 |
| 最近记录: |