← назад к разделу

Реальное приложение редко запускается само по себе. Ему нужна база данных, брокер сообщений, кэш. Docker Compose позволяет описать все эти сервисы в одном файле и запустить их вместе — одной командой.

Проблема: запускать всё вручную утомительно

Представьте типичное окружение для разработки: Spring Boot приложение, Postgres, Kafka, Zookeeper. Без Compose каждый участник команды вручную запускает каждый контейнер, передаёт правильные переменные окружения, пробрасывает порты, следит за порядком запуска. При смене машины или переключении между проектами всё повторяется заново.

Классическая жалоба — «на моей машине работает». Чаще всего причина в том, что локальное окружение отличается от коллежского: другая версия Postgres, другой порт, другая переменная окружения. Docker Compose решает именно эту проблему: конфигурация окружения лежит в файле в репозитории и воспроизводима на любой машине.

Короткая формула: один файл docker-compose.yml — одна команда docker compose up — готовое окружение.

Что такое Docker Compose

Docker Compose — инструмент для описания и запуска многоконтейнерных приложений. Вы описываете все нужные сервисы, их настройки, связи между ними и тома в одном YAML-файле. Compose читает этот файл и управляет жизненным циклом всех контейнеров: запуск, остановка, пересборка.

Начиная с Docker Desktop и актуальных версий Docker Engine, Compose встроен в CLI как плагин — команда выглядит как docker compose (без дефиса).

Структура docker-compose.yml

Рассмотрим минимальный пример: Spring Boot приложение + Postgres.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: myapp
      POSTGRES_PASSWORD: secret
    ports:
      - "5432:5432"        # порт хоста : порт контейнера
    volumes:
      - postgres_data:/var/lib/postgresql/data  # том для хранения данных между перезапусками
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myapp"]
      interval: 5s
      timeout: 5s
      retries: 10

  app:
    image: myapp:latest    # или build: . — если собирать из Dockerfile
    environment:
      SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/myapp
      SPRING_DATASOURCE_USERNAME: myapp
      SPRING_DATASOURCE_PASSWORD: secret
    ports:
      - "8080:8080"
    depends_on:
      db:
        condition: service_healthy  # ждём, пока Postgres не пройдёт healthcheck

volumes:
  postgres_data:

Разберём ключевые блоки.

services

services — главный раздел файла. Каждый ключ внутри — имя сервиса (db, app). Это имя одновременно является именем хоста внутри сети Compose: из контейнера app можно обратиться к базе данных просто по имени db. Никаких IP-адресов прописывать не нужно — Compose создаёт внутреннюю DNS-запись автоматически.

image и build

image указывает, какой образ использовать. Если образ ещё нужно собрать из Dockerfile, используйте build: . вместо image (или вместе с ним для задания имени тега). Для приложения при разработке часто удобнее собирать образ налету:

  app:
    build:
      context: .
      dockerfile: Dockerfile

environment

environment задаёт переменные окружения внутри контейнера. Spring Boot читает переменные окружения и использует их как свойства конфигурации: SPRING_DATASOURCE_URL соответствует spring.datasource.url в application.properties.

Длинный список переменных удобно выносить в файл .env и ссылаться на него через env_file: .env.

ports

ports пробрасывает порт из контейнера на хост. Формат "хост:контейнер". Если вам не нужен доступ к Postgres с хоста (только из приложения внутри сети Compose), блок ports для базы можно убрать — контейнеры всё равно видят друг друга по имени сервиса.

volumes

volumes в секции сервиса монтирует том или директорию хоста внутрь контейнера. В примере выше именованный том postgres_data хранит данные Postgres между перезапусками. Именованные тома объявляются в разделе volumes верхнего уровня.

Для разработки удобно монтировать директорию с кодом:

volumes:
  - ./src:/app/src   # изменения в коде сразу видны в контейнере

healthcheck

healthcheck задаёт команду проверки готовности сервиса. Compose периодически запускает её внутри контейнера и отмечает сервис как healthy только после успешного прохождения.

Без healthcheck зависимость depends_on срабатывает, когда контейнер запущен, но Postgres ещё не принимает соединения — приложение упадёт с ошибкой подключения. С healthcheck и condition: service_healthy Compose дождётся реальной готовности базы.

depends_on

depends_on управляет порядком запуска. В простейшем виде:

depends_on:
  - db

Но это только гарантирует, что контейнер db запущен раньше app. Для гарантии готовности используйте расширенный вариант с condition:

depends_on:
  db:
    condition: service_healthy

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

# запустить все сервисы в фоне
docker compose up -d

# посмотреть логи всех сервисов (или конкретного: ... logs db)
docker compose logs -f

# остановить и удалить контейнеры (тома сохраняются)
docker compose down

# остановить и удалить контейнеры вместе с томами
docker compose down -v

# пересобрать образ и перезапустить
docker compose up -d --build

# выполнить команду внутри запущенного контейнера
docker compose exec db psql -U myapp

Сети в Compose

По умолчанию Compose создаёт одну общую сеть для всех сервисов файла. Все контейнеры в этой сети видят друг друга по именам сервисов. Вы можете явно описывать несколько сетей — например, чтобы изолировать часть сервисов:

services:
  app:
    networks:
      - frontend
      - backend
  db:
    networks:
      - backend

networks:
  frontend:
  backend:

Подробнее о сетях — в статье Сети в Docker.

Пример: Spring Boot + Postgres с профилем разработки

Полный docker-compose.yml для локальной разработки Spring Boot приложения:

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_DB: orders
      POSTGRES_USER: orders
      POSTGRES_PASSWORD: dev_secret
    ports:
      - "5432:5432"
    volumes:
      - pg_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U orders"]
      interval: 5s
      retries: 10

  app:
    build: .
    environment:
      SPRING_PROFILES_ACTIVE: dev
      SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/orders
      SPRING_DATASOURCE_USERNAME: orders
      SPRING_DATASOURCE_PASSWORD: dev_secret
      SPRING_JPA_HIBERNATE_DDL_AUTO: validate
    ports:
      - "8080:8080"
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ~/.m2:/root/.m2  # кэш Maven между перезапусками сборки

volumes:
  pg_data:

Команда docker compose up -d поднимет Postgres, дождётся его готовности и только потом запустит приложение. Логи обоих контейнеров будут доступны через docker compose logs -f.

Коротко

  • Docker Compose описывает многоконтейнерное окружение в одном YAML-файле и запускает его одной командой.
  • Сервисы видят друг друга по именам, заданным в services: — DNS-резолюция работает автоматически.
  • healthcheck + depends_on: condition: service_healthy гарантируют, что зависимый сервис стартует после реальной готовности базы.
  • volumes сохраняют данные между перезапусками контейнеров.
  • environment передаёт конфигурацию — Spring Boot читает переменные окружения напрямую как свойства.
  • docker compose down останавливает и удаляет контейнеры, тома при этом сохраняются; down -v удаляет и тома.
  • Файл docker-compose.yml коммитится в репозиторий — окружение воспроизводимо на любой машине.

Что почитать дальше

  • Сети в Docker — как устроены сети между контейнерами, как их изолировать.
  • Тома и хранение данных — типы томов, bind mounts, когда что использовать.
  • Запуск контейнеров — флаги docker run, управление жизненным циклом контейнера.