正确的容器分离方法,无需停止容器

457
在Docker 1.1.2 (最新版)中,如何正确地从容器中分离而不停止它?
例如,如果我尝试以下操作: - docker run -i -t foo /bin/bash 或 - docker attach foo (对于已运行的容器)
这两种方法都可以让我进入容器的终端环境,那么如何退出容器的终端环境而不停止它?
使用 exit 和 CTR+C 都会停止容器。

“容器”只是一组受限命名空间(进程命名空间、文件系统命名空间等),进程可以在其中运行。如果一个命名空间内没有进程,那么这个命名空间是否真的存在呢?这不像虚拟机,有一个内核响应时钟中断等操作。 - Charles Duffy
1
可能是 如何附加和分离 Docker 的进程? 的重复问题。 - tripleee
14个回答

679

5
似乎无法正常工作(尝试退出已连接的Wekan容器)。 - Melroy van den Berg
8
我来过这个页面很多次,因为我无法准确记住这个键盘组合操作!:-D - Thamme Gowda
34
只有在以交互模式(-it)启动容器时,ctrl-p,ctrl-q才有效。 如果您以守护程序模式(-d)启动并附加到容器,则可以只退出容器,它仍将在后台运行。 - Riscie
3
按下 Ctrl + P 然后按下 Ctrl + Q 以退出,不是其中一个,而是按照这个顺序依次按下。 - Mohyaddin Alaoddin

239

更新: 如下面回答中提到的,Ctrl+pCtrl+q现已将交互模式转换为守护进程模式。


好的,Ctrl+C(或 Ctrl+\)应该会使您从容器中分离出来,但是由于您的主进程是bash,它会杀死容器

Docker的一个小课程。 容器不是真正的全功能操作系统。当您运行容器时,启动的进程将获取PID 1并假定init权限。因此,当该进程终止时,守护程序会停止容器,直到启动新进程(通过docker start)。(有关此问题的更多解释,请参见http://phusion.github.io/baseimage-docker/#intro

如果您想要一直在分离模式下运行的容器,我建议您使用

docker run -d foo

在容器中运行ssh服务器(最简单的方法是按照dockerizing openssh教程进行操作https://docs.docker.com/engine/examples/running_ssh_service/)。

或者您可以通过重新启动容器来实现

docker start foo

(默认情况下它将被分离)


3
+1 给 baseimage-docker。很棒能知道有一个关于 Docker 难点的模板和建议。 - mtmacdonald
1
在-d模式下运行容器非常有帮助。此外,通过Dockerfile启动ssh的链接使我的生活变得轻松。 - Ravi
75
使用 Ctrl-p、Ctrl-q 分离。这个建议会停止容器的运行。 - taranaki
5
这个对我有用(摘自下面的回答):先使用“-ti -d”开始,然后使用“docker attach”连接,最后使用先按ctrl+p,然后再按ctrl+q来分离。我曾以为我只需要使用一个键盘快捷方式。 - CGFoX
1
这个答案中的信息很有用,谢谢。在下面更深入的答案中适用于docker v23.0.1 Linux。如果我使用docker container attach --sig-proxy=false mycontainer附加到一个已经运行的容器,CTRL-C将会分离而不停止该容器。为了一次性启动并分离,我使用docker container start mycontainer;docker container attach --sig-proxy=false mycontainer - Ashley
显示剩余4条评论

224

我深入研究了这个问题,以上所有答案都有一定的道理。这完全取决于容器的启动方式。以下是容器启动时需要考虑的几点:

  • 是否分配了TTY (-t)
  • 是否保留了标准输入 (-i)

^P^Q 确实有效,但是只有在使用-t-i启动容器时才有效:

[berto@g6]$ docker run -ti -d --name test python:3.6 /bin/bash -c 'while [ 1 ]; do sleep 30; done;'
b26e39632351192a9a1a00ea0c2f3e10729b6d3e22f8e0676d6519e15c08b518

[berto@g6]$ docker attach test
# here I typed ^P^Q
read escape sequence

# i'm back to my prompt
[berto@g6]$ docker kill test; docker rm -v test
test
test

ctrl+c 确实可以工作,但是只有在使用-t不带-i)启动容器时才能工作:

[berto@g6]$ docker run -t -d --name test python:3.6 /bin/bash -c 'while [ 1 ]; do sleep 30; done;'
018a228c96d6bf2e73cccaefcf656b02753905b9a859f32e60bdf343bcbe834d

[berto@g6]$ docker attach test
^C

[berto@g6]$    

第三种分离方式

有一种方法可以在不杀死容器的情况下进行分离; 您需要另一个 shell。简而言之,在另一个 shell 中运行以下命令即可分离并保持容器运行:pkill -9 -f 'docker.*attach'(注意!使用 sigkill 的 -9 对于防止“attach”进程将信号传播到正在运行的容器非常重要。)

[berto@g6]$ docker run -d --name test python:3.6 /bin/bash -c 'while [ 1 ]; do sleep 30; done;'
b26e39632351192a9a1a00ea0c2f3e10729b6d3e22f8e0676d6519e15c08b518

[berto@g6]$ docker attach test
# here I typed ^P^Q and doesn't work
^P
# ctrl+c doesn't work either
^C
# can't background either
^Z

# go to another shell and run the `pkill` command above

# i'm back to my prompt
[berto@g6]$

为什么?因为你杀死的是连接你到容器的进程,而不是容器本身。


8
第三种方法适合我。谢谢。如果您正在连接多个实例,并且只想从其中一个实例中断连接,可以杀死特定的进程:ps -ef | grep attach -> 获取pid。然后: kill -9 <pid> - phanhuy152
pkill 是在 docker attach 后唯一对我有效的方法。 - sm4rk0
1
为什么我们需要使用“-9”参数?我注意到如果不使用“-9”,容器会关闭。 - Angelo
1
其他信号是信号。它们告诉进程哪种类型的信号,并给它机会去采取行动和做一些事情。kill -9信号不这样做。进程被终止了,没有任何补救措施。我的猜测是,其他信号让容器有机会关闭,而-9则不允许。 - berto
1
这非常有帮助。谢谢! - Evan Zamir
我会用 while true 替换 while [ 1 ][ 命令,也就是 test 命令在这里并不起作用。无论是 [ 0 ] 还是 [ 1 ] 都会返回零,所以循环会一直执行。truefalse 是命令,分别成功和失败地什么都不做。 - SenhorLucas

50

如果你执行 "docker attach "容器id"" 命令,你会进入到这个容器中。
如果你想退出容器但又不想停止它,那么你需要按下Ctrl+P+Q


7
最好按Ctrl+P和Ctrl+Q。 - sib10
7
按住Ctrl键,然后按P键和Q键(仍然按住Ctrl键)即可。 ;) - dimpiax
返回的错误信息为:守护进程错误响应:容器f560a0ad6806150b2775d0b6e6d5f7065a03775bae858fb4fb7df05a277976db未运行。 - Webwoman

35

我认为Ashwin的答案是最正确的,我的旧答案如下。


这里还想加入另一个选项,即按以下方式运行容器。

docker run -dti foo bash

然后您可以进入容器并使用以下命令运行bash:

docker exec -ti ID_of_foo bash

不需要安装sshd :)


我认为在第二个命令中,你需要用 foo 的容器 ID 替换 foo。 - Nehal J Wani
1
在这种情况下,我认为docker attach更标准,通过重新附加到第一个bash运行。 docker exec在这里也可以工作,但是它会创建一个新的bash进程,除了第一个进程之外。当然,该进程是在第一个进程的相同上下文/环境/容器中创建的,但它是不同的(类比于在您喜欢的终端仿真器中打开一个新的终端选项卡)。 - thiagowfx
这是唯一在我的特定场景下有效的命令。使用VS Code在Docker中运行测试套件。在我的情况下,这是一个Rails应用程序,所以要启动后台容器,请使用docker-compose run -d --name app_tests app spring server,然后我可以通过将vscode测试命令设置为docker exec -ti app_tests spring rspec来运行测试。 - wiggles

32

尝试使用CTRL+P, CTRL+Q将交互模式转换为守护进程。

如果这不能生效并且您是通过docker attach连接的,您可以通过终止docker attach进程来分离连接。

更好的方法是使用sig-proxy参数以避免将CTRL+C传递到容器中:

docker attach --sig-proxy=false [container-name]

docker run命令也有相同的选项可用。


9
尽管 --sig-proxy=false 非常有用,但对于已经附加的容器而言,它不起作用。问题在于,附加后似乎没有方法可以分离而不终止进程,包括“终止docker attach进程”。 在已附加的容器中,C-p,C-q不起作用,只适用于交互式容器(如问题所指)。 - taranaki
1
这应该是被接受的答案,包括@taranaki的评论,Ctrl+P,Q对于php:7.3-apache不起作用。 - MKaama

24

从交互式容器中分离的默认方法是使用 Ctrl+P Ctrl+Q,但是您可以在运行新容器或附加到现有容器时使用--detach-keys标志来覆盖它。


19
当运行docker attach时,您可以使用--detach-keys选项覆盖默认的CTRL+P,CTRL+Q序列(不总是有效),以便更好地控制容器。例如,运行docker attach --detach-keys="ctrl-a" test并按下CTRL+A,则会退出容器而不终止它。其他示例包括:docker attach --detach-keys="ctrl-a,x" test - 按下CTRL+A,然后按X退出;docker attach --detach-keys="a,b,c" test - 按下A,然后按B,最后按C退出。如果Docker默认序列与您用于其他应用程序的键序列冲突,则可以配置覆盖Docker分离的密钥序列。有两种方法可以定义自己的分离密钥序列,作为每个容器覆盖或作为整个配置的配置属性。要为单个容器覆盖序列,请在docker attach命令中使用--detach-keys=""标志。
  • a-z(一个小写字母)
  • @(at符号)
  • [(左括号)
  • \\(两个反斜杠)
  • _(下划线)
  • ^(插入符号)

这些actrl-aXctrl-\\值都是有效的键序列示例。要为所有容器配置不同的默认配置键序列,请参见Configuration文件部分。

注意:此功能适用于docker版本1.10+(在回答时,当前版本为18.03)


16

如果您只想在容器内查看进程的输出,可以使用简单的docker container logs -f <container id>

-f标志使得容器的输出会被实时跟随和更新。非常有用于调试或监控。


谢谢,ctrl+p+ctrl+q 对我来说不起作用,原因不明。 - lasec0203

10
在Docker容器中至少要运行一个进程,才能使容器在后台运行docker镜像(无论是Ubuntu、httd等)。必须保留至少一个进程才能避免退出。
例如,在Ubuntu docker镜像中,要创建一个新的容器并以分离模式运行(在后台运行至少一个进程):
docker run -d -i -t f63181f19b2f /bin/bash

它将为这个镜像(Ubuntu)ID f63181f19b2f 创建一个新的容器。容器将在分离模式下运行(在后台运行),此时一个小进程 tty bash shell 将在后台运行。因此,只要 bash shell 进程没有被杀死,容器就会继续运行。

要连接到正在运行的后台容器,请使用

docker attach  b1a0873a8647

如果您想在不退出容器的情况下分离(而不杀死bash shell),则默认情况下,您可以使用ctrl-p,q。这将使容器退出而不退出容器(在后台运行,也就是说,不杀死bash shell)。

您可以在附加容器时传递自定义命令。

docker attach --detach-keys="ctrl-s" b1a0873a8647

这次ctrl-p,q的转义序列将不起作用。相反,ctrl-s将用于退出容器。您可以传递任何键,例如(ctrl-*)


1
我已经在多个Stack Overflow答案之间切换了好几次,而这个答案是最简单、易懂、完整和直接的。感谢兄弟。 - Arwildo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接