Что именно означает «устройство ввода не TTY» в выводе «Docker Run»?

18

Это команда, которая работает:

$ echo 'hi there' | docker run -i ubuntu cat
hi there

Эта команда отвечает сообщением об ошибке:

$ echo 'hi there' | docker run -it ubuntu cat
the input device is not a TTY

Я хотел бы выяснить, что именно здесь происходит. Не просто "удалить -t, и это будет исправлено".

Я знаю , что docker run«S -tопция означает„Выделяют псевдо-TTY“, и я читал исторические обзоры о том, что стоит TTY для , но это не помогло мне понять , какой вид договора нарушается здесь.

Михаил Васин
источник
Это не избыточно, докер может создать TTY, ничего к нему не прикрепляя. Ваш вывод будет содержать символы для цвета и т. Д., Но ваш вывод терминала не будет передан на вход контейнера. Таким образом, введенные вами символы будут поставлены в очередь для следующей команды, которую вы запускаете после выхода из команды docker.
BMitch
Могу ли я запустить tty в докере? У меня есть приложение, которое перестает работать -t, но я не запускаю докер , но не могу изменить команду запуска докера в рабочей среде. Поэтому мне нужно заставить приложение думать, что оно было начато -t.
Мворисек

Ответы:

9

Этот ответ помог мне обернуть голову:

  • по умолчанию (без параметров -iи -tпараметров) контейнер Docker отправляет свой вывод только в STDOUT,
  • с -iопцией приходит подключение к STDIN,
  • -tопция загружает драйвер интерфейса терминала , который работает поверх STDIN / STDOUT. А когда подключается драйвер терминала, связь с контейнером должна соответствовать протоколу интерфейса терминала . Обвязка строки не делает.
Михаил Васин
источник
7

Поздний ответ, но может помочь кому-то

docker run/exec -iсоединит STDIN команды внутри контейнера с STDIN docker run/execсамого.

Так

  • docker run -i alpine catвыдает пустую строку в ожидании ввода. Типа "привет", вы получаете эхо "привет". Контейнер не выйдет, пока вы не отправите CTRL + D, потому что основной процесс catожидает ввода из бесконечного потока, который является входом терминала для docker run.
  • С другой стороны echo "hello" | docker -i run alpine cat, выведите «hello» и немедленно catвыйдете, потому что замечает, что поток ввода закончился и завершает сам.

Если вы попытаетесь docker psпосле выхода из любого из вышеперечисленных, вы не найдете никаких работающих контейнеров. В обоих случаях catсамо завершение работы завершилось, поэтому docker завершил работу контейнера.

Теперь для "-t" это говорит главному процессу внутри докера, что его вход является терминальным устройством.

Так

  • docker run -t alpine catвыдаст пустую строку, но если вы попытаетесь напечатать "привет", вы не получите никакого эха. Это потому, что хотя catон подключен к входу терминала, этот вход не подключен к вашему входу. «Привет», который вы ввели, не дошел до ввода cat. catждет ввода, который никогда не поступит.
  • echo "hello" | docker run -t alpine cat также даст вам пустую строку и не выйдет из контейнера на CTRL-D, но вы не получите эхо "привет", потому что вы не прошли -i

Если вы отправите CTRL + C, вы вернете свою оболочку, но если вы попробуете docker psсейчас, вы увидите, что catконтейнер все еще работает. Это потому, что catвсе еще ожидает входной поток, который никогда не был закрыт. Я не нашел никакого полезного использования для -tодиночества, не будучи объединенным с -i.

Теперь -itвместе. Это говорит кошке, что ее вход является терминалом и в то же время подключите этот терминал к входу docker runкоторого является терминалом. docker run/execпрежде чем передать его, убедитесь, что его собственный ввод является tty cat. Вот почему вы получите, input device is not a TTYесли попытаетесь, echo "hello" | docker run -it alpine catпотому что в этом случае вход docker runсам по себе является каналом от предыдущего эха, а не терминалом, где docker runвыполняется

Наконец, зачем вам нужно проходить, -tесли вам нужно -iбудет соединить ваш вход catсо входом? Это потому, что команды обрабатывают ввод по-разному, если это терминал. Это также лучше всего иллюстрируется на примере

  • docker run -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -uroot -pдаст вам запрос пароля. Если вы введете пароль, символы будут напечатаны визуально.
  • docker run -i alpine shдаст вам пустую строку. Если вы наберете команду, как lsвы получите вывод, но вы не получите приглашение или цветной вывод.

В последних двух случаях вы получаете это поведение, потому mysqlчто вы shellне обрабатываете ввод как tty и, следовательно, не используете специфическое для tty поведение, такое как маскирование ввода или окрашивание вывода.

Ахмед Гоним
источник
4

Tty указывает, что у вас есть терминал, который будет предоставлен xterm или одним из многих интерфейсов командной строки linux. Требуется клавиатура и связанный с ним интерфейс вывода текста. Типичные причины для этого - поддержка вывода цветного текста, обработка различных комбинаций клавиш (например, клавиш со стрелками) и возможность перемещать курсор по экрану.

Когда вы передаете команду в docker, как echoпоказано в вашем примере, этот канал является входным, а этот канал не имеет интерфейса tty, это просто поток текста. Попытка создать tty с этим потерпит неудачу, как указывает сообщение об ошибке.

BMitch
источник
См. Также: stackoverflow.com/a/43099210/596285
BMitch
Для меня все еще есть разрыв между «клавиатурой и выходным интерфейсом» и «STDIN / STDOUT». Очевидно, что вы не можете применить концепцию «положение курсора» к STDOUT, так как STDOUT - это поток, а не экран. Какие спецификации описывают абстракцию выходного интерфейса, которая (я думаю, есть) поверх STDOUT?
Михаил Васин
1
Это интерфейс, который работает поверх stdin / stdout. ru.wikipedia.org/wiki/POSIX_terminal_interface
BMitch