为什么“docker attach”会挂起?

93

我可以成功运行一个 ubuntu 容器:

# docker run -it -d ubuntu
3aef6e642327ce7d19c7381eb145f3ad10291f1f2393af16a6327ee78d7c60bb
# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
3aef6e642327        ubuntu              "/bin/bash"         3 seconds ago       Up 2 seconds                            condescending_sammet

但执行docker attach会挂起:

# docker attach 3aef6e642327

在我按下任意键之前,比如说Enter键:

# docker attach 3aef6e642327
root@3aef6e642327:/#
root@3aef6e642327:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
为什么docker attach会挂起?
更新:
阅读评论后,我认为我得到了答案:
前提: "docker attach" 重用相同的 tty,而不是打开新的 tty。 (1)在非守护进程模式下执行docker run
# docker run -it ubuntu
root@eb3c9d86d7a2:/# 

一切正常后,运行ls命令:

root@eb3c9d86d7a2:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@eb3c9d86d7a2:/#

(2) 使用守护进程模式运行 docker run 命令:

# docker run -it -d ubuntu
91262536f7c9a3060641448120bda7af5ca812b0beb8f3c9fe72811a61db07fc

实际上,以下内容应该已从运行的容器中输出到标准输出:

root@91262536f7c9:/#

执行docker attach命令看起来会卡住,但实际上它在等待你的输入:

# docker attach 91262536f7c9
ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@91262536f7c9:/#

2
@user2915097:抱歉,我不理解你的评论与问题有何关联。您能详细说明一下吗?谢谢! - Nan Xiao
尝试运行 docker run -p 80:80 nginx - user2915097
有几个人在Docker Github仓库上开了问题来解决这个问题,请参见Docker的回应:docker attach container hangs, requires inputdocker attach hangs setting terminal state when attaching to container - Francesco de Guytenaere
5
首先,命令 # docker run -it -d ubuntu 自相矛盾。-it 表示“交互式地运行,并配备 tty”,而 -d 则表示“在后台运行”。
Docker 的 attach 命令允许您以交互方式控制容器。
请参考文档
- Auzias
1
确实,“docker不会处于Up状态”,因为您没有提供任何命令,然后运行了bash,但是由于没有tty、stdin或stdout,所以bash退出。如果您例如运行docker run -d ubuntu nc -l 1445,则容器将保持运行状态。 - Auzias
显示剩余4条评论
7个回答

47

当我尝试连接一个由其他人开发并已运行守护程序的容器(在这种情况下,是LinuxServer的transmission docker镜像)时,我也遇到了这个问题。

问题:

问题是终端似乎“挂起”,输入任何内容都无济于事且不会显示出来。只有Ctrl-C才能让我退出。

docker rundocker startdocker attach都没有成功,结果发现我需要的命令(在使用runstart启动容器后)是执行bash,因为从您下载的容器中很可能没有bash正在运行。

解决方案:

docker exec -it <container-id> bash

(您可以从运行docker ps -a获得container-id)。

这将以root用户的身份将您拉入实例中,并具有功能完整的bash(假设您下载的映像没有进行其他明确设置)。

我知道已经有一个被采纳的答案,但我决定发布另一个更简洁和明显的解决方案,因为当我阅读时,这个解决方案并没有显露出来。


接受的答案可能确实包含有用的信息,但它掩盖了重点。感谢直截了当地表达。 - steve

45

它并没有真正的“挂起”。正如您在下面的评论中看到的(您正在运行“/bin/bash”作为命令),当附加时似乎是预期的行为。

据我所了解,您只需附加到正在运行的 shell,并且只有标准输入/输出/错误 - 取决于您与运行命令一起传递的选项 - 将向您显示从那一刻开始进出的任何内容。(希望有更深入了解的人可以在更高层次上解释这一点)。

正如我在您的问题评论中写的那样,有几个人在 docker github 存储库上打开了一个问题,描述了类似的行为:

由于你提到了shell,我推测你已经在运行一个shell。attach不会启动一个新进程,那么连接到正在运行的进程的in/out/err流的预期行为是什么? 我没有考虑过这一点。当然,这是连接到正在运行的shell的预期行为,但这是可取的吗? 在docker attach上刷新stdout/stderr是否有可能,从而强制打印shell提示符,还是比这更复杂?当我连接到一个已经运行的shell时,这就是我个人的"期望"。 如有必要,请随时关闭此问题,我只是觉得有必要记录并获得一些反馈。

如果您开始输入命令,而不是enter,则不会看到额外的空提示行。如果您运行

$ docker exec -it ubuntu <container-ID-or-name> bash 

<container-ID-or-name>是在运行docker run -it -d ubuntu后的容器ID或名称(在你的问题中为3aef6e642327或condescending_sammet),它将运行一个新命令,因此不会出现连接到现有命令时的“stdout问题”。

例子

如果您在目录中有一个包含以下内容的Dockerfile

FROM ubuntu:latest
ADD ./script.sh /timescript.sh 
RUN chmod +x /timescript.sh
CMD ["/timescript.sh"]

在同一目录下有一个简单的bash脚本script.sh,内容如下:

#!/bin/bash

#trap ctrl-c and exit, couldn't get out
#of the docker container once attached
trap ctrl_c INT
function ctrl_c() {
    exit
}

while true; do
    time=$(date +%N)
    echo $time;
    sleep  1;
done

然后使用以下命令在构建(在此示例中与Dockerfile和script.sh位于同一目录中)并运行它

$ docker build -t nan-xiao/time-test .
..stuff happening...
$ docker run -itd --name time-test nan-xiao/time-test

最终 attach
$ docker attach time-test

你将会附加到一个容器中,每秒钟打印出时间。(按下CTRL-C退出)
示例2
或者如果你有一个包含以下内容的Dockerfile:
FROM ubuntu:latest
RUN apt-get -y install irssi
ENTRYPOINT ["irssi"]

然后在同一目录下运行:
$ docker build -t nan-xiao/irssi-test .

然后运行它:
$ docker run -itd --name irssi-test nan-xiao/irssi-test

最后。
$ docker attach irssi-test

如果没有这种特定的行为,你会在一个正在运行的 irssi 窗口中结束。当然,你可以用另一个程序替换 irrsi。

你能帮我检查一下我的更新是否正确吗?非常感谢! - Nan Xiao
对我来说,最后一个“ls”在我开始输入时会重新打印提示符,但除此之外看起来很好。 - Francesco de Guytenaere
5
docker exec -t -i [container] /bin/bash 这个命令让我在终端中浏览容器的文件系统。 - Patrick
1
@FrancescodeGuytenaere,我认为你需要更改: $ docker exec -it ubuntu bash <container-ID-or-name> 为 $ docker exec -it ubuntu <container-ID-or-name> bash - daprezjer

7
当我运行docker attach container-name时,没有任何输出,即使按下Ctrl-c也无效。因此,首先尝试:
docker attach container-name --sig-proxy=false

然后使用 ctrl-c 可以停止它。为什么没有输出? 因为容器没有输出。实际上,我需要进入我的容器并运行一些 shell 命令。因此,正确的命令是:

docker exec -ti container-name bash

1
如果您有新的问题,请通过单击提问按钮来提出。如果它有助于提供上下文,请包含此问题的链接。- 来自审核 - rzelek
抱歉,我只是描述了我的情况。 - Billy Yang

1
这种情况曾经发生在我身上,原因如下:
容器内的bash命令可能正在执行一个"cat"命令。
因此,当你附加到容器(bash命令)时,实际上是在"cat"命令中,它正在等待输入(文本和/或ctrl-d来写文件)。

0

使用:docker exec -it CONTAINER_ID/NAME bash

替代方案:docker attach...


0

如果您无法访问命令行,请确保在启动容器时使用-i标志。


0

我今天遇到了类似的问题,但是我已经解决了:

以下是我的情况:

docker-compose logs -f nginx
Attaching to laradock_nginx_1

然后它会一直停在那里,直到我通过CTRL-C退出:^CERROR: Aborting.

docker ps -a 显示应该被称为 laradock_nginx 的内容没有使用该映像名称存在,因此我想我只需要删除并重新启动该容器:

docker stop cce0c32f7556
docker rm cce0c32f7556
docker-compose up -d laradock_nginx

不好意思:错误:没有此服务:laradock_nginx

所以我执行了sudo重启,然后执行了 docker ps -a,但 laradock_nginx 仍然不存在。

幸运的是,docker-compose up -d nginx 然后就能工作了,docker-compose logs -f nginx 现在也可以工作。


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