如何在 docker 容器内修复 ctrl+c
How to fix ctrl+c inside a docker container
如果我连接到 docker 容器
$> docker exec -it my_container zsh
在里面我想杀死我开始的东西ctrl+c
我注意到它需要很长时间才能完成。我用谷歌搜索了一下,似乎 ctrl+c
的工作方式与您预期的有点不同。我的问题是,如何在容器内修复 ctrl+c
?
问题是 Ctrl-C 向容器内的顶级进程发送了一个信号,但该进程不一定会像您预期的那样做出反应。顶层进程在容器内的 ID 为 1,这意味着它不会获得进程通常具有的默认信号处理程序。如果顶级进程是 shell,那么它可以通过自己的处理程序接收信号,但不会将其转发给在 shell 中执行的命令。详细说明here。在这两种情况下,docker 容器的行为就好像它只是忽略了 Ctrl-C。
从 docker 0.6.5
开始,您可以将 -t
添加到 docker 运行 命令,这将附加一个 pseudo-TTY
。然后你可以输入 Control-C
来脱离容器而不终止它。
如果您使用 -t
和 -i
那么 Control-C 将终止容器。使用 -i with -t
时,您必须使用 Control-P Control-Q
来分离而不终止。
测试 1:
$ ID=$(sudo docker run -t -d ubuntu /usr/bin/top -b)
$ sudo docker attach $ID
Control-P Control-Q
$ sudo docker ps
容器仍在列表中。
测试 2:
$ ID=$(sudo docker run -t -i -d ubuntu /usr/bin/top -b)
$ sudo docker attach $ID
Control-C
$ sudo docker ps
容器不存在(已终止)。如果在第二个示例中键入 Control-P
Control-Q
而不是 Control-C,容器仍将是 运行ning.
Wrap the program with a docker-entrypoint.sh bash script that blocks
the container process and is able to catch ctrl-c. This bash example
might help:
https://rimuhosting.com/knowledgebase/linux/misc/trapping-ctrl-c-in-bash
#!/bin/bash
# trap ctrl-c and call ctrl_c()
trap ctrl_c INT
function ctrl_c() {
echo "** Trapped CTRL-C"
}
for i in `seq 1 5`; do
sleep 1
echo -n "."
done
使用Ctrl+\代替Ctrl+C
它会终止进程,而不是礼貌地要求它关闭。(阅读更多 here。)
我在 docker 容器中尝试 运行 mdbook
(Rust 可执行文件)时遇到了类似的问题。 mdbook
启动简单的网络服务器,我想通过 Ctrl+C 停止它,但没有用。
$ docker -ti --rm -p 4321:4321 my-docker-image mdbook serve --hostname 0.0.0.0 --port 4321
2019-08-16 14:00:11 [INFO] (mdbook::book): Book building has started
2019-08-16 14:00:11 [INFO] (mdbook::book): Running the html backend
2019-08-16 14:00:11 [INFO] (mdbook::cmd::serve): Serving on: http://0.0.0.0:4321
2019-08-16 14:00:11 [INFO] (ws): Listening for new connections on 0.0.0.0:3001.
2019-08-16 14:00:11 [INFO] (mdbook::cmd::watch): Listening for changes...
^C^C
受到@NID 回答的启发,我通过通用 bash 脚本 docker-entrypoint.sh
封装了 mdbook 可执行文件,它起到了作用(无需显式捕获 INT 信号)。
$ docker -ti --rm -p 4321:4321 my-docker-image docker-entrypoint.sh mdbook serve --hostname 0.0.0.0 --port 4321
2019-08-16 14:00:11 [INFO] (mdbook::book): Book building has started
2019-08-16 14:00:11 [INFO] (mdbook::book): Running the html backend
2019-08-16 14:00:11 [INFO] (mdbook::cmd::serve): Serving on: http://0.0.0.0:4321
2019-08-16 14:00:11 [INFO] (ws): Listening for new connections on 0.0.0.0:3001.
2019-08-16 14:00:11 [INFO] (mdbook::cmd::watch): Listening for changes...
^C $
docker-entrypoint.sh
的内容很简单:
#!/bin/bash
$@
浪费了大约2个小时。
新命令 --(工作正常)
sudo docker stop
sudo docker rm
sudo docker run -t
旧命令 --(不再有效)
sudo docker stop
sudo docker rm
sudo docker run
Ctrl + C
sudo docker start
希望对某人有所帮助。
在某些情况下,当我使用 ctrl-C 终止容器内的进程时,容器会终止。
此外,我还见过容器内的进程 运行ning 离开僵尸进程的情况。
我发现在使用“--init”开关启动容器时,这两个问题都得到了解决。这似乎使我的容器以更“正常的、预期的类似 UNIX 的方式”运行。
注意:--init不同于-i,后者是--interactive
的缩写
如果您想了解有关“--init”开关功能的更多信息,请在包含有关“docker 运行 信息的 Docker 网页上阅读它”。该网页上的信息显示“运行 容器内的一个 init,用于转发信号和获取进程”。
我尝试了@Remy Orange 的 --init
解决方案,它对我有用。经过一些搜索,包括i), ii) What is advantage of Tini? and iii) init,我把详细的解决方案写在下面:
- 在 Ubuntu 上安装
tini
:
- 通过启动:
$ sudo apt update && sudo apt install tini
- 或者,如果
tini
在您的发行版中不可用或太旧,请检查 Docker 文件以在 here 添加 tini。
- 运行 你的 Docker 容器
--init
:
docker run -ti --init --rm YOUR_DOCKER_CONTAINER_EXMAPLE bash
然后你进入你的 docker 容器,你可以 运行 一些过程或实验。例如,运行 一个 Python 代码,然后你可以启动 Ctrl + C
来取消这个 Python 代码,就像你可以在 Ubuntu 上做的一样(即docker 容器外的常规终端。
看我的截图:
正在启动 Ctrl + C (i.e., ^C)
以取消 python 进程:
它停止了,按预期显示 KeyboardInterrupt
:
谁还有这个问题,为我工作Ctrl+d
。 Ctrl+c
或 Ctrl+z
均无效。
如果使用DockerCompose,可以添加init
参数转发信号到容器:
version: "2.4"
services:
web:
image: alpine:latest
init: true
要使其正常工作,您需要在 docker exec
命令中添加选项 -ti
。
如果我连接到 docker 容器
$> docker exec -it my_container zsh
在里面我想杀死我开始的东西ctrl+c
我注意到它需要很长时间才能完成。我用谷歌搜索了一下,似乎 ctrl+c
的工作方式与您预期的有点不同。我的问题是,如何在容器内修复 ctrl+c
?
问题是 Ctrl-C 向容器内的顶级进程发送了一个信号,但该进程不一定会像您预期的那样做出反应。顶层进程在容器内的 ID 为 1,这意味着它不会获得进程通常具有的默认信号处理程序。如果顶级进程是 shell,那么它可以通过自己的处理程序接收信号,但不会将其转发给在 shell 中执行的命令。详细说明here。在这两种情况下,docker 容器的行为就好像它只是忽略了 Ctrl-C。
从 docker 0.6.5
开始,您可以将 -t
添加到 docker 运行 命令,这将附加一个 pseudo-TTY
。然后你可以输入 Control-C
来脱离容器而不终止它。
如果您使用 -t
和 -i
那么 Control-C 将终止容器。使用 -i with -t
时,您必须使用 Control-P Control-Q
来分离而不终止。
测试 1:
$ ID=$(sudo docker run -t -d ubuntu /usr/bin/top -b)
$ sudo docker attach $ID
Control-P Control-Q
$ sudo docker ps
容器仍在列表中。
测试 2:
$ ID=$(sudo docker run -t -i -d ubuntu /usr/bin/top -b)
$ sudo docker attach $ID
Control-C
$ sudo docker ps
容器不存在(已终止)。如果在第二个示例中键入 Control-P
Control-Q
而不是 Control-C,容器仍将是 运行ning.
Wrap the program with a docker-entrypoint.sh bash script that blocks the container process and is able to catch ctrl-c. This bash example might help: https://rimuhosting.com/knowledgebase/linux/misc/trapping-ctrl-c-in-bash
#!/bin/bash
# trap ctrl-c and call ctrl_c()
trap ctrl_c INT
function ctrl_c() {
echo "** Trapped CTRL-C"
}
for i in `seq 1 5`; do
sleep 1
echo -n "."
done
使用Ctrl+\代替Ctrl+C
它会终止进程,而不是礼貌地要求它关闭。(阅读更多 here。)
我在 docker 容器中尝试 运行 mdbook
(Rust 可执行文件)时遇到了类似的问题。 mdbook
启动简单的网络服务器,我想通过 Ctrl+C 停止它,但没有用。
$ docker -ti --rm -p 4321:4321 my-docker-image mdbook serve --hostname 0.0.0.0 --port 4321
2019-08-16 14:00:11 [INFO] (mdbook::book): Book building has started
2019-08-16 14:00:11 [INFO] (mdbook::book): Running the html backend
2019-08-16 14:00:11 [INFO] (mdbook::cmd::serve): Serving on: http://0.0.0.0:4321
2019-08-16 14:00:11 [INFO] (ws): Listening for new connections on 0.0.0.0:3001.
2019-08-16 14:00:11 [INFO] (mdbook::cmd::watch): Listening for changes...
^C^C
受到@NID 回答的启发,我通过通用 bash 脚本 docker-entrypoint.sh
封装了 mdbook 可执行文件,它起到了作用(无需显式捕获 INT 信号)。
$ docker -ti --rm -p 4321:4321 my-docker-image docker-entrypoint.sh mdbook serve --hostname 0.0.0.0 --port 4321
2019-08-16 14:00:11 [INFO] (mdbook::book): Book building has started
2019-08-16 14:00:11 [INFO] (mdbook::book): Running the html backend
2019-08-16 14:00:11 [INFO] (mdbook::cmd::serve): Serving on: http://0.0.0.0:4321
2019-08-16 14:00:11 [INFO] (ws): Listening for new connections on 0.0.0.0:3001.
2019-08-16 14:00:11 [INFO] (mdbook::cmd::watch): Listening for changes...
^C $
docker-entrypoint.sh
的内容很简单:
#!/bin/bash
$@
浪费了大约2个小时。
新命令 --(工作正常)
sudo docker stop
sudo docker rm
sudo docker run -t
旧命令 --(不再有效)
sudo docker stop
sudo docker rm
sudo docker run
Ctrl + C
sudo docker start
希望对某人有所帮助。
在某些情况下,当我使用 ctrl-C 终止容器内的进程时,容器会终止。
此外,我还见过容器内的进程 运行ning 离开僵尸进程的情况。
我发现在使用“--init”开关启动容器时,这两个问题都得到了解决。这似乎使我的容器以更“正常的、预期的类似 UNIX 的方式”运行。
注意:--init不同于-i,后者是--interactive
的缩写如果您想了解有关“--init”开关功能的更多信息,请在包含有关“docker 运行 信息的 Docker 网页上阅读它”。该网页上的信息显示“运行 容器内的一个 init,用于转发信号和获取进程”。
我尝试了@Remy Orange 的 --init
解决方案,它对我有用。经过一些搜索,包括i)
- 在 Ubuntu 上安装
tini
:
- 通过启动:
$ sudo apt update && sudo apt install tini
- 或者,如果
tini
在您的发行版中不可用或太旧,请检查 Docker 文件以在 here 添加 tini。
- 运行 你的 Docker 容器
--init
:
docker run -ti --init --rm YOUR_DOCKER_CONTAINER_EXMAPLE bash
然后你进入你的 docker 容器,你可以 运行 一些过程或实验。例如,运行 一个 Python 代码,然后你可以启动
Ctrl + C
来取消这个 Python 代码,就像你可以在 Ubuntu 上做的一样(即docker 容器外的常规终端。看我的截图:
正在启动
Ctrl + C (i.e., ^C)
以取消 python 进程:它停止了,按预期显示
KeyboardInterrupt
:
谁还有这个问题,为我工作Ctrl+d
。 Ctrl+c
或 Ctrl+z
均无效。
如果使用DockerCompose,可以添加init
参数转发信号到容器:
version: "2.4"
services:
web:
image: alpine:latest
init: true
要使其正常工作,您需要在 docker exec
命令中添加选项 -ti
。