Когда я буду использовать `--interactive` без` -tty` в контейнере Docker?
Я сделал несколько поисковых запросов и не повезло найти случай, когда я бы выполнил docker run -i some_image
, а не docker run -it some_image
.
Если я запустил docker run -i --name sample some_image bash
, контейнер запускается на переднем плане, но я не могу взаимодействовать с ним из оболочки, в которой я находится. Я даже не могу остановить ее с помощью CTRL + C. Однако я могу открыть другую оболочку и запустить docker exec -it sample bash
и получить доступ к контейнеру.
Если я запустил docker run -i -d --name sample some_image bash
, контейнер немедленно выйдет. Я могу перезапустить его с помощью docker start sample
, а затем он останется, поэтому я могу запустить docker exec -it sample bash
и снова взаимодействовать с ним.
Однако во всех этих случаях я в конечном итоге использую -it
для взаимодействия с моими контейнерами. В каком мире мне не нужен флаг -t
?
Приветствия
Ответы
Ответ 1
Так как -i
сохраняет STDIN открытым, даже если он не подключен, он позволяет создавать композицию (трубопровод).
Например:
docker run ubuntu printf "line1\nline2\n" | docker run -i ubuntu grep line2 | docker run -i ubuntu sed 's/line2/line3/g'
(Источник: issue 14221)
Или:
$ echo hello | docker run -i busybox cat
hello
(Источник: issue 12401)
Теперь представьте себе, что это не перед клавиатурой и используется в script, где вы действительно можете написать процессам stdin через что-то лучше, чем оболочка |
: example integration-cli/docker_cli_attach_test.go
Ответ 2
Поздний ответ, но может помочь кому-то
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
echo "hello" | docker -i run alpine cat
выведет "hello" и немедленно выйдет, потому что cat
замечает, что поток ввода закончился и завершает сам.
Если вы попробуете docker ps
после выхода из любого из вышеперечисленных, вы не найдете никаких работающих контейнеров. В обоих случаях сам cat
завершил работу, поэтому docker завершил работу с контейнером.
Теперь для "-t" это говорит основному процессу внутри докера, что его вход является терминальным устройством.
Так
-
docker run -t alpine cat
выдаст вам пустую строку, но если вы попытаетесь напечатать "hello", вы не получите никакого эха. Это потому, что хотя cat
подключен к входу терминала, этот вход не подключен к вашему входу. "Привет", который вы набрали, не дошел до ввода cat
. cat
ждет ввода, который никогда не прибудет. -
echo "hello" | docker run -t alpine cat
echo "hello" | docker run -t alpine cat
также выдаст вам пустую строку и не выйдет из контейнера на CTRL-D, но вы не получите эхо "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
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 -e MYSQL_ROOT_PASSWORD=123 -i mariadb mysql -uroot -p
пароля. Если вы введете пароль, символы будут напечатаны визуально. -
docker run -i alpine sh
выдаст вам пустую строку. Если вы наберете команду типа ls
вы получите вывод, но вы не получите подсказку или цветной вывод.
В последних двух случаях вы получаете такое поведение, потому что mysql
а также shell
не обрабатывали ввод как tty и, следовательно, не использовали специфическое для tty поведение, такое как маскирование ввода или окрашивание вывода.