Перейти к содержанию
Innovialabs

Docker Compose: как запускать многоконтейнерные приложения

Практика3 мин

Коротко

Docker Compose описывает все контейнеры проекта в одном YAML-файле и поднимает их одной командой docker compose up. Сервисы видят друг друга по имени, данные хранятся в volumes, настройки — в .env.

Что такое Docker Compose

Docker Compose — инструмент, который описывает несколько контейнеров в одном файле compose.yaml и управляет ими как единым приложением. Вместо трёх длинных команд docker run с флагами вы пишете конфигурацию один раз и запускаете всё через docker compose up.

Типичный набор для веб-проекта: приложение, база данных (PostgreSQL) и кэш (Redis). Соберём его по шагам.

Шаг 1: сервис приложения

services:
  app:
    build: .
    ports:
      - "3000:3000"
    env_file: .env
  • build: . — собрать образ из Dockerfile в текущей папке.
  • ports — пробросить порт контейнера на хост: хост:контейнер.
  • env_file — загрузить переменные окружения из файла.

Шаг 2: база данных и volume

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"]
      interval: 5s
      retries: 5

volumes:
  db-data:
  • image — готовый официальный образ, собирать ничего не нужно.
  • ${...} — значения подставляются из файла .env рядом с compose-файлом.
  • Именованный volume db-data хранит данные вне контейнера: пересоздание контейнера их не удалит.
  • healthcheck проверяет, что база действительно готова принимать подключения. $$ экранирует $, чтобы переменную раскрыл shell внутри контейнера.

Шаг 3: кэш

  cache:
    image: redis:7

Порт наружу не пробрасываем: Redis нужен только приложению.

Шаг 4: depends_on и порядок запуска

Добавьте в сервис app:

    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started

Обычный depends_on гарантирует только порядок старта контейнеров, а не готовность сервиса. Условие service_healthy ждёт, пока healthcheck базы пройдёт успешно. Приложению всё равно полезно уметь переподключаться к базе — это надёжнее.

Сети: как сервисы находят друг друга

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

POSTGRES_USER=app
POSTGRES_PASSWORD=change-me
POSTGRES_DB=app
DATABASE_URL=postgres://app:change-me@db:5432/app
REDIS_URL=redis://cache:6379

localhost внутри контейнера указывает на сам контейнер — частая причина ошибки «connection refused». Файл .env добавьте в .gitignore, а в репозитории держите .env.example.

Отдельные сети через ключ networks нужны, когда сервисы надо изолировать друг от друга, например фронтенд от базы.

Команды на каждый день

КомандаЧто делает
docker compose up -dЗапустить всё в фоне
docker compose up -d --buildПересобрать образы и запустить
docker compose psСписок сервисов и их статус
docker compose logs -f appЛоги сервиса в реальном времени
docker compose exec db psql -U appВыполнить команду в работающем контейнере
docker compose downОстановить и удалить контейнеры и сеть
docker compose down -vТо же, плюс удалить volumes — данные базы пропадут

Частые ошибки

  • localhost вместо имени сервиса в строке подключения.
  • Пароли прямо в compose.yaml, закоммиченные в Git.
  • down -v «на всякий случай» — и потеря локальной базы.
  • Проброс порта базы наружу на сервере без необходимости.
  • Ожидание, что depends_on без healthcheck дождётся готовности базы.

Частые вопросы

Да, для небольших проектов на одном сервере это рабочий вариант. Когда нужны несколько серверов, автомасштабирование и rolling-обновления, обычно переходят на оркестратор.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.