为什么我不能总是用Ctrl-C杀死一个docker进程?

问题描述 投票:0回答:2

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

test2.sh

#!/bin/bash

/test1.sh true $@

basic-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

#!/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来终止。

为什么会这样?

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

docker
2个回答
2
投票

这是码头工人常见的误解,但这是有充分理由的。

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

这就是你的第二个场景有效的原因(PID 1是script2.sh,它在script1.sh中委托信号,因为它不是PID1而停止)但不是第一个(script1.sh是PID 1因此它没有'用SIGTERM停止)。

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

exit_func() {
        echo "SIGTERM detected"            
        exit 1
}
trap exit_func SIGTERM SIGINT

或者告诉docker run用不同的进程初始化容器作为PID 1.具体来说,如果你将--init添加到没有更多参数的docker run,它会使用一个默认程序tini来准备处理这些情况:

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

1
投票

你也可以使用exec用一个新的替换当前的shell,可以用ctrl-c来停止它。例如start.sh脚本启动nginx服务器并运行uwsgi

#!/usr/bin/env bash

service nginx start
uwsgi --ini uwsgi.ini

应该改为

#!/usr/bin/env bash

service nginx start
exec uwsgi --ini uwsgi.ini

在theese改变后ctrl c将停止容器

© www.soinside.com 2019 - 2024. All rights reserved.