Docker — это утилита контейнеризации, которая позволяет разработчикам создавать и управлять портативными, согласованными контейнерами Linux.
При разработке или развертывании контейнеров часто возникает необходимость заглянуть в запущенный контейнер, чтобы проверить его текущее состояние или устранить проблему. Для этого в Docker есть команда docker exec.
В этом мануале мы рассмотрим команду docker exec, а также расскажем, как с ее помощью выполнять команды и получить интерактивную оболочку в запущенном контейнере Docker.
Требования
В этом туториале предполагается, что у вас уже установлен Docker и у вашего пользователя есть разрешение на запуск команды docker. Если вам нужно запустить docker от пользователя root, не забудьте добавить sudo перед командой.
Читайте также: Установка и использование Docker в Ubuntu 20.04
Запуск тестового контейнера
Для работы с docker exec вам понадобится работающий контейнер. Если у вас еще нет его, запустите тестовый с помощью следующей команды docker run:
docker run -d --name container-name alpine watch "date >> /var/log/date.log"
Эта команда создаст новый контейнер Docker из официального образа alpine. Это популярный образ контейнера Linux, который использует Alpine Linux — легкий, минимальный дистрибутив Linux.
С помощью флага -d отсоединим контейнер от терминала и запустим его в фоновом режиме. –name container-name присвоит контейнеру название container-name. Вы можете выбрать любое имя или вообще не указывать его, чтобы Docker автоматически сгенерировал уникальное название для нового контейнера.
Далее у нас есть alpine, который указывает на образ, с помощью которого мы создаем контейнер.
watch “date >> /var/log/date.log” — это команда, которую мы хотим выполнить в контейнере. watch будет повторять команду, которую вы укажете, каждые две секунды по умолчанию. В данном случае будет запущена команда watch: date >> /var/log/date.log. Команда date выводит текущую дату и время, например:
OutputFri Jul 23 14:57:05 UTC 2021
Часть команды >> /var/log/date.log перенаправляет вывод из date и добавляет его в файл /var/log/date.log. Каждые две секунды в файл будет добавляться новая строка, и через несколько секунд он будет выглядеть примерно так:
Fri Jul 23 15:00:26 UTC 2021 Fri Jul 23 15:00:28 UTC 2021 Fri Jul 23 15:00:30 UTC 2021 Fri Jul 23 15:00:32 UTC 2021 Fri Jul 23 15:00:34 UTC 2021
На следующем этапе мы рассмотрим, как узнать имена контейнеров Docker. Это поможет, если у вас уже есть контейнер, с которым вы хотите работать, но вы не знаете, как он называется.
Поиск имени контейнера Docker
Как правило, нам нужно сообщить docker exec название (или ID) контейнера, с которым мы хотим работать. Мы можем найти эту информацию с помощью команды docker ps:
docker ps
Эта команда выводит список всех контейнеров Docker, которые запущены на сервере, и предоставляет высокоуровневую информацию о них:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 76aded7112d4 alpine "watch 'date >> /var…" 11 seconds ago Up 10 seconds container-name
В этом примере указаны ID и название контейнера. Вы можете использовать любое значение, чтобы сообщить команде docker exec, с каким контейнером нужно работать.
Переименовать контейнер можно с помощью команды docker rename:
docker rename container-name new-name
Далее мы рассмотрим несколько примеров использования docker exec для выполнения команд в запущенном контейнере Docker.
Запуск интерактивной оболочки в контейнере Docker
Запустить интерактивную оболочку в контейнере Docker (возможно, для изучения файловой системы или отладки запущенных процессов) можно с помощью docker exec с флагами -i и -t.
Флаг -i открывает ввод для контейнера, а -t создает псевдо-терминал, к которому может подключиться оболочка. Эти флаги можно комбинировать следующим образом:
docker exec -it container-name sh
Команда запустит базовую оболочку sh в указанном контейнере. Для выхода из контейнера введите exit и нажмите ENTER:
exit
Если образ контейнера включает более продвинутую оболочку, например bash, вы можете заменить sh на bash.
Запуск неинтерактивной команды в контейнере Docker
Если вам нужно выполнить неинтерактивную команду в работающем контейнере Docker, запустите docker exec без флагов:
docker exec container-name tail /var/log/date.log
Эта команда выполнит tail /var/log/date.log в контейнере container-name и выведет результаты. По умолчанию команда tail выводит последние десять строк файла. Если вы запускаете демо-контейнер, который мы установили на первом этапе, то вывод будет примерно следующим:
Mon Jul 26 14:39:33 UTC 2021 Mon Jul 26 14:39:35 UTC 2021 Mon Jul 26 14:39:37 UTC 2021 Mon Jul 26 14:39:39 UTC 2021 Mon Jul 26 14:39:41 UTC 2021 Mon Jul 26 14:39:43 UTC 2021 Mon Jul 26 14:39:45 UTC 2021 Mon Jul 26 14:39:47 UTC 2021 Mon Jul 26 14:39:49 UTC 2021 Mon Jul 26 14:39:51 UTC 2021
По сути, это то же самое, что и запуск интерактивной оболочки для контейнера Docker (как это было сделано на предыдущем этапе с помощью docker exec -it container-name sh) и выполнение команды tail /var/log/date.log. Но вместо того чтобы открывать оболочку, выполнять команду и затем закрывать ее, эта команда возвращает тот же вывод,не запуская псевдо-терминал.
Выполнение команд в альтернативном каталоге
Запустить команду в определенном каталоге контейнера можно с помощью флага –workdir:
docker exec --workdir /tmp container-name pwd
В этом примере команда устанавливает каталог /tmp в качестве рабочего, а затем запускает pwd, которая выводит текущий рабочий каталог:
/tmp
Команда pwd подтверждает, что рабочий каталог — /tmp.
Выполнение команд от имени другого пользователя
Добавьте флаг –user, чтобы запустить команду от имени другого пользователя внутри контейнера:
docker exec --user guest container-name whoami
Для выполнения команды whoami в контейнере будет использоваться пользователь guest. Команда whoami выводит имя текущего пользователя:
guest
whoami подтверждает, что текущий пользователь контейнера — guest.
Передача переменных окружения
Иногда вместе с выполняемой командой в контейнер нужно передать переменные окружения. Флаг -e позволяет указать переменную окружения:
docker exec -e TEST=8host container-name env
Эта команда устанавливает для переменной окружения TEST значение 8host, а затем запускает команду env в контейнере. Потом env выводит все переменные окружения:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=76aded7112d4 TEST=8host HOME=/root
Для переменной TEST устанавливается значение 8host.
Чтобы установить несколько переменных, повторите флаг -e для каждой:
docker exec -e TEST=8host -e ENVIRONMENT=prod container-name env
Если вы хотите передать файл со значениями переменных окружения, вы можете сделать это с помощью флага –env-file.
Сначала создайте файл с помощью текстового редактора. Мы откроем новый файл через nano, но вы можете использовать любой другой редактор:
nano .env
Назовем файл .env, так как это популярный стандарт для использования файлов такого типа (для управления информацией вне системы контроля версий).
Запишите переменные KEY=value в файл, по одной в строке:
TEST=8host ENVIRONMENT=prod
Сохраните и закройте файл. В nano для этого нажмите CTRL+O, ENTER и CTRL+X.
Теперь запустите команду docker exec, указав правильное имя файла после –env-file:
docker exec --env-file .env container-name env
Вывод будет таким:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=76aded7112d4 TEST=8host ENVIRONMENT=prod HOME=/root
Теперь в файле установлены две переменные.
Вы можете указать больше файлов с помощью нескольких флагов –env-file. Если переменные в файлах пересекаются, то файл, который был указан последним в команде, перезапишет предыдущие.
Частые ошибки
При работе с командой docker exec вы можете столкнуться с такими ошибками:
Error: No such container: container-name
Ошибка No such container означает, что указанный контейнер не существует, а также может указывать на неправильное написание имени контейнера. Выполните docker ps, чтобы вывести список запущенных контейнеров и проверить его название.
Error response from daemon: Container 2a94aae70ea5dc92a12e30b13d0613dd6ca5919174d73e62e29cb0f79db6e4ab is not running
Сообщение not running означает, что контейнер существует, но он остановлен. Вы можете запустить контейнер с помощью docker start container-name.
Error response from daemon: Container container-name is paused, unpause the container before exec
Ошибка Container is paused достаточно понятно объясняет проблему. Нужно разблокировать контейнер с помощью docker unpause container-name, прежде чем приступать к дальнейшей работе.
Заключение
В этом мануале мы рассмотрели выполнение команд в запущенном контейнере Docker, а также некоторые опции командной строки.