对Docker -t选项分配伪TTY感到困惑


206

此选项的作用是什么?我已经阅读了很多有关TTY的文章,但仍然感到困惑。我试过没有-t和正义-i,似乎期望用户输入的程序如果没有则抛出错误-t。启用伪TTY为何很重要?

Answers:


223

-t选项进入Unix / Linux中如何处理终端接入。过去,终端是硬线连接,后来是基于调制解调器的连接。这些具有物理设备驱动程序(它们是真正的设备)。一旦通用网络开始使用,便会开发出伪终端驱动程序。这是因为它创造了解什么,而不需要将它写入到你的程序直接(阅读手册页使用终端能力之间的分离sttycurses)。

因此,以此为背景,运行一个没有选项的容器,并且默认情况下,您有一个stdout流(如此docker run | <cmd>工作);运行-i,您将添加stdin流(如此<cmd> | docker run -i工作);使用-t,通常结合使用,-it并添加了一个终端驱动程序,如果您要与该流程进行交互,则很可能需要该驱动程序。它基本上使容器启动看起来像一个终端连接会话。


7
这应该是最佳答案。尽管这里不是最技术性的,但它说明了-it标志的基本行为。
克里斯·海拉

1
同意克里斯。我读了其他答案,但仍然很困惑。这个答案将其清除。
李·本

3
是的,也许值得一提的是,“ TTY”本身是“ teletypewriter”(又名“ teleprinter”)一词的缩写,该词是设备的名称,允许您同时键入文本并发送出去,例如电话文本;-)尝试一下docker run -i ubuntudocker run -it ubuntu您会立即发现差异。“ -i”使您可以让容器等待主机的交互,但是在使用标志“ -t”“分配tty驱动程序”之后,可以从控制台(终端)进行实际交互。
Zegar

我可以在docker中启动tty吗?我有一些停止运行的应用程序,我没有使用来运行docker -t,但是我无法在生产中修改docker start命令。因此,我需要使该应用程序认为它始于-t
mvorisek

97

答案较晚,但可能对某人有帮助

docker run/exec -i会将容器内命令的STDIN连接到容器docker run/exec本身的STDIN 。

所以

  • docker run -i alpine cat给您空行等待输入。输入“ hello”,您将得到回声“ hello”。除非您发送CTRL+,否则容器不会退出,D因为主进程cat正在等待来自无限流(即的终端输入)的输入docker run
  • 另一方面,echo "hello" | docker run -i alpine cat将显示“ hello”并立即退出,因为会cat注意到输入流已结束并自行终止。

如果您docker ps在退出以上任何一种方法后尝试,则将找不到任何正在运行的容器。在这两种情况下,cat其自身都已终止,因此docker已终止了该容器。

现在,对于“ -t”,它告诉docker内部的主要过程其输入是终端设备。

所以

  • docker run -t alpine cat会给您空行,但是如果您尝试键入“ hello”,则不会得到任何回显。这是因为当cat连接到终端输入时,此输入未连接到您的输入。您输入的“ hello”未达到的输入catcat正在等待永远不会到达的输入。
  • echo "hello" | docker run -t alpine cat也会给您空行,并且不会退出容器CTRL- D但是您不会收到回声“ hello”,因为您没有通过-i

如果发送CTRL+ C,则返回外壳,但是如果现在尝试docker ps,则看到cat容器仍在运行。这是因为cat仍在等待从未关闭的输入流。如果未-t与结合使用,我还没有发现任何有用的用途-i

现在,为了-it在一起。这告诉cat它的输入是端子,同时将此端子连接到其输入docker run是端子。docker run/exec在将自己的输入传递到之前,将确保它的输入实际上是tty cat。这就是为什么input device is not a TTY尝试时会得到a的echo "hello" | docker run -it alpine cat原因,因为在这种情况下,其docker run自身的输入是来自先前回显的管道,而不是docker run执行终端

最后,-t如果-i要执行将输入连接到输入的技巧,您为什么需要通过cat?这是因为如果命令是终端,则命令对输入的处理会有所不同。这也是最好的例子

  • docker run -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -u root -p会提示您输入密码。如果您键入密码,则字符将被清晰地打印出来。
  • docker run -i alpine sh给你一个空行。如果键入类似的命令,ls则会得到输出,但不会得到提示或彩色输出。

在后两种情况下,您会得到这种行为,因为mysql并且shell没有将输入视为tty,因此没有使用tty特有的行为,例如掩盖输入或为输出着色。


6
最好的答案真正使我了解确切的功能-t-i选项!
Ruslan Stelmachenko,

1
神奇的答案预料到我会遇到的每个问题
James Machin

@Ahmed Ghonim,很好的答案。谢谢。但是关于“这是因为如果是终端,命令会以不同的方式对待输入”,我认为这是一种误解,对吗?应该是“这是因为如果不是终端,命令会以不同的方式对待输入”,对吗?
tuq

@艾哈迈德·格尼姆(Ahmed Ghonim)。晶莹剔透。但是docker run -a = stdin高山猫呢?
HKIT

1
@HKIIT“ -a = stdin”将stdin流附加到容器,但不分配内存。是-i标志在容器中为stdin流分配缓冲内存,因此,当传递-i时,无论附加标志如何,都将为stdin分配内存,从而描述“即使没有连接也保持STDIN打开”。没有此分配的内存,对stdin的读取为空/ eof。另外,您还需要包括“ -a = stdout”以查看来自cat命令的响应,例如:“ docker run -i -a = stdin -a = stdout高山猫” ...当然,不需要这样做只需运行“ docker run -i高山猫”。
David D

71

-t根据Google搜索,该论据没有得到很好的证明,或者被很多人经常提及。

当您通过docker在Bash提示符(最新版本为1.8.1)中键入(应为)所有Docker客户端参数的列表时,它甚至都不会显示。

实际上,如果您尝试通过键入docker -t --helpif 来获得有关此参数的特定帮助,则会给出以下令人惊讶的模糊答复:

提供但未定义的标志:-t

因此,您不会因对此争论感到困惑而受到指责!

在Docker在线文档中有提到,它是“分配一个伪tty”,通常用于-i

https://docs.docker.com/reference/run/

jwilder/nginx-proxy以下列方式在很棒的docker容器的文档中看到了它:

docker run -d -p 80:80 --name nginx -v /tmp/nginx:/etc/nginx/conf.d -t nginx

在这种情况下,它要做的是将输出发送到该Docker容器内的“虚拟” tty(Bash命令提示符/终端)。然后,您可以通过运行命令泊坞窗看到这个输出docker logs CONTAINER这里CONTAINER是第一对夫妇的这个集装箱的ID的人物。可以通过键入以下内容找到该容器IDdocker ps -a

我看过-t以下链接中简要提到的这个论点,它说

-t-i标志分配一个伪终端,并保持开放的标准输入即使没有连接。只要运行bash提示,您就可以像使用传统VM一样使用容器。

https://coreos.com/os/docs/latest/getting-started-with-docker.html

我希望这有帮助!我不确定为什么没有对此进行记录或使用过多。也许它是实验性的,并将在即将发布的版本中作为文档功能实现。


21
该文档显示的是docker run --help,不是docker -t --help-t, --tty=false Allocate a pseudo-TTY
bskaggs

5

我所知道的-t是以下内容:

docker exec -ti CONTAINER bash-允许我“登录”容器。感觉像是在摇晃(不是)。

但是麻烦是当我想还原数据库时。

通常我会做docker exec -ti mysql.5.7 mysql-在这里,我在容器中执行mysql命令并获得一个交互式终端。

我已添加<dump.sql到上一个命令,因此可以还原数据库。但是失败了cannot enable tty mode on non tty input

删除-t帮助。还是不明白为什么:

docker exec -i mysql.5.7 mysql < dump.sql

最后一个作品。希望这对人们有所帮助。


我可以在docker中启动tty吗?我有一些停止运行的应用程序,我没有使用来运行docker -t,但是我无法在生产中修改docker start命令。因此,我需要使该应用程序认为它始于-t
mvorisek

1

在linux中,当您运行命令时,需要一个终端(tty)来执行它。

因此,当您要连接到docker(或在docker容器中运行命令)时,必须提供选项-t,该选项考虑了docker容器内的终端。


0

每个进程都有三个数据流,即STDIN/ STDOUT/ STDERR。当容器中正在运行进程时,默认情况下,将终端与容器中正在运行的进程的STDOUT流连接。因此docker run,在终端中运行命令时,所有输出流都是可见的。但是,如果要向容器中正在运行的进程提供输入,则必须连接进程的STDIN通道,这不是默认设置,而是通过docker run -i命令完成的。

-t 用于交互式/格式化输入操作。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.