📖 Теория: Операции с Docker-контейнерами

⚡ Кратко: жизненный цикл контейнера

Контейнер — это изолированный процесс на хосте. Он проходит состояния: Created → Running → Paused/Stopped → Deleted.

  • create — создать, run = create + start, start/stop/restart/rm — управление
  • ps / ps -a — список контейнеров (работающих / всех)
  • exec -it — войти в работающий контейнер, logs -f — следить за логами
  • Без команды контейнер мгновенно завершается — нужна задача, удерживающая процесс

1. Контейнер как процесс

Контейнеры — это способ стандартизации развёртки приложения и отделения его от общей инфраструктуры. Экземпляр приложения запускается в изолированной среде, не влияющей на основную операционную систему.

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

Ключевая концепция: Docker-контейнер работает, пока работает его основной процесс. Как только процесс завершается — завершается и контейнер. Именно поэтому docker run ubuntu без команды мгновенно останавливается: ubuntu-образ не имеет вечно работающего процесса по умолчанию.

2. Основные состояния контейнеров

Контейнер в Docker проходит через несколько чётко определённых состояний:

Состояние Описание Команда перехода
Created Контейнер создан из образа, но ещё не запущен. Docker зарезервировал ресурсы, но процесс не стартовал. docker create
Running Контейнер запущен, его приложение активно выполняется. Контейнер потребляет CPU, память и другие ресурсы хоста. docker start / docker run
Paused Выполнение процессов контейнера приостановлено (cgroup freezer). Состояние сохраняется, ресурсы памяти заняты, CPU — нет. docker pause
Stopped (Exited) Контейнер остановлен: процесс завершён, ресурсы хоста освобождены, но файловая система контейнера сохранена на диске. docker stop / docker kill
Deleted Контейнер удалён. Файловая система контейнера удалена с диска. Данные без volume потеряны навсегда. docker rm

3. Docker Entrypoint

Docker Entrypoint — это команда (или исполняемый файл), которая определяет, что будет запущено внутри контейнера при его старте. Entrypoint задаётся в Dockerfile инструкцией ENTRYPOINT.

Полезно знать: Entrypoint — это неизменяемая по умолчанию точка входа контейнера. При запуске через docker run можно переопределить Entrypoint флагом --entrypoint, а аргументы передать позиционно.

Зачем нужен Entrypoint

  • Определение команды запуска: задаёт основной процесс, который удерживает контейнер в состоянии Running
  • Настройка инициализации: позволяет выполнить скрипт инициализации перед запуском основного приложения (настройка окружения, миграции БД)
  • Повторное использование: один образ — разные задачи через разные аргументы к одному Entrypoint

Проблема мгновенного завершения контейнера

Контейнеры в Docker завершаются сразу, как только завершается их основной процесс (PID 1). Если образ не определяет долгоживущего процесса, контейнер мгновенно переходит в состояние Exited:

# Терминал
# ubuntu не имеет длительного процесса по умолчанию — контейнер сразу завершится
docker run ubuntu

# Проверим — контейнер в состоянии Exited
docker ps -a

Решения для длительной работы контейнера:

# Терминал
# Вариант 1: интерактивный bash
docker run -it ubuntu bash

# Вариант 2: фоновый режим с вечной задачей (tail -f /dev/null читает пустой файл бесконечно)
docker run -d --name my_ubuntu_container ubuntu tail -f /dev/null

# Приложения типа nginx или PostgreSQL сами удерживают процесс — дополнительная команда не нужна
docker run -d --name mynginx nginx
tail -f /dev/null — классический трюк для «заморозки» контейнера в работающем состоянии. tail -f бесконечно ждёт новых данных из файла, а /dev/null — пустое устройство, которое никогда не пишет данные. Результат: процесс не завершается, контейнер остаётся Running.

4. Команды управления контейнерами

Команды управления изменяют состояние контейнера. Принимают ID или имя контейнера.

Команда Что делает
docker create <image> Создаёт контейнер из образа, не запуская его (Created)
docker run <image> Создаёт и сразу запускает контейнер (= create + start)
docker start <id> Запускает остановленный контейнер
docker stop <id> Останавливает контейнер: посылает SIGTERM, ждёт 10 с, затем SIGKILL
docker kill <id> Немедленно завершает контейнер сигналом SIGKILL (без graceful shutdown)
docker restart <id> Перезапускает контейнер (= stop + start)
docker pause <id> Приостанавливает все процессы контейнера (cgroup freezer)
docker unpause <id> Возобновляет приостановленный контейнер
docker rm <id> Удаляет остановленный контейнер
docker rm -f <id> Принудительно удаляет даже работающий контейнер

5. Инспектирование контейнеров

Команды инспектирования позволяют читать состояние контейнеров, не меняя его.

Команда Что показывает
docker ps Список работающих контейнеров: ID, имя, образ, статус, порты, время запуска
docker ps -a Все контейнеры, включая остановленные и завершённые
docker logs <id> Вывод stdout и stderr контейнера (весь журнал)
docker logs -f <id> Логи в режиме follow — новые записи выводятся в реальном времени (как tail -f)
docker top <id> Список процессов внутри контейнера (PID, пользователь, команда)
docker diff <id> Изменения файловой системы контейнера относительно базового образа (A=added, C=changed, D=deleted)
docker inspect <id> Полная информация в JSON: сетевые настройки, монтированные тома, переменные окружения, метаданные образа

6. Взаимодействие с контейнером

Команды взаимодействия позволяют управлять данными и процессами внутри работающего контейнера.

Команда Назначение
docker exec <id> <cmd> Выполняет команду внутри работающего контейнера. С флагами -it — открывает интерактивную оболочку.
docker cp <src> <dst> Копирует файлы между хостом и контейнером в обоих направлениях
docker attach <id> Присоединяется к stdin/stdout/stderr работающего контейнера (PID 1)
docker export <id> Экспортирует файловую систему контейнера в .tar архив (без метаданных образа)
docker wait <id> Блокирует терминал до завершения контейнера, затем выводит код выхода
docker commit <id> <name> Создаёт новый образ на основе текущего состояния контейнера (включая изменения в файловой системе)
exec vs attach — в чём разница:
  • docker exec — запускает новый процесс в пространстве контейнера. Безопаснее, чаще используется.
  • docker attach — подключается к PID 1 (основному процессу). Нажатие Ctrl+C завершит основной процесс и остановит контейнер!

7. Команды управления образами

Помимо контейнеров, Docker предоставляет команды для управления образами на хосте.

Команда Назначение
docker images Список всех образов на хосте: ID, репозиторий, тег, размер, дата создания
docker history <image> История слоёв образа: команды, которые выполнялись при сборке каждого слоя
docker inspect <image> Подробная информация об образе в JSON: конфигурация, метки, переменные среды
docker tag <src> <dst> Устанавливает новый тег для образа (псевдоним для пуша в реестр)
docker commit <container> <image> Создаёт образ из текущего состояния контейнера
docker import <file.tar> Импортирует образ из .tar архива (созданного docker export)
docker rmi <image> Удаляет образ с хоста (нельзя удалить, пока есть использующие его контейнеры)
docker commit — антипаттерн в production: создание образов через docker commit из изменённых контейнеров — неплохой учебный инструмент, но в реальных проектах образы всегда собираются через Dockerfile. Это обеспечивает воспроизводимость и версионирование. Подробнее — в уроке 03.
← К оглавлению урока