如何进入已经使用新 TTY 运行的 Docker 容器
Posted
技术标签:
【中文标题】如何进入已经使用新 TTY 运行的 Docker 容器【英文标题】:How to enter in a Docker container already running with a new TTY 【发布时间】:2014-01-22 19:37:09 【问题描述】:我有一个在前台运行 Apache 服务的容器。我希望能够从另一个外壳访问容器,以便在其中“四处探查”并检查文件。目前,如果我附加到容器,我只能查看 Apache 守护进程并且无法运行任何命令。
是否可以将另一个 tty 附加到正在运行的容器?也许,我可以利用 Docker 实际上只是包装 LXC 容器这一事实?我已经尝试过sudo lxc-console -n [container-id] -t [1-4]
,但似乎只有一个 tty 可用,那就是运行 apache 守护程序的那个。也许有办法在构建期间启用多个 lxc 控制台?
如果可能,我宁愿不使用 openssh 服务配置和构建容器。
【问题讨论】:
你试过docker attach [conainer-id]
吗?
@shabbychef 除非 docker attach 已更改,否则 attach 命令附加到正在运行的 tty,而不是新的,因此问题标题是“...with new TTY”。这就是为什么下面的答案不使用附加命令的原因。
从 1.3 开始,有一种更简单的方法,如 this answer 所述
【参考方案1】:
在 docker 1.3 中,有一个新命令 docker exec
。这允许你进入一个正在运行的容器:
docker exec -it [container-id] bash
注意:这假设bash
已安装在您的容器上。您可以运行 sh
或容器上安装的任何交互式 shell。
【讨论】:
我已将其更改为正确答案(来自我自己的),因为这种新方法在提出问题时并不存在,是目前最好的 IMO 方法。 但是请注意exec
不能作为普通终端。例如,您不能在容器内更改用户。
@Pithikos:我可以使用 exec 运行 shell,然后使用 su someuser
更改用户。运行 Docker 1.4.1
请注意阅读此讨论的任何人。我敢肯定docker exec -it
最终会提供一个功能齐全的伪 tty,但是目前(Docker 版本 1.9.1)还有一些不足:github.com/docker/docker/issues/8755
如果你得到错误 'exec: "bash": executable file not found in $PATH' 你可以试试这个:docker exec -it [container-id] /bin/sh【参考方案2】:
您应该使用 Jérôme Petazzoni 的名为“nsenter”的工具进入容器,而不使用 SSH。见:https://github.com/jpetazzo/nsenter
只需运行即可安装:docker run -v /usr/local/bin:/target jpetazzo/nsenter
然后使用命令docker-enter <container-id>
进入容器。
【讨论】:
这是正确的方法。见blog。 在 docker 1.3 中,有一个新命令docker exec
。这允许您输入正在运行的 docker:docker exec -it <container-id> bash
(请参阅下面的答案)
docker-enter
还存在吗?它给了我command not found
。【参考方案3】:
更新
从 docker 0.9 开始,要使以下步骤生效,现在必须在重新启动守护程序之前将带有 '-e lxc'
的 /etc/default/docker
文件更新为 docker 守护程序启动选项(我通过重新启动主机来完成此操作) .
这都是因为……
...它 [docker 0.9] 包含一个新的“引擎驱动程序”抽象,使使用成为可能 LXC 以外的其他 API 来启动容器。它还提供了一个新的 基于新 API 库 (libcontainer) 的引擎驱动程序 在不使用 LXC 工具的情况下处理控制组。主要问题是 如果您依靠 lxc-attach 对您的 容器,就像在容器内启动一个外壳,它是 对开发环境非常有用...
source
请注意,这将阻止新的host only networking optional feature of docker 0.11“工作”,您只会看到环回接口。 bug report
原来a different question的解决方案也是这个解决方案:
...您可以使用 docker
ps -notrunc
获取完整的 lxc 容器 ID 和 然后使用lxc-attach -n <container_id>
在该容器中运行 bash 作为 根。
更新:您很快将需要使用 ps --no-trunc
而不是已弃用的 ps -notrunc
。
查找完整的容器 ID
输入 lxc attach 命令。
顶部显示了运行 docker 启动的我的 apache 进程。
【讨论】:
那么,仅使用 Docker 是无法做到这一点的,对吧?我个人不喜欢自己混入 LXC。 有没有办法用 lxc-attach 运行命令来启动 bash?谢谢!! @qkrijger 据我所知这是正确的。为什么担心“混合”LXC?你知道 docker 是建立在 LXC 之上的吧? @joselo 我不明白你的问题,但我建议你创建一个更详细的新帖子?启动 docker 进程的方法有很多,例如使用 bash 或作为守护进程使用 -d 等。 @programster 是的,我意识到 :) 尽管如此,直接将 LXC 与 Docker 结合使用感觉就像是在黑客攻击。有趣,但不是真正可维护的。一般来说,应该在自己选择工作的抽象层中编码。如果你真的需要 LXC 本身,可能是时候在 Docker 上提出拉取请求了:)【参考方案4】:第一步获取容器id:
docker ps
这会告诉你类似的东西
容器 ID 图像命令创建状态端口名称
1170fe9e9460 localhost:5000/python:env-7e847468c4d73a0f35e9c5164046ad88 "./run_notebook.sh" 26 秒前 Up 25 seconds 0.0.0.0:8989->9999/tcp SLURM_TASK-303337_0
1170fe9e9460
是本例中的容器 ID。
第二,进入docker:
docker exec -it [container_id] bash
所以在上述情况下:
docker exec -it 1170fe9e9460 bash
【讨论】:
【参考方案5】:在容器中运行 tmux/GNU Screen 怎么样? 使用简单的方法似乎可以更顺畅地访问任意数量的 vty:
$ docker attach container id
【讨论】:
如果你知道你想要访问一个容器(例如调试它),这是一个不错的解决方案,但这不会帮助 OP 声明他们想要查看现有的容器。 我对这个答案的问题是人们已经询问过使用docker attach
,我指出:...the attach command attaches to the running tty, not a new one, hence the question title is "...with new TTY"
好吧,如果容器已经在运行,这个解决方案对你没有帮助,但如果你以前注意让多路复用器运行,你就不需要额外的 tty... 事实上因为我开始使用 tmux,我使用一个 tty,并且只使用一个来完成我需要的一切,因为一旦进入 tmux,我就可以生成任意数量的 vty。【参考方案6】:
docker exec -ti 'CONTAINER_NAME' sh
or
docker exec -ti 'CONTAINER_ID' sh
【讨论】:
【参考方案7】:nsenter
这样做。但是,我还需要以一种简单的方式输入一个容器,而 nsenter 并不能满足我的需要。在某些情况下它是错误的(黑屏加上 -wd 标志不起作用)。此外,我想以特定用户身份登录特定目录。
我最终制作了自己的工具来进入容器。您可以在以下位置找到它:https://github.com/Pithikos/docker-enter
它的使用很简单
./docker-enter [-u <user>] [-d <directory>] <container ID>
【讨论】:
刚试过,很酷!在 ubuntu 上必须运行 sudo apt-get build-essential -y gcc docker-enter.c -o docker-enter sudo ./docker-enterdocker exec -t -i container_name /bin/bash
将带您进入容器控制台。
【讨论】:
我遇到了这个问题,因为我遇到了同样的问题。在我修改之前,看起来相似的答案对我不起作用。不过我可以删除它。【参考方案9】:“nsinit”方式是:
安装 nsinit
git clone git@github.com:dotcloud/docker.git
cd docker
make shell
从容器内部:
go install github.com/dotcloud/docker/pkg/libcontainer/nsinit/nsinit
从外面:
docker cp id_docker_container:/go/bin/nsinit /root/
使用它
cd /var/lib/docker/execdriver/native/<container_id>/
nsinit exec bash
【讨论】:
【参考方案10】:我在作为守护进程运行的 microsoft/iis 上启动了 powershell 使用
docker exec -it <nameOfContainer> powershell
【讨论】:
看起来好像问题是关于基于 linux 的容器。仅当您拥有基于 Windows 的容器或安装了 .NET Core 版本的 PowerShell 时,此答案才可能有效,例如PowerShell 6 或更高版本。【参考方案11】:在 Windows 10 上,我安装了 docker。我在容器上运行 Jnekins,但遇到了相同的错误消息。以下是解决此问题的分步指南:
第 1 步: 打开 gitbash 并运行 docker run -p 8080:8080 -p 50000:50000 jenkins。
第 2 步:打开一个新终端。
第 3 步: 执行“docker ps”以获取正在运行的容器的列表。复制容器 id。
第 4 步: 现在,如果您执行“docker exec -it container id sh”或“docker exec -it container id bash”,您将收到类似于“输入设备不是 TTY。如果您使用的是 mintty,请尝试在命令前加上 'winpty'"
第五步:运行命令“$winpty docker exec -it container id sh”
伏拉!!你现在在终端里面。
【讨论】:
以上是关于如何进入已经使用新 TTY 运行的 Docker 容器的主要内容,如果未能解决你的问题,请参考以下文章
使用 grunt-shell 调用调用 docker run 的脚本时如何解决“输入设备不是 TTY”?