1

recently I learned something about using tty in docker.

I run a shell script in a docker container and want to read from stdin to provide something interactively when attached to the container. If you just use the command read -p "> " -r line you will get 100% cpu load, if there is no tty connected to the docker container.

To understand what's going on, let's have a look at the following. Run a bash script in a docker container as main process, which executes the command:

lsof -c bash

Depending on how you run the container you get following output:

docker run mycontainer

bash      7 root    0u   CHR    1,3      0t0        6 /dev/null
bash      7 root    1w  FIFO   0,13      0t0   392981 pipe
bash      7 root    2w  FIFO   0,13      0t0   392982 pipe

stdin is connected to /dev/null, which cause 100% cpu load on the read command.


docker run -i mycontainer

bash      7 root    0r  FIFO   0,13      0t0   398965 pipe
bash      7 root    1w  FIFO   0,13      0t0   398966 pipe
bash      7 root    2w  FIFO   0,13      0t0   398967 pipe

the host stdin is connected to the container stdin, but there is no tty.


docker run -t mycontainer

bash      8 root    0u   CHR  136,0      0t0        3 /dev/pts/0
bash      8 root    1u   CHR  136,0      0t0        3 /dev/pts/0
bash      8 root    2u   CHR  136,0      0t0        3 /dev/pts/0

stdin, stdout, stderr are connected to a tty, but the host stdin is not connected, typing commands is not possible.


docker run -it mycontainer

bash      8 root    0u   CHR  136,0      0t0        3 /dev/pts/0
bash      8 root    1u   CHR  136,0      0t0        3 /dev/pts/0
bash      8 root    2u   CHR  136,0      0t0        3 /dev/pts/0

stdin, stdout, stderr are connected to a tty and the host stdin is connected.


Check if connected to a tty

Here are some code, I found around the internet.

if tty -s
then
  echo "Terminal connected."
else
  echo "No Terminal connected."
fi

This is true as long the option -t is given. I think to check if option -i was given on the docker run command is not possible.


if [ -t 0 ]; then
    echo "stdin is connected to a terminal."
fi

if [ -t 1 ]; then
    echo "stout is connected to a terminal."
fi

if [ -t 2 ]; then
    echo "stderr is connected to a terminal."
fi

This checks everything separate.


Furthermore it is possible to check for a pipe:

if [[ -p /dev/stdin ]] ; then
    echo "stdin is coming from a pipe"
fi
if [[ -t 0 ]] ; then
    echo "stdin is coming from the terminal"
fi
if [[ ! -t 0 && ! -p /dev/stdin ]] ; then
    echo "stdin is redirected"
fi

Interactive Shell with docker-compose

https://stackoverflow.com/a/39150040/17875203

version: "3"
services:
  app:
    image: app:1.2.3
    stdin_open: true # docker run -i
    tty: true        # docker run -t
    

0 Answers0