无法使用 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
的组合和使用 ENTRYPOINT
或 CMD
的数组参数版本应该允许信号到达它,但是这些似乎对我没有帮助。
为了查看它是否与我的设置(Docker 用于桌面、WSL 等)或我的 Docker 文件有关,我遵循了 docker-http-https-echo 的自述文件,而且我能够 Ctrl-C 这个过程。检查 Docker 文件并没有显示它在做任何与我不同的事情,但显然我遗漏了一些东西。
你的问题的原因是内核对 PID 为 1 的进程进行了特殊处理,并且在默认情况下不会在收到 SIGTERM
或 SIGINT
信号时终止进程。
您有两个选择:
- 将
--init
标志添加到 docker run
命令。这样,将创建一个 PID 为 1 的特殊进程,它将成为您进程的父进程,并将代理所有信号并正确获取您的进程。
- 为您的应用程序添加显式信号处理,如果您想正常关机,这很好。
最好的做法是结合使用这两种方法。
我希望不要迟到,Nikscorp 提供了您的容器可能无法停止的可能原因之一,但这可能发生在其他情况下,如下所示:
您的 ENTRYPOINT
是一个 sheel 脚本并且您没有使用 Exec: 通常,当您 运行 您的容器来自shell 脚本,你的容器 运行s 在一个新进程上导致你的容器不会收到任何信号,这可以使用 exec 命令解决
不要在您的 Exec 入口点使用 Pipeline: 在某些情况下,这可以在子 [=39= 中生成您的应用程序 运行 ], 这导致没有信号 (SIGINT, SIGTERM, SIGKILL)
使用不正确的入口点形式:推荐的入口点形式是 exec 形式,就像这个 (这发生在我身上并且解决了我的问题)
ENTRYPOINT ["/app/bin/your-app", "arg1", "arg2"]
我在 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
的组合和使用 ENTRYPOINT
或 CMD
的数组参数版本应该允许信号到达它,但是这些似乎对我没有帮助。
为了查看它是否与我的设置(Docker 用于桌面、WSL 等)或我的 Docker 文件有关,我遵循了 docker-http-https-echo 的自述文件,而且我能够 Ctrl-C 这个过程。检查 Docker 文件并没有显示它在做任何与我不同的事情,但显然我遗漏了一些东西。
你的问题的原因是内核对 PID 为 1 的进程进行了特殊处理,并且在默认情况下不会在收到 SIGTERM
或 SIGINT
信号时终止进程。
您有两个选择:
- 将
--init
标志添加到docker run
命令。这样,将创建一个 PID 为 1 的特殊进程,它将成为您进程的父进程,并将代理所有信号并正确获取您的进程。 - 为您的应用程序添加显式信号处理,如果您想正常关机,这很好。
最好的做法是结合使用这两种方法。
我希望不要迟到,Nikscorp 提供了您的容器可能无法停止的可能原因之一,但这可能发生在其他情况下,如下所示:
您的
ENTRYPOINT
是一个 sheel 脚本并且您没有使用 Exec: 通常,当您 运行 您的容器来自shell 脚本,你的容器 运行s 在一个新进程上导致你的容器不会收到任何信号,这可以使用 exec 命令解决不要在您的 Exec 入口点使用 Pipeline: 在某些情况下,这可以在子 [=39= 中生成您的应用程序 运行 ], 这导致没有信号 (SIGINT, SIGTERM, SIGKILL)
使用不正确的入口点形式:推荐的入口点形式是 exec 形式,就像这个 (这发生在我身上并且解决了我的问题)
ENTRYPOINT ["/app/bin/your-app", "arg1", "arg2"]