当您使用-i 选项时,客户端(即docker 命令)会将自己附加到容器内命令的标准输入。如果您使用-t 选项,您也是attaching a terminal 的命令。当连接到终端时,某些程序的行为会有所不同。
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 命令的标准输入连接到docker run 命令的标准输入。
bash-3.2$ echo Hey | docker run -i ubuntu cat
Hey --> output from cat
这里,cat 命令的标准输入连接到docker run 的标准输入,它连接到echo 的标准输出。 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 的标准输入也必须是 tty。
不确定如果 cat 的 stdin 是 tty,它的行为是否会有所不同,但许多其他程序会这样做。示例:Some commands might hide the input when taking password input from a tty.
bash-3.2$ echo Hey | docker run -it ubuntu cat
the input device is not a TTY
docker run 命令的标准输入不是 tty。所以它不能连接到连接到cat命令的stdin的tty。
bash-3.2$ docker run -t ubuntu cat
Hey <-- input from my stdin. no output from cat
cat 命令的标准输入连接到 tty 就是这样。 docker run 命令的标准输入未连接到 cat,因为未使用 -i 选项。因此,即使您在标准输入中输入任何内容,它也不会到达 cat。
bash-3.2$ echo Hey | docker run -t ubuntu cat
cat 命令的标准输入连接到 tty 就是这样。 echo 的输出不会达到 cat。
这些如何使容器具有交互性?
客户端在/containers/{id}/attach 处向 docker 守护进程生成一个API call。然后这个 HTTP 连接是 hijacked 以通过底层套接字传输 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.
在客户端,来自流的数据是copied onto it's stdout 和it's stdin is copied onto the stream。