Урок курса
Команда внутри работающего контейнера
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. Других действий не было. Что произойдёт?
Продолжить с сохранением прогресса
Перейдите к уроку в учебном кабинете.
