Запутался в опции Docker -t для выделения псевдо-TTY

209

Что именно делает эта опция? Я много читал на TTY и все еще в замешательстве. Я играл с отсутствием -tи просто, -iи кажется, что программы, которые ожидают пользовательского ввода, выдают ошибку без -t. Почему важно включить псевдо-TTY?

user1099123
источник

Ответы:

225

-tВариант идет к тому, как Unix / Linux обрабатывает терминальный доступ. В прошлом терминал был жестким соединением, позже модемным соединением. У них были драйверы для физических устройств (они были настоящими частями оборудования). Как только обобщенные сети начали использоваться, был разработан драйвер псевдо-терминала. Это потому, что это создает разделение между пониманием того, какие возможности терминала можно использовать, без необходимости записывать их непосредственно в вашу программу (читайте справочные страницы stty, curses).

Итак, с этим в качестве фона, запустите контейнер без параметров, и по умолчанию у вас есть поток stdout (так docker run | <cmd>работает); запустить с -i, и вы получите поток stdin (так <cmd> | docker run -iработает); используйте -t, как правило, в комбинации, -itи у вас есть добавленный драйвер терминала, который, если вы взаимодействуете с процессом, скорее всего, то, что вы хотите. Это в основном делает начало контейнера похожим на сеанс терминального соединения.

Twweeed
источник
7
Это должен быть главный ответ. Хотя он не самый технический, он объясняет фундаментальное поведение -itфлагов.
Крис Хайра
1
Согласитесь с Крисом. Я прочитал другие ответы и все еще был в замешательстве. Этот ответ проясняет это.
Бен Ли
4
Да, возможно, стоит упомянуть, что само слово «TTY» является аббревиатурой от слова «teletypewriter» (AKA «teleprinter»), которое представляет собой имя устройства, позволяющее набирать текст и отправлять его одновременно - как телефон для текста ;-) Попробуйте, docker run -i ubuntuи docker run -it ubuntuвы увидите разницу сразу. «-i» позволяет заставить контейнер ожидать взаимодействия с хостом, но фактическое взаимодействие с консолью (терминалом) возможно после того, как вы «выделите tty драйвер» с флагом «-t».
Зегар
Могу ли я запустить tty в докере? У меня есть приложение, которое перестает работать -t, но я не запускаю докер , но не могу изменить команду запуска докера в рабочей среде. Поэтому мне нужно заставить приложение думать, что оно было начато -t.
Мворисек
98

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

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

Так

  • docker run -i alpine catвыдает пустую строку в ожидании ввода. Типа "привет", вы получаете эхо "привет". Контейнер не выйдет, пока вы не отправите CTRL+, Dпотому что основной процесс catожидает ввода от бесконечного потока, который является входом терминала для docker run.
  • С другой стороны echo "hello" | docker run -i alpine cat, напечатает «привет» и сразу же 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вместе. Это говорит cat, что его вход является терминалом, и в то же время подключите этот терминал к входу 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 -u root -pдаст вам запрос пароля. Если вы введете пароль, символы будут напечатаны визуально.
  • docker run -i alpine shдаст вам пустую строку. Если вы наберете команду, как lsвы получите вывод, но вы не получите приглашение или цветной вывод.

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

Ахмед Гоним
источник
6
Лучший ответ здесь, который действительно заставляет меня понять, что именно -tи -iварианты делают!
Руслан Стельмаченко
1
Фантастический ответ, который предвосхищал все
Джеймс Мачин
@ Ахмед Гоним, Очень хорошие ответы. Спасибо. Но насчет «Это потому, что команды обрабатывают ввод по-разному, если это терминал», я думаю, что это опечатка, верно? Должно быть «Это потому, что команды обрабатывают ввод по-разному, если это не терминал», верно?
tuq
@ Ахмед Гоним. Кристально чистый. Но как насчет запуска docker -a = stdin alpine cat?
HKIT
1
@HKIIT "-a = stdin" присоединяет поток stdin к контейнеру, но без выделения памяти. Это флаг -i, который выделяет буферную память в контейнере для потока stdin, поэтому в описании «Держите STDIN открытым, даже если он не подключен», когда передается -i, память выделяется для stdin независимо от флагов вложений. Без этой выделенной памяти чтения в stdin пусты / eof. Также вам нужно включить «-a = stdout», чтобы увидеть ответ от команды cat, например: «docker run -i -a = stdin -a = stdout alpine cat» ... конечно, нет необходимости делать это, вы можете просто запустите "Docker Run -i Alpine Cat".
Дэвид Д
71

-tАргумент не документирован хорошо, или упоминается многими людьми , часто, по данным поиска Google.

Он даже не отображается, когда вы выводите список (что должно быть) всех аргументов докер-клиента, набирая dockerв приглашении Bash (с последней версией 1.8.1).

На самом деле, если вы попытаетесь получить конкретную помощь по этому аргументу, набрав docker -t --helpif , вы получите удивительно смутный ответ:

флаг указан, но не определен: -t

Таким образом, вы не можете быть обвинены в том, что запутались в этом аргументе!

В онлайн-документации Docker есть упоминание о том, что оно «выделяет псевдо-tty» и часто используется с -i:

https://docs.docker.com/reference/run/

Я видел, что он использовался в документации для потрясающего jwilder/nginx-proxyдок-контейнера следующим образом:

docker run -d -p 80:80 --name nginx -v /tmp/nginx:/etc/nginx/conf.d -t nginx

В этом случае он отправляет выходные данные в «virtual» tty (командная строка / терминал Bash) в этом контейнере Docker. Затем вы можете увидеть эти выходные данные, выполнив команду docker docker logs CONTAINERгде CONTAINERпервая пара символов идентификатора этого контейнера. Этот идентификатор контейнера можно найти, набравdocker ps -a

Я видел этот -tаргумент кратко упоминается в следующей ссылке, где он говорит

-tИ -iфлаги выделить псевдо-терминал и держать стандартный ввод открытым , даже если не прилагается. Это позволит вам использовать контейнер как традиционную виртуальную машину, пока работает приглашение bash.

https://coreos.com/os/docs/latest/getting-started-with-docker.html

Надеюсь, это поможет! Я не уверен, почему это не задокументировано или не используется много. Возможно, это экспериментально и будет реализовано как документированная функция в следующих версиях.

Богатый
источник
21
Документация показывается docker run --help, а не docker -t --help: -t, --tty=false Allocate a pseudo-TTY"
bskaggs
5

Что я знаю о -tследующем:

docker exec -ti CONTAINER bash- позволяет мне «войти» в контейнер. Это похоже на ssh-ing (это не так).

Но беда была, когда я захотел восстановить базу данных.

Обычно я делаю docker exec -ti mysql.5.7 mysql- здесь я выполняю команду mysql в контейнере и получаю интерактивный терминал.

Я добавил <dump.sqlк предыдущей команде, чтобы я мог восстановить БД. Но это не удалось с cannot enable tty mode on non tty input.

Удаление -tпомогло. Все еще не понимаю, почему:

docker exec -i mysql.5.7 mysql < dump.sql

Последний работает. Надеюсь, что это помогает людям.

туман
источник
Могу ли я запустить tty в докере? У меня есть приложение, которое перестает работать -t, но я не запускаю докер , но не могу изменить команду запуска докера в рабочей среде. Поэтому мне нужно заставить приложение думать, что оно было начато -t.
Мворисек
1

В Linux, когда вы запускаете команду, вам нужен терминал (tty) для ее выполнения.

Поэтому, когда вы хотите подключиться к Docker (или запустить команду в Docker-контейнере), вы должны указать параметр -t, который учитывает наличие терминала в Docker-контейнере.

Чираг
источник
0

Каждый процесс имеет три потоки данных ИЭ STDIN/ STDOUT/ STDERR. Когда процесс выполняется в контейнере, по умолчанию терминал связан с потоком STDOUT процесса, выполняющегося в контейнере. Следовательно, все выходные потоки будут видны при запуске docker runкоманды в терминале. Но если вы хотите обеспечить ввод для запущенного процесса в контейнере, то вам нужно соединиться с каналом STDIN процесса, который не является по умолчанию и выполняется docker run -iкомандой.

-t используется для интерактивных / форматированных операций ввода.

Суровый Вардхан
источник
-3

-itИнструктирует DOCKER выделить псевдо-TTY , соединенную с стандартным вводом контейнера, создавая интерактивную оболочку Баша в контейнере.

--interactive, -i falseKeep STDIN открыть , даже если не прилагается

--tty, -t false Выделяют псевдо-TTY

https://docs.docker.com/engine/reference/commandline/run/

Чайная Droid
источник