Урок курса

Команда внутри работающего контейнера

Docker и Docker Compose: контейнеризация приложений

1. Осмотреть работающий контейнер

В предыдущих уроках запущенный в фоне контейнер наблюдался только снаружи: через docker ps для проверки статуса и docker logs для чтения стандартных потоков вывода. Если фоновому сервису требуется разовая диагностика — например, проверить наличие файла настроек или убедиться в доступности каталога, — чтение журналов не покажет файловую систему.

Убедимся, что имя свободно после очистки прошлых уроков, и запустим фоновый учебный контейнер на базе busybox:1.36 с именем cf_docker_course_early_background, основным процессом которого останется длительная пауза:

docker run -d --name cf_docker_course_early_background busybox:1.36 sleep 3600

Команда возвращает идентификатор контейнера. Контейнер переходит в статус Up, а его основной процесс (PID 1 внутри изолированного пространства) выполняет sleep.

В уроке 05 для подключения к контейнеру рассматривалась команда docker attach. Напомним её механику: docker attach привязывает стандартные потоки ввода и вывода терминала хоста напрямую к уже работающему основному процессу (PID 1). Если этот процесс — sleep 3600, он ничего не выводит и не ожидает команд шелла. Попытка ввести в таком терминале команды навигации ничего не даст. При этом нажатие Ctrl+C пересылает сигнал SIGINT, но реакция зависит от запущенного приложения: PID 1 без собственного обработчика сигналов (включая наш sleep) может проигнорировать SIGINT и продолжить работу. Для остановки такого процесса по-прежнему требуется выполнить docker stop из отдельного окна терминала.

Для запуска новой дополнительной задачи внутри того же изолированного окружения применяется команда docker exec:

docker exec [OPTIONS] <контейнер> <команда> [аргументы...]

Механизм docker exec принципиально отличается от attach: Docker Engine не подключается к потокам PID 1, а порождает внутри уже работающего контейнера отдельный вспомогательный процесс. Этот новый процесс получает то же самое окружение: видит ту же файловую систему, сетевой стек и переменные окружения контейнера, но выполняется параллельно основному процессу.

Важное условие применимости docker exec: целевой контейнер обязан находиться в статусе Up. Если контейнер остановлен (статус Exited), попытка выполнить команду завершится ошибкой демона:

Error response from daemon: Container cf_docker_course_early_background is not running

Двоичный файл команды, которую вы передаёте в docker exec, должен физически присутствовать в файловой системе самого контейнера. Docker не копирует утилиты с хост-системы внутрь контейнера во время вызова exec.

2. Папка, список и содержимое

Для исследования файловой системы контейнера используются базовые POSIX-утилиты командной строки. Разберём четыре стандартные утилиты перед их вызовом:

  • pwd (print working directory) — выводит абсолютный путь к текущей рабочей директории процесса;
  • ls [путь] (list) — отображает имена файлов и подкаталогов по указанному пути;
  • cat <путь> (concatenate) — читает файл и выводит его текстовое содержимое в стандартный поток вывода;
  • sh — командный интерпретатор (шелл), исполняющий переданные скрипты или принимающий интерактивные команды.

Выполним однократный вызов утилиты pwd в работающем контейнере cf_docker_course_early_background:

docker exec cf_docker_course_early_background pwd

Вывод команды:

/

Утилита pwd отработала в корневом каталоге контейнера /, вывела результат в терминал и завершила свой процесс. Контейнер при этом продолжает работать.

Теперь запросим список элементов в директории /etc внутри контейнера:

docker exec cf_docker_course_early_background ls /etc

Команда вернёт перечень системных файлов окружения. Конкретный набор файлов в каталоге зависит от дистрибутива и настроек демона, но Docker всегда формирует для каждого запущенного контейнера файл /etc/hostname с назначенным сетевым именем (по умолчанию — сокращённым идентификатором контейнера). Прочитаем его содержимое с помощью cat:

docker exec cf_docker_course_early_background cat /etc/hostname

Пример вывода:

c2d9f5866314

Вывод представляет собой отдельную динамическую строку с именем хоста этого конкретного контейнера. Путь /etc/hostname указывает на файл внутри изолированной файловой системы контейнера, а не на хост разработчика. Утилита cat запустилась внутри окружения контейнера, прочитала файл и передала текст демону Docker, который вывел его в терминал.

Если требуется выполнить серию команд без постоянного ввода docker exec, запускают интерактивный шелл. Для этого передаются флаги -i (интерактивный ввод) и -t (псевдотерминал):

docker exec -it cf_docker_course_early_background sh

Терминал переключится на приглашение оболочки внутри контейнера (например, / #). Здесь можно последовательно запускать pwd, ls или просматривать другие файлы. Завершение сессии шелла выполняется командой exit или комбинацией клавиш Ctrl+D.

3. Вспомогательная команда завершилась

Когда вы вызываете разовую команду чтения через docker exec (например, pwd, ls или cat) либо вводите exit в интерактивном шелле sh, этот вспомогательный процесс завершает работу. Проверим, как завершение такой диагностической команды отражается на самом контейнере.

Запросим статус нашего контейнера с помощью docker ps:

docker ps --filter "name=cf_docker_course_early_background"

Пример вывода:

CONTAINER ID   IMAGE          COMMAND        CREATED         STATUS         PORTS     NAMES
2f3a8b4c9e10   busybox:1.36   "sleep 3600"   5 minutes ago   Up 5 minutes             cf_docker_course_early_background

Идентификатор остался прежним, а статус указывает Up. Можно запросить статус напрямую через форматированный docker inspect:

docker inspect --format '{{.State.Status}}' cf_docker_course_early_background

Вывод:

running

Жизненный цикл контейнера привязан к его основному процессу — PID 1. Процессы, порождённые через docker exec, запускаются рядом в тех же пространствах имён и не становятся PID 1. Поэтому штатное завершение утилит чтения или выход из оболочки sh завершают только сам вспомогательный процесс и сами по себе не приводят к остановке sleep 3600.

При этом важно помнить о границе изоляции: команда exec не изолирована от контейнера полностью. Она делит с основным процессом общую файловую систему, сетевой стек и ресурсы памяти и процессора. Вспомогательная команда, которая перезаписывает файлы данных, отправляет сигналы процессам или исчерпывает оперативную память, способна нарушить работу сервиса. Однако пока команды носят характер чтения и диагностики, их завершение оставляет контейнер в статусе Up до тех пор, пока выполняется его основной процесс.

Локальная лабораторная / самопроверка

Что уже дано

Файлы хоста не нужны. Выданная нагрузка для alpine:3.20: sh -c "echo 'system-ready' > /tmp/status.txt; exec sleep 600". Она создаёт файл внутри контейнера, затем запускает sleep. Имя ${LAB}_box; стартуйте в фоне. Утилиты pwd, ls, cat, sh присутствуют в этом образе.

Все команды выполняются на хосте в POSIX-терминале; для Linux-ветки с sudo используйте sudo docker. Рабочая папка — любая пустая учебная папка, исходных файлов нет. Задайте LAB=cf_docker_task_l07_run1. Перед началом выполните docker container ls -a --filter "name=^/${LAB}_": строк со своим префиксом быть не должно. Если имя занято, выберите новый суффикс вместо run1 и используйте его во всех именах этой лабораторной. Не удаляйте найденные чужие контейнеры.

Что нужно сделать

Осмотрите рабочую директорию вспомогательной команды и список /tmp, прочитайте /tmp/status.txt отдельной командой внутри работающего контейнера. Затем запустите отдельную интерактивную оболочку в этом же контейнере и завершите её командой exit. Выберите механизм, который создаёт дополнительный процесс, а не подключается к sleep. Проверьте, сохранился ли основной контейнер.

Ввод и вывод

Вы выбираете и вводите команды Docker на хосте. Результат — реальные выводы команд и состояние локальных ресурсов. Форма автоматического ответа отсутствует. Сохраните команды и наблюдения в свой текстовый отчёт; ввод в контейнер нужен только там, где прямо требуется отдельная интерактивная оболочка.

Проверка результата:

  • Сохранены результаты pwd, ls /tmp и чтения status.txt; прочитанная строка — system-ready.
  • В интерактивной оболочке выполнен exit. После её выхода тот же контейнер с прежним ID остаётся Up/running.
  • Чтение происходит в контейнере, host file с таким именем не создаётся и не читается.

Оставьте у себя отчёт с выполненными командами, динамическими ID и наблюдениями до очистки. Самопроверка — сравнение с критериями выше; вводить кодовое слово или загружать отчёт на платформу не требуется. После сохранения отчёта завершите свои ресурсы:

docker stop "${LAB}_box"
docker rm "${LAB}_box"

Если экземпляр уже удалён, сообщение No such container допустимо; если он уже остановлен, stop не требуется. Перед повторной попыткой осмотрите только имена своего LAB.

Ограничения:

  • Выполнение локальное; автоматической оценки и проверки вашего отчёта нет.
  • Не используйте глобальную очистку Docker. Команды очистки относятся только к выбранным именам LAB; общие образы Alpine/Python сохраняются.
  • Команды проверены в Linux-контейнерах Docker Engine 29.6.2 на Windows Docker Desktop; установка Docker на других ОС и аппаратных архитектурах отдельно не проверялась.

Лабораторная выполняется локально. Latorn не запускает Docker Compose или весь проект и не подтверждает выполнение лабораторной автоматически.

Задача 1

В работающем контейнере web-api основной процесс — sleep 1000; утилита ls установлена. Нужно выполнить ls /etc отдельной командой внутри этого контейнера. Какое действие подходит?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 2

В контейнере worker продолжает работать основной процесс sleep 600. Разработчик открыл оболочку через docker exec -it worker sh, затем выполнил в ней exit. Других действий не было. Что произойдёт?

Выберите один вариант
Без регистрации · результат не сохраняется

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку