Модель композиции (Docker Compose)

TL;DR: Docker Compose — декларативное описание многоконтейнерного приложения. Один YAML-файл заменяет десятки docker run команд. Service ≠ Container.

Docker Compose — это инструмент для определения и запуска многоконтейнерных приложений. Он совершает парадигмальный сдвиг в работе с Docker: переход от императивного управления отдельными контейнерами к декларативному описанию всей системы.

Compose реализует подход Infrastructure as Code (IaC) для локальной среды разработки.

Декларативный vs Императивный подход

  • Императивный (Docker CLI): Вы говорите системе что сделать. docker run -d --network app-net --name db postgres Если вы выполните эту команду дважды, вы получите ошибку (конфликт имен). Вам нужно писать скрипты для проверки состояния, создания сетей и т.д.
  • Декларативный (Compose): Вы описываете желаемое состояние системы в YAML-файле. docker compose up Compose смотрит на текущее состояние, сравнивает его с желаемым и выполняет только необходимые действия (конвергенция). Если контейнер уже запущен и его конфигурация не изменилась, Compose его не тронет. Если изменилась — пересоздаст.

Структура проекта

Compose вводит понятие Проекта — логической группы ресурсов, изолированных от других проектов.

1. Service (Сервис) vs Container (Контейнер)

Важно различать эти понятия:

  • Service: Это абстрактное определение, конфигурация (шаблон). “Мне нужен веб-сервер на базе Nginx с такими-то портами”.
  • Container: Это конкретный запущенный экземпляр сервиса.

В большинстве случаев у сервиса один контейнер (1:1), но Compose позволяет масштабировать сервисы (scale: 3), создавая несколько реплик (контейнеров) из одного определения сервиса (1:N).

2. Изоляция проектов

Имя проекта (по умолчанию — имя папки) используется как префикс для всех создаваемых ресурсов (сетей, томов, контейнеров).

  • Папка my-shop контейнер my-shop-db-1, сеть my-shop_default.
  • Это позволяет запускать несколько копий одного и того же окружения на одной машине (например, в CI/CD агентах), просто меняя имя проекта (-p project_name).

Управление зависимостями

В микросервисной архитектуре порядок запуска критичен. Backend не должен падать, если Database еще не готова принимать соединения.

depends_on

Определяет порядок запуска и остановки.

  • depends_on: [db]: Гарантирует, что Docker отправит команду старта контейнеру db раньше, чем backend.
  • Проблема: Docker считает контейнер запущенным, как только процесс стартовал (PID появился). Но базе данных может потребоваться 10-30 секунд на инициализацию (создание файлов, восстановление журнала). Приложение попытается подключиться сразу и упадет.

Healthchecks (Проверки здоровья)

Для решения проблемы “RACE Condition” (гонки) Compose использует Healthchecks.

  1. В сервисе БД описывается, как проверить ее готовность (например, команда pg_isready).
  2. В зависимом сервисе используется расширенный синтаксис:
    depends_on:
      db:
        condition: service_healthy

Теперь Compose не просто запустит базу, но будет ждать, пока она не ответит “OK”, и только потом запустит Backend.

Сетевое взаимодействие

Compose автоматически создает единую сеть для проекта (обычно типа bridge).

  • Service Discovery: Имя сервиса в YAML становится DNS-именем. Сервис web может обратиться к базе по адресу postgres://db:5432 (где db — имя сервиса).
  • Внутренние порты открыты для всех участников сети проекта, даже если они не опубликованы (ports) на хост-машину.

Профили и Переопределения (Overrides)

Docker Compose позволяет управлять сложностью конфигурации через наслоение (Layering).

  1. Profiles: Позволяют включать/выключать группы сервисов.
    • Пример: profiles: ["debug"] для phpMyAdmin или визуализаторов логов. Они не запустятся по docker compose up, пока вы явно не укажете --profile debug.
  2. Overrides: Compose по умолчанию читает compose.yaml и compose.override.yaml, объединяя их.
    • compose.yaml: Базовая структура (образы, связи).
    • compose.override.yaml: Локальные настройки (порты, bind mounts для кода), которые не коммитятся в git.
    • compose.prod.yaml: Настройки для продакшена (политика рестарта, production-ready конфиги), применяемые поверх базы.

Подводные камни

ЗаблуждениеРеальность
«depends_on гарантирует готовность БД»depends_on ждёт только запуск процесса, не готовность. Используй condition: service_healthy
«docker compose down удалит данные»По умолчанию volumes сохраняются. Для удаления: docker compose down -v
«Compose — это для production»Compose подходит для dev и простого prod. Для серьёзного production — Swarm/K8s
«Имя сервиса = имя контейнера»Имя контейнера = <project>_<service>_<replica>. Сервис — DNS-имя внутри сети