Вот команда, которая работает:
$ 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
опция -t
означает «Выделить псевдо-TTY», и я читалисторические обзоры того, что означает TTY, но это не помогло мне понять, какой именно договор здесь нарушен.
решение1
Поздний ответ, но может кому-то поможет
docker run/exec -i
соединит STDIN команды внутри контейнера с STDIN самого себя docker run/exec
.
Так
docker run -i alpine cat
дает вам пустую строку, ожидающую ввода. Введите "hello", и вы получите echo "hello". Контейнер не выйдет, пока вы не отправите CTRL+D, потому что основной процессcat
ждет ввода из бесконечного потока, который является конечным вводомdocker run
.- С другой стороны,
echo "hello" | docker run -i alpine cat
выведет «привет» и немедленно завершит работу, посколькуcat
заметит, что поток ввода закончился, и завершит себя.
Если вы попробуете docker ps
после выхода из любого из вышеперечисленных вариантов, вы не найдете ни одного запущенного контейнера. В обоих случаях cat
сам завершился, поэтому docker завершил контейнер.
Теперь о «-t», который сообщает основному процессу внутри Docker, что его входные данные — это терминальное устройство.
Так
docker run -t alpine cat
даст вам пустую строку, но если вы попытаетесь ввести "hello", вы не получите никакого эха. Это потому, что whilecat
подключен к терминальному входу, этот вход не подключен к вашему входу. "hello", который вы набрали, не достиг входаcat
.cat
ожидает ввода, который никогда не поступит.echo "hello" | docker run -t alpine cat
также выдаст вам пустую строку и не выйдет из контейнера по CTRL-D, но вы не получите echo "hello", потому что вы не передали-i
Если вы отправите CTRL+C, вы получите свою оболочку обратно, но если вы попробуете docker ps
сейчас, вы увидите, что cat
контейнер все еще работает. Это потому, что cat
он все еще ждет входной поток, который никогда не был закрыт. Я не нашел никакого полезного использования для -t
одного без объединения с -i
.
Теперь, для -it
вместе. Это говорит cat, что его вход является терминалом и в то же время подключает этот терминал к входу, docker run
который является терминалом. docker run/exec
убедится, что его собственный вход на самом деле является tty, прежде чем передать его в cat
. Вот почему вы получите , input device is not a TTY
если попробуете echo "hello" | docker run -it alpine cat
, потому что в этом случае вход docker run
сам по себе является каналом из предыдущего echo, а не терминалом, где docker run
выполняется
Наконец, зачем вам нужно передавать -t
if -i
will делать трюк с подключением вашего ввода к cat
вводу ? Это потому, что команды обрабатывают ввод по-разному, если это терминал. Это также лучше всего проиллюстрировано на примере
docker run -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -uroot -p
выдаст вам запрос на ввод пароля. Если вы введете пароль, символы будут напечатаны видимым образом.docker run -i alpine sh
даст вам пустую строку. Если вы введете команду, какls
вы получите вывод, но вы не получите приглашение или цветной вывод.
В последних двух случаях вы получаете такое поведение, поскольку mysql
мы shell
не обрабатываем входные данные как tty и, следовательно, не используем специфичное для tty поведение, такое как маскировка входных данных или раскрашивание выходных данных.
решение2
Этот ответпомогло мне осознать:
- по умолчанию (без опций neither
-i
)-t
контейнер Docker отправляет свой вывод только в STDOUT, - с
-i
опцией идет подключение к STDIN, -t
опция подключает драйвер интерфейса терминала, который работает поверх STDIN/STDOUT. И когда подключается драйвер терминала, связь с контейнером должна соответствоватьпротокол терминального интерфейса. Игра на струне не делает этого.
решение3
Tty указывает на то, что у вас есть терминал, то есть то, что предоставляется xterm или одним из многих интерфейсов командной строки Linux. Ему нужна клавиатура и связанный с ним интерфейс текстового вывода. Типичные причины, по которым это нужно, — поддержка цветного текстового вывода, обработка различных комбинаций клавиш (например, клавиш со стрелками) и возможность перемещать курсор по экрану.
Когда вы передаете команду в docker, как echo
показано в вашем примере, этот канал является входом, и у этого канала нет интерфейса tty, это просто поток текста. Попытка создать tty с этим потерпит неудачу, как указано в сообщении об ошибке.