When you use -i
option, the client (i.e., docker
command) is attaching itself to the stdin of the command inside the container. If you use -t
option, you are also attaching a terminal to the command. Some programs behave differently when connected to 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
command's stdin is connected to docker run
command's stdin.
bash-3.2$ echo Hey | docker run -i ubuntu cat
Hey --> output from cat
Here, the stdin of cat
command is connected to stdin of docker run
which is connected to stdout of echo
. docker run
exits as soon as the stdin is disconnected.
bash-3.2$ docker run -it ubuntu cat
Hey <-- input from my stdin
Hey --> output from cat
The stdin of cat
is connected to a tty input. This tty is connected to stdin of docker run
. stdin of docker run
must also be a tty.
Not sure if cat behaves any differently if it's stdin is tty, but many other programs do. Example: 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
command's stdin is not a tty. So it cannot be connected to tty connected to cat
command's stdin.
bash-3.2$ docker run -t ubuntu cat
Hey <-- input from my stdin. no output from cat
cat
command's stdin is connected to tty and that's it. docker run
command's stdin is NOT connected to the cat
because -i
option is not used. So even you type anything into your stdin, it won't reach cat
.
bash-3.2$ echo Hey | docker run -t ubuntu cat
cat
command's stdin is connected to tty and that's it. Output of echo
won't reach cat
.
How do these work for making the containers interactive?
Client makes an API call at /containers/{id}/attach
to the docker daemon. This HTTP connection is then hijacked to transport the stdin
, stdout
, and stderr
(depending on options) over the underlying socket. Client and server use this socket for bidirectional streaming.
Depending on whether tty is enabled, the stream format might vary. From 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.
On the client side, the data from stream is copied onto it's stdout and it's stdin is copied onto the stream.