1. Обзор
Docker – это популярная платформа для контейнеризации.
С помощью инструмента командной строки docker она предлагает различные подкоманды, которые значительно упрощают управление контейнерами в системе.
Среди этих подкоманд exec и attach – две команды, обычно используемые для взаимодействия с запущенным контейнером.
Несмотря на кажущуюся схожесть функциональности, команды docker exec и docker attach сильно отличаются друг от друга при взаимодействии с запущенным контейнером.
Чтобы понять эти различия, важно узнать, как эти две команды работают под капотом.
В этом руководстве мы узнаем, что делают команды docker attach и docker exec и в чем их различия.
2. Docker Exec
Команда docker exec выполняет любую произвольную команду в запущенном контейнере.
В частности, команда docker exec запускает заданную команду в рабочей директории контейнера по умолчанию под новым процессом.
Как правило, команда имеет следующее выражение:
docker exec [OPTIONS] CONTAINER COMMAND
Важно отметить, что COMMAND должна быть исполняемым файлом, а не цитируемым скриптом.
Это связано с тем, что движок Docker передает COMMAND системному вызову exec под капотом.
Например, распространенной ошибкой является передача однострочного скрипта оболочки в качестве COMMAND
$ docker exec ubuntu "echo hello && echo world"
OCI runtime exec failed: exec failed: unable to start container process: exec: "echo hello && echo world": executable file not found in $PATH: unknown
Проблема в том, что однострочный скрипт не является исполняемым файлом.
Чтобы запустить скрипт оболочки с помощью docker exec, мы должны указать исполняемый файл, sh, и передать скрипт в качестве аргументов команде sh.
Поэтому правильным способом запуска однострочного скрипта оболочки является префикс исполняемого файла sh -c:
$ docker exec ubuntu sh -c "echo hello && echo world"
hello
world
Кроме того, docker exec предлагает различные опции для использования с командой.
Важными являются опции -i и -t, которые позволяют держать открытым поток STDIN и выделять pseudo-tty для таких случаев, как запуск интерактивной оболочки в контейнере.
3. Docker Attach
Команда docker attach прикрепляет стандартные потоки ввода, вывода и ошибок текущего терминала к основному процессу запущенного контейнера.
С присоединенными потоками мы можем взаимодействовать с процессом внутри контейнера так, как если бы он был запущен на нашем терминале.
Прежде чем продолжить, давайте рассмотрим значение первичного процесса в контексте контейнера Docker.
3.1. Первичный процесс
Внутри работающего контейнера Docker будет запущен обычный процесс с PID, равным 1.
Этот процесс с PID, равным 1, называется первичным процессом.
Первичный процесс – это процесс, который запускается командой, указанной в ENTRYPOINT или CMD в образе Docker.
Когда мы выполняем команду docker attach на контейнере, команда прикрепляется к первичному процессу контейнера.
3.2. Команда
Команда docker attach принимает список опций и имя контейнера:
docker attach [OPTIONS] CONTAINER
Аргумент CONTAINER должен быть именем или идентификатором запущенного в данный момент контейнера Docker.
Кроме того, команда поддерживает такие опции, как -no-stdin, чтобы явно не подключать стандартный поток ввода.
Кроме того, мы можем предотвратить отправку сигналов процессу, указав опцию -sig-proxy false.
3.3. Демонстрация
Для демонстрации мы используем команду redis-cli, поскольку она представляет собой процесс, который слушает стандартный поток ввода и печатает в поток вывода.
Это позволяет нам продемонстрировать присоединение стандартного входного и выходного потоков.
Для начала мы запустим отдельный Docker-контейнер, используя Docker-образ redis.
Важно отметить, что нам нужно будет выполнить команду redis-cli, чтобы запустить его в качестве основного процесса нашего контейнера:
$ docker run -dit –name redis —rm redis redis-cli 2d3d508df8ad7b7e9c3864ae9733b1bd32e12f94330559f1ee6a4f753c299b9e
$ docker run -dit --name redis --rm redis redis-cli
2d3d508df8ad7b7e9c3864ae9733b1bd32e12f94330559f1ee6a4f753c299b9e
Очень важно, что мы указали опцию -it, чтобы сохранить входной поток контейнера открытым.
Кроме того, мы запускаем контейнер в отсоединенном режиме с помощью опции -d.
Затем мы можем присоединиться к процессу redis-cli с помощью команды docker attach:
$ docker attach redis
not connected>
Как и ожидалось, redis-cli не может подключиться к серверу Redis, потому что мы переписали стандартный CMD, запускающий сервер Redis.
Но это не повлияет на нашу демонстрацию, поскольку нас интересует только то, что поток ввода и вывода нашего терминала и основных процессов связаны.
Давайте выполним команду SET через стандартный поток ввода:
not connected> SET user bob
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected>
Как мы видим, процесс redis-cli считывает команды, которые мы поместили в стандартный поток ввода, и действует соответствующим образом.
Кроме того, любой вывод или ошибки, которые процесс поместил в стандартные потоки вывода и ошибок, отображаются на нашем терминале благодаря вложению.
4. Разница между Docker Exec и Docker Attach
Основное различие между командами docker exec и docker attach заключается в том, что docker exec выполняет команду в новом процессе.
Обычно она используется для запуска интерактивной оболочки в работающем контейнере или для выполнения произвольных команд в среде контейнера.
С другой стороны, команда docker attach не запускает никакого нового процесса.
Она присоединяет стандартные потоки ввода и вывода текущего терминала к основному процессу запущенного контейнера.
Команда docker attach используется в основном тогда, когда мы хотим напрямую отправлять команды первичному процессу.
5. Заключение
В этом руководстве мы узнали, что команда docker exec и команда docker attach – это совершенно разные команды для взаимодействия с процессом в запущенном контейнере.
см. также:
- 🐳 Разница между ENTRYPOINT и CMD в Dockerfile
- 🐳 Docker Compose Up или Start и Down или Stop: в чем разница
- 🐳 Узнаем, как долго работает контейнер Docker
- 🐳 Автоматический вход в Docker реджестри скриптом Bash
- ⚙️ Разница между полной виртуализацией и паравиртуализацией
- 🐳 Что такое слои образа Docker?