我经常使用这些命令行选项,在处理要与之交互的容器时,-i
和-t
。
-i, --stdin=false: Pass stdin to the container
-t, --tty=false: Stdin is a TTY
这些如何使容器具有交互性?
当您使用-i
选项时,客户端(即docker
命令(将自身附加到容器内命令的 stdin。如果使用-t
选项,则还会将终端附加到命令。某些程序在连接到终端时的行为不同。
bash-3.2$ docker run -i ubuntu cat
Hey <-- input from my stdin
Hey --> output from cat
Hello <-- input from my stdin
Hello --> output from cat
cat
命令的 stdin 连接到docker run
命令的 stdin。
bash-3.2$ echo Hey | docker run -i ubuntu cat
Hey --> output from cat
在这里,cat
命令的 stdin 连接到docker run
的 stdin,后者连接到echo
的 stdout 。 一旦 stdin 断开连接,docker run
就会退出。
bash-3.2$ docker run -it ubuntu cat
Hey <-- input from my stdin
Hey --> output from cat
cat
的标准连接到 tty 输入。这个tty连接到docker run
的标准。docker run
的 stdin 也必须是 tty。
不确定如果 stdin 是 tty,cat 的行为是否有任何不同,但许多其他程序会这样做。 示例:从 tty 获取密码输入时,某些命令可能会隐藏输入。
bash-3.2$ echo Hey | docker run -it ubuntu cat
the input device is not a TTY
docker run
命令的 stdin 不是 tty。因此,它无法连接到连接到cat
命令的 stdin。
bash-3.2$ docker run -t ubuntu cat
Hey <-- input from my stdin. no output from cat
cat
命令的 stdin 连接到 tty,仅此而已。docker run
命令的 stdin 未连接到cat
-i
因为未使用该选项。因此,即使您在标准中输入任何内容,它也不会达到cat
。
bash-3.2$ echo Hey | docker run -t ubuntu cat
cat
命令的 stdin 连接到 tty,仅此而已。echo
的输出不会达到cat
。
这些如何使容器具有交互性?
客户端在/containers/{id}/attach
时对 docker 守护程序进行 API 调用。然后,此HTTP连接被劫持,以通过底层套接字传输stdin
、stdout
和stderr
(取决于选项(。客户端和服务器使用此套接字进行双向流式处理。
根据是否启用 tty,流格式可能会有所不同。从 container_attach.go:
// If the container is using a TTY, there is only a single stream (stdout), and
// data is copied directly from the container output stream, no extra
// multiplexing or headers.
//
// If the container is *not* using a TTY, streams for stdout and stderr are
// multiplexed.
// The format of the multiplexed stream is as follows:
//
// [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT}
//
// STREAM_TYPE can be 1 for stdout and 2 for stderr
//
// SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded as big endian.
// This is the size of OUTPUT.
在客户端,流中的数据被复制到它的 stdout 上,它的 stdin 被复制到流上。