← Docker
15 мин · средне · Урок 7 из 8

Docker Compose

Описываем стек в yaml, поднимаем одной командой. depends_on, healthcheck, profiles, основные команды и граница с Kubernetes.

Зачем compose

Когда у тебя один сервис, docker run хватает. Когда два, три, пять, команда раздувается до десятка строк с тонной флагов, и воспроизводить её руками больно.

Compose решает это: один yaml-файл описывает весь стек, одна команда его поднимает.

docker compose up -d

Всё. Сети созданы, volume'ы подмонтированы, контейнеры запущены в правильном порядке.

Минимальный пример

services:
  api:
    build: .
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      DB_HOST: db
      REDIS_HOST: cache
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: example   # только для локальной разработки; в проде — секрет
      POSTGRES_DB: app
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
      interval: 5s
      timeout: 3s
      retries: 10
    restart: unless-stopped

  cache:
    image: redis:7-alpine
    restart: unless-stopped

volumes:
  pgdata:

Что произошло:

Ключевые поля сервиса

ПолеЧто значит
imageготовый образ из registry
buildпуть к Dockerfile / build-контекст (вместо image)
portsпубликация портов (см. урок про сети)
environmentпеременные окружения как map или список
env_fileподгрузить переменные из файла
volumesbind или named volume mounts
depends_onпорядок запуска и (опционально) ожидание healthcheck
networksв каких сетях участвует
restartполитика перезапуска
healthcheckпроверка живости контейнера
commandпереопределить CMD образа
entrypointпереопределить ENTRYPOINT образа
profilesв каких профилях сервис активен

depends_on и healthcheck

Сам по себе depends_on: [db] означает только «запусти db раньше». Это не значит «жди, пока db готова принимать соединения». Postgres стартует за несколько секунд, и api успеет упасть с connection refused.

Чтобы дождаться готовности, нужен healthcheck:

services:
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 10

  api:
    image: myapp
    depends_on:
      db:
        condition: service_healthy   # ← ждёт healthcheck

Возможные condition:

Volumes и networks в compose

Named volume объявляется на верхнем уровне и используется в сервисе:

services:
  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data    # named
      - ./initdb:/docker-entrypoint-initdb.d  # bind
volumes:
  pgdata:

Сети — так же. Если ничего не указано, compose создаёт <project>_default и все сервисы туда подключены. Если хочешь несколько:

services:
  web:
    networks: [public, db-net]
  db:
    networks: [db-net]
  admin:
    networks: [public]
networks:
  public:
  db-net:

Внешняя сеть нужна, чтобы общаться между разными compose-проектами:

networks:
  shared:
    external: true                # сеть уже существует, не создавай

Перед этим её надо создать вручную: docker network create shared.

Profiles: опциональные сервисы

Иногда нужны сервисы, которые не нужны в каждом запуске: admin-панель, worker для тяжёлых задач, инструменты дебага. Профили решают:

services:
  api:
    image: myapp
  db:
    image: postgres:16
  adminer:
    image: adminer
    profiles: [admin]
  pgcli:
    image: dbcli/pgcli
    profiles: [debug]
    depends_on: [db]

По умолчанию docker compose up поднимет только api и db. Чтобы включить админку:

docker compose --profile admin up -d
docker compose --profile admin --profile debug up -d

Основные команды

КомандаЧто делает
docker compose up [-d]создать и запустить стек
docker compose downостановить и удалить контейнеры + сети
docker compose down -vто же + удалить named volumes
docker compose psстатус сервисов
docker compose logs [-f] [service]логи; -f стримит
docker compose exec <svc> shзайти внутрь как docker exec
docker compose pullподтянуть новые версии образов
docker compose buildпересобрать образы из build:
docker compose configотрендерить итоговый yaml (после env-подстановок)
docker compose restart [service]перезапустить, не пересоздавая

Типичный апгрейд в проде:

docker compose pull && docker compose up -d

Pull тянет новые образы по тэгам, up -d пересоздаёт контейнеры с новыми образами. Volume'ы остаются, простой минимальный.

Несколько compose-файлов

Compose автоматически читает compose.yaml (или docker-compose.yml). Можно указать другой или склеить несколько:

docker compose -f compose.yaml -f compose.prod.yaml up -d

Второй файл переопределяет значения из первого. Типичный паттерн:

Граница с Kubernetes

Compose рассчитан на одну машину. Поднял стек локально или на одном сервере и пользуйся. Когда переезжаешь:

Про поле deploy: ходит миф, будто оно живёт только в Swarm. Compose v2 часть его исполняет сам: deploy.replicas, deploy.resources.limits и reservations, deploy.restart_policy. Игнорируются только Swarm-специфичные ключи: placement, endpoint_mode, mode: global.

services:
  web:
    image: myapp:1.0
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "0.5"
          memory: 512M

Столько же копий можно поднять и без правки файла:

docker compose up -d --scale web=3

Ловушка тут другая. Если у сервиса зафиксирован container_name или опубликован статичный порт (- "8080:80"), несколько копий не поднимутся: имя и порт заняты первой. Для масштабирования убирай container_name, а порт публикуй диапазоном или не публикуй вовсе, пуская трафик через reverse proxy.

Compose можно сконвертировать в kubernetes-манифесты через kompose. Это отправная точка, а не финальный результат: kompose часто генерит устаревшие apiVersion, переезд всё равно сопровождается переписыванием.

Что важно запомнить

docker compose up -d — одна команда вместо десятка docker run. yaml в репозитории = воспроизводимый стек.

depends_on без condition: service_healthy ждёт только запуска, не готовности. Для базы добавляй healthcheck.

down -v сносит volumes. В проде не запускай. Для prod-reset volumes делаются вручную с явным docker volume rm.

deploy.replicas и deploy.resources работают в обычном compose, Swarm для них не нужен. Быстрее всего копии поднимает docker compose up -d --scale web=3, но сначала убери у сервиса container_name и статичный проброс порта.

В следующем уроке — короткий квиз по всему, что прошли.

Самопроверка

Впишите команду / ключевую строку. Регистр и пробелы не важны.

1. Подними весь стек в фоне (compose-файл — в текущей папке).
2. Обнови образы всех сервисов и перезапусти стек.
3. Останови стек и удали тома вместе с контейнерами (полный reset).

Дрилл · вопросы как на собесе

Проверь себя без подсказок

Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.

01

Как ограничить ресурсы контейнера (CPU, RAM, IO, network)?

DOC-023
02

Что такое Docker-compose?

DOC-012
03

Веб-сервер в контейнере отдаёт 502 — где искать?

DOC-031

Прошли материал до конца? Отметьте урок пройденным.