Жизненный цикл контейнера: run, exec, stop, rm и сохранность файлов
Автор: Казачкин Даниил Михайлович · Обновлено
Контейнер живёт, пока работает его главный процесс. docker run создаёт новый контейнер и запускает его; docker start запускает уже существующий остановленный; docker exec…
Контейнер живёт, пока работает его главный процесс. docker run создаёт новый контейнер и запускает его; docker start запускает уже существующий остановленный; docker exec выполняет дополнительную команду в работающем контейнере. Это различие объясняет, почему повторный run иногда получает конфликт имени, а exec не работает после stop.
Практика с управляемым процессом
В Bash на Linux или в Ubuntu WSL создайте учебный контейнер:
docker run -d --name dk-life alpine:3.22 sh -c 'trap "exit 0" TERM; while :; do sleep 1; done'
docker ps --filter name=dk-life
docker exec dk-life sh -c 'echo draft > /tmp/note'
docker exec dk-life cat /tmp/noteПолучится draft. -d освобождает терминал, но не превращает короткую программу в сервис. Если запустить alpine echo hello с -d, контейнер всё равно быстро завершится. В нашем примере shell остаётся в цикле; обработчик TERM позволяет ему закончить работу при остановке. Параметры run.
Остановка не удаляет контейнер
docker stop --timeout 5 dk-life
docker ps -a --filter name=dk-life
docker inspect --format '{{.State.Status}} {{.State.ExitCode}}' dk-life
docker start dk-life
docker exec dk-life cat /tmp/noteПосле stop ожидается exited, после start файл по-прежнему содержит draft. Stop обычно отправляет главному процессу SIGTERM, ждёт установленный срок и при необходимости применяет SIGKILL. Приложение должно корректно обрабатывать завершение: записать буфер, закрыть соединения и выйти. Семантика stop.
docker exec -it dk-life sh открывает shell, но выход из этого дополнительного shell не останавливает основной цикл. Не используйте интерактивное редактирование контейнера как способ доставки новой версии программы: изменения трудно повторить при следующем развёртывании.
Как удалить контейнер Docker
docker stop dk-life
docker rm dk-life
docker run --rm alpine:3.22 sh -c 'test ! -e /tmp/note && echo clean'Новый контейнер выводит clean. Удаление уничтожило записываемый слой старого экземпляра. Образ Alpine не изменился и не удалился. docker rm без принудительного флага откажется удалять работающий контейнер: сначала выполните stop. docker rm -f принудительно завершает процесс; это не обычный путь остановки приложения с важными данными.
Параметр --rm удобен для одноразовых проверок: контейнер автоматически удалится после завершения. Для расследования раннего падения он неудобен — вы потеряете объект для последующего inspect и logs. Имена задавайте предметно, чтобы не использовать массовое удаление всех контейнеров.
Сравнение с volume
Теперь перенесём только учебную заметку в именованный том:
docker volume create dk-life-data
docker run --rm --mount type=volume,src=dk-life-data,dst=/data alpine:3.22 sh -c 'echo saved > /data/note'
docker run --rm --mount type=volume,src=dk-life-data,dst=/data alpine:3.22 cat /data/noteВторой, новый контейнер выводит saved: данные принадлежат тому. --rm не удаляет именованный том. Он удаляет контейнер и связанные с ним анонимные тома; это важное различие при чтении чужих Dockerfile с VOLUME. После эксперимента удалите только учебный том: docker volume rm dk-life-data. Жизненный цикл volumes.
Диагностика и упражнение
Если имя занято, найдите объект через docker ps -a --filter name=dk-life и решите, нужен ли start или новый контейнер с другим именем. Если exec сообщает, что контейнер не работает, изучите его состояние и логи, а не повторяйте exec. При «пропаже» файла сравните ID контейнера и список его mounts.
Повторите эксперимент с другим учебным именем. До каждой операции запишите прогноз: останется ли файл после stop, start, rm и нового run? Правильный ответ зависит от места записи: в записываемом слое файл переживает stop/start, в именованном томе — и удаление контейнера. Том при этом не заменяет резервную копию: пользователь или приложение всё ещё могут удалить данные внутри него.