这是一个有效的命令:
$ echo 'hi there' | docker run -i ubuntu cat
hi there
Run Code Online (Sandbox Code Playgroud)
这是一条响应错误消息的命令:
$ echo 'hi there' | docker run -it ubuntu cat
the input device is not a TTY
Run Code Online (Sandbox Code Playgroud)
我想弄清楚这里到底发生了什么。不仅仅是“删除 -t 它将被修复”。
我知道docker run
's-t
选项代表“分配伪 TTY”,我已经阅读了 TTY 代表什么的历史概述,但这并没有帮助我理解这里违反了什么样的合同。
小智 15
迟到的答案,但可能会帮助某人
docker run/exec -i
将容器内命令的 STDIN 连接到docker run/exec
自身的 STDIN 。
所以
docker run -i alpine cat
给你一个等待输入的空行。输入“你好”你会得到一个回声“你好”。在您发送 CTRL+D 之前,容器不会退出,因为主进程cat
正在等待来自无限流的输入,该无限流是docker run
.echo "hello" | docker -i run alpine cat
将打印“hello”并立即退出,因为cat
注意到输入流已结束并自行终止。如果您docker ps
在退出上述任何一个后尝试,您将找不到任何正在运行的容器。在这两种情况下,cat
本身都已终止,因此 docker 已终止容器。
现在对于“-t”,它告诉 docker 内的主进程它的输入是一个终端设备。
所以
docker run -t alpine cat
会给你一个空行,但如果你尝试输入“hello”,你不会得到任何回声。这是因为虽然cat
连接到终端输入,但此输入未连接到您的输入。您输入的“hello”没有到达cat
. cat
正在等待永远不会到达的输入。echo "hello" | docker run -t alpine cat
也会给你一个空行,不会在 CTRL-D 上退出容器,但你不会得到回声“你好”,因为你没有通过 -i
如果你发送 CTRL+C,你会得到你的 shell,但是如果你docker ps
现在尝试,你会看到cat
容器仍在运行。这是因为cat
仍在等待从未关闭的输入流。如果不-t
与-i
.
现在,为了-it
在一起。这告诉 cat 它的输入是一个终端,同时将这个终端连接到docker run
一个终端的输入。docker run/exec
将确保它自己的输入实际上是一个 tty,然后将它传递给cat
. 这就是为什么你会得到 ainput device is not a TTY
如果你尝试,echo "hello" | docker run -it alpine cat
因为在这种情况下,docker run
它本身的输入是来自前一个 echo 的管道,而不是docker run
执行的终端
最后,为什么你需要通过-t
if-i
将你的输入连接到cat
's input的技巧?这是因为如果输入是终端,命令会以不同的方式处理输入。这也最好通过例子来说明
docker run -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -uroot -p
会给你一个密码提示。如果您输入密码,字符会被清晰地打印出来。docker run -i alpine sh
会给你一个空行。如果您键入命令,就像ls
得到输出一样,但不会得到提示或彩色输出。在最后两种情况下,您会得到这种行为,因为mysql
它shell
没有将输入视为 tty,因此没有使用 tty 特定行为,例如屏蔽输入或为输出着色。