I was working on a project that involved running a docker command as a systemd service. The docker command looked something like the following.
docker run -it \ foobar python3 -c 'import this; print(this)'
When I tried to start the systemd service I saw the following error.
Jan 27 18:37:37 host program: the input device is not a TTY
After some research, I found other people who had the same problem. Their solution was to remove the
-t option from the docker command. I tried it, and it worked. I submitted a pull request and my teammate asked what the difference between the two options was. I was a little embarrassed that I couldn’t explain it to him.
The documentation says
-i, –interactive Keep STDIN open even if not attacheddocker run –help
-t, –tty Allocate a pseudo-TTYdocker run –help
I learn best by doing. So I created a simple Dockerfile to test out these different options.
FROM python:3-slim CMD python
Then I built the image.
docker build -t dummy .
I ran the container in four different ways.
$ docker run dummy $ docker run -i dummy # .....waits for me to type something print('hello') # pressed Ctrl-D to signal End of Transmission hello $ docker run -t dummy Python 3.8.1 (default, Jan 3 2020, 22:55:55) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> ^C^Fexit ^D ^C # ... help! I cannot escape # because a psuedo-terminal has not been allocated $ docker run -it dummy Python 3.8.1 (default, Jan 3 2020, 22:55:55) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> KeyboardInterrupt >>> # I pressed Ctrl-C to kill the process
-i by itself tells docker to connect the terminal stdin to the container’s stdin.
$ docker run -i alpine sh ls /var cache empty lib local lock log mail opt run spool tmp
Notice there is no shell prompt. There is no pseudo-terminal, the alpine container is just using the stdin of its parent process. This is not user-friendly for interactive shell sessions inside containers.
-t tells the docker process that input is coming not only from stdin, but specifically a terminal device (aka your shell session), so it allocates a pseudo-terminal for the container.
$ docker run -it alpine sh / # ls /var cache empty lib local lock log mail opt run spool tmp / #
If you remove
-t from the
docker run command, you are telling docker that you don’t need a pseudo-terminal allocated for the container. You will still be able to type commands into it (for example, Ctrl-C will be read by the container if you want to kill it), but you won’t get a shell prompt.
This is a good post that helped me understand what’s going on.