The best answers to the question “Confused about Docker -t option to Allocate a pseudo-TTY” in the category Dev.
What exactly does this option do? I’ve been reading a lot on TTY and I’m still confused. I played around without having the
-t and just
-i and it seems like programs that expect user input throw an error without the
-t. Why is it important for pseudo-TTY to be enabled?
Late answer, but might help someone
docker run/exec -i will connect the STDIN of the command inside the container to the STDIN of the
docker run/exec itself.
docker run -i alpine catgives you an empty line waiting for input. Type “hello” you get an echo “hello”. The container will not exit until you send CTRL+D because the main process
catis waiting for input from the infinite stream that is the terminal input of the
- On the other hand
echo "hello" | docker run -i alpine catwill print “hello” and exit immediately because
catnotices that the input stream has ended and terminates itself.
If you try
docker ps after you exit either of the above, you will not find any running containers. In both cases,
cat itself has terminated, thus docker has terminated the container.
Now for “-t”, this tells the main process inside docker that its input is a terminal device.
docker run -t alpine catwill give you an empty line, but if you try to type “hello”, you will not get any echo. This is because while
catis connected to a terminal input, this input is not connected to your input. The “hello” that you typed did not reach the input of
catis waiting for input that never arrives.
echo "hello" | docker run -t alpine catwill also give you an empty line and will not exit the container on CTRL–D but you will not get an echo “hello” because you didn’t pass
If you send CTRL+C, you get your shell back, but if you try
docker ps now, you see the
cat container still running. This is because
cat is still waiting on an input stream that was never closed. I have not found any useful use for the
-t alone without being combined with
-it together. This tells cat that its input is a terminal and in the same time connect this terminal to the input of
docker run which is a terminal.
docker run/exec will make sure that its own input is in fact a tty before passing it to
cat. This is why you will get a
input device is not a TTY if you try
echo "hello" | docker run -it alpine cat because in this case, the input of
docker run itself is the pipe from the previous echo and not the terminal where
docker run is executed
Finally, why would you need to pass
-i will do the trick of connecting your input to
cat‘s input? This is because commands treat the input differently if it’s a terminal. This is also best illustrated by example
docker run -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -u root -pwill give you a password prompt. If you type the password, the characters are printed visibly.
docker run -i alpine shwill give you an empty line. If you type a command like
lsyou get an output, but you will not get a prompt or colored output.
In the last two cases, you get this behavior because
mysql as well as
shell were not treating the input as a tty and thus did not use tty specific behavior like masking the input or coloring the output.
-t option goes to how Unix/Linux handles terminal access. In the past, a terminal was a hardline connection, later a modem based connection. These had physical device drivers (they were real pieces of equipment). Once generalized networks came into use, a pseudo-terminal driver was developed. This is because it creates a separation between understanding what terminal capabilities can be used without the need to write it into your program directly (read man pages on
So, with that as background, run a container with no options and by default you have a stdout stream (so
docker run | <cmd> works); run with
-i, and you get stdin stream added (so
<cmd> | docker run -i works); use
-t, usually in the combination
-it and you have a terminal driver added, which if you are interacting with the process is likely what you want. It basically makes the container start look like a terminal connection session.
What I know about the
-t is the following:
docker exec -ti CONTAINER bash – allows me to “login” in the container. It feels like ssh-ing (it’s not).
But the trouble was when I wanted to restore a database.
Usually I do
docker exec -ti mysql.5.7 mysql – Here I execute the mysql command in the container and get an interactive terminal.
<dump.sql to the previous command so I can restore a db. But it failed with
cannot enable tty mode on non tty input.
-t helped. Still don’t understand why:
docker exec -i mysql.5.7 mysql < dump.sql
The last one works. Hope this helps people.
-t argument is NOT documented well, or mentioned by many people often, according to a Google search.
It doesn’t even show up when you display a list of (what should be) all docker client arguments by typing
docker at the Bash prompt (with the latest version of 1.8.1).
In fact, if you try to get specific help about this argument by typing
docker -t --help if gives this amazingly vague reply:
flag provided but not defined: -t
So, you can’t be blamed for being confused about this argument!
There is a mention in the Docker online documentation which says it is to “Allocate a pseudo-tty” and is often used with
I saw it used in the documentation for the terrific
jwilder/nginx-proxy docker container in the following way:
docker run -d -p 80:80 --name nginx -v /tmp/nginx:/etc/nginx/conf.d -t nginx
In this case, what it does is send the output to the ‘virtual’ tty (Bash command prompt/terminal) within this docker container. You can then see this output by running the docker command
docker logs CONTAINER where
CONTAINER is the first couple of characters of this container’s ID. This CONTAINER ID can be found by typing
docker ps -a
I’ve seen this
-t argument mentioned briefly in the following link, where it says
-iflags allocate a pseudo-tty and keep stdin open even
if not attached. This will allow you to use the container like a
traditional VM as long as the bash prompt is running.
I hope this helps! I’m not sure why this isn’t documented or used much. Maybe it’s experimental and will be implemented as a documented feature in upcoming versions.