這是一個有效的命令:
$ echo 'hi there' | docker run -i ubuntu cat
hi there
這是一條回應錯誤訊息的命令:
$ echo 'hi there' | docker run -it ubuntu cat
the input device is not a TTY
我想弄清楚這裡究竟發生了什麼事。不僅僅是「刪除-t,它就會被修復」。
我知道docker run
's-t
選項代表“分配偽 TTY”,並且我已閱讀TTY 代表的歷史概述,但這並沒有幫助我理解這裡違反了什麼樣的合約。
答案1
遲到的回答,但可能對某人有幫助
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」沒有到達 的輸入cat
。cat
正在等待永遠不會到達的輸入。echo "hello" | docker run -t alpine cat
也會給你一個空行,並且不會在 CTRL-D 上退出容器,但你不會得到回顯“hello”,因為你沒有通過-i
如果您發送 CTRL+C,您會取回 shell,但如果您docker ps
現在嘗試,您會看到cat
容器仍在運行。這是因為cat
仍在等待從未關閉的輸入流。我還沒有發現單獨使用-t
而不與 結合使用有任何有用的用途-i
。
現在,為了-it
在一起。這告訴 cat 它的輸入是一個終端,同時將該終端連接到其輸入docker run
是一個終端。docker run/exec
在將其傳遞給 之前,將確保其自己的輸入實際上是一個 tty cat
。這就是為什麼你會得到一個input device is not a TTY
if you tryecho "hello" | docker run -it alpine cat
因為在這種情況下,它本身的輸入是來自前一個 echo 的管道,而不是執行的docker run
終端docker run
最後,為什麼你需要傳遞-t
if -i
will 來完成將你的輸入連接到 的輸入的技巧cat
?這是因為如果輸入是終端,命令會以不同的方式處理輸入。這也可以透過範例得到最好的說明
docker run -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -uroot -p
會給你一個密碼提示。如果您輸入密碼,字元就會清楚列印出來。docker run -i alpine sh
會給你一個空白行。如果您鍵入命令,就像您ls
得到輸出一樣,但您不會得到提示或彩色輸出。
在最後兩種情況下,您會得到此行為,因為mysql
我們shell
沒有將輸入視為 tty,因此沒有使用 tty 特定行為,例如屏蔽輸入或為輸出著色。
答案2
答案3
tty 表示您有一個終端,它是由 xterm 或眾多 Linux 命令列介面之一提供。它需要一個與之關聯的鍵盤和文字輸出介面。想要這樣做的典型原因是支援彩色文字輸出、處理各種組合鍵(如箭頭鍵)以及在螢幕上移動遊標的能力。
當您像echo
範例所示將命令透過管道傳輸到 docker 時,該管道是輸入,且該管道沒有 tty 接口,它只是一個文字流。嘗試使用該命令建立 tty 將失敗,如錯誤訊息所示。