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

def*_*ect 8 rust docker windows-subsystem-for-linux

我在使用 Ubuntu 映像的 Windows 10 上使用 WSL2,以及使用 WSL 集成的 Docker for Desktop Windows (2.2.2.0)。

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

我把它变成了一个 Docker 镜像。这是 Dockerfile。

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"]
Run Code Online (Sandbox Code Playgroud)

然后我做:

docker build -t myserver .
docker run -it --rm -p 8080:8080 myserver
Run Code Online (Sandbox Code Playgroud)

试图Ctrl-C进程^C在终端中显示字符,但信号似乎没有到达进程。我必须使用docker kill. 我读过其他像这样这样的帖子。它表明组合-it和使用ENTRYPOINTor的数组参数版本CMD应该允许信号到达它,但是这些似乎对我没有帮助。

要查看它是否与我的设置(桌面版 Docker、WSL 等)或我的 Dockerfile 有关,我遵循了 docker -http-https-echo的自述文件,并且我能够Ctrl-C过程。检查 Dockerfile 并没有表明它做的事情与我不同,但显然我遗漏了一些东西。

小智 11

您的问题的原因是内核特别对待PID为1的进程,并且默认情况下在接收SIGTERMSIGINT信号时不会终止该进程。

您有两个选择:

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

好的做法是将这两种方法结合起来。


Yor*_*ggy 5

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

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

  • 不要在 Exec 入口点中使用 Pipeline:在某些情况下,这可能会生成在子 shell 中运行的应用程序,从而导致无信号(SIGINT、SIGTERM、SIGKILL)

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

    ENTRYPOINT ["/app/bin/your-app", "arg1", "arg2"]
Run Code Online (Sandbox Code Playgroud)

我的回答基于这篇文章和这篇文章