无法使用 Ctrl-C 停止我的 Docker 容器

Unable to stop my Docker container with Ctrl-C

我在 Windows 10 上使用 WSL2,使用 Ubuntu 图像,Docker 桌面 Windows (2.2.2.0) 与 WSL 集成。

我有一个 Rust TCP 服务器。当我 运行 它与 cargo run (或 cargo install 之后的二进制文件)时,它做了正确的事情,我可以发送 Ctrl-C 给它终止。我没有在代码中做任何明确的信号处理。

我把它变成了 Docker 图片。这是 Docker 文件。

FROM rust:1.40 as builder
COPY . .
RUN cargo install --path . --root .

FROM debian:buster-slim
COPY --from=builder ./bin/myserver ./myserver
EXPOSE 8080
ENTRYPOINT ["./myserver"]

然后我做:

docker build -t myserver .
docker run -it --rm -p 8080:8080 myserver

尝试Ctrl-C进程在终端显示^C字符,但信号不似乎到达了过程。我使用docker kill。我读过其他帖子,例如 this and this。它表明 -it 的组合和使用 ENTRYPOINTCMD 的数组参数版本应该允许信号到达它,但是这些似乎对我没有帮助。

为了查看它是否与我的设置(Docker 用于桌面、WSL 等)或我的 Docker 文件有关,我遵循了 docker-http-https-echo 的自述文件,而且我能够 Ctrl-C 这个过程。检查 Docker 文件并没有显示它在做任何与我不同的事情,但显然我遗漏了一些东西。

你的问题的原因是内核对 PID 为 1 的进程进行了特殊处理,并且在默认情况下不会在收到 SIGTERMSIGINT 信号时终止进程。

您有两个选择:

  1. --init 标志添加到 docker run 命令。这样,将创建一个 PID 为 1 的特殊进程,它将成为您进程的父进程,并将代理所有信号并正确获取您的进程。
  2. 为您的应用程序添加显式信号处理,如果您想正常关机,这很好。

最好的做法是结合使用这两种方法。

我希望不要迟到,Nikscorp 提供了您的容器可能无法停止的可能原因之一,但这可能发生在其他情况下,如下所示:

  • 您的 ENTRYPOINT 是一个 sheel 脚本并且您没有使用 Exec: 通常,当您 运行 您的容器来自shell 脚本,你的容器 运行s 在一个新进程上导致你的容器不会收到任何信号,这可以使用 exec 命令解决

  • 不要在您的 Exec 入口点使用 Pipeline: 在某些情况下,这可以在子 [=39= 中生成您的应用程序 运行 ], 这导致没有信号 (SIGINT, SIGTERM, SIGKILL)

  • 使用不正确的入口点形式:推荐的入口点形式是 exec 形式,就像这个 (这发生在我身上并且解决了我的问题)

    ENTRYPOINT ["/app/bin/your-app", "arg1", "arg2"]

我的回答基于此 post and this one