Docker Compose

Зачем нужно

Docker Compose — инструмент для запуска нескольких контейнеров одной командой. Вместо десятка docker run команд ты описываешь все сервисы в одном YAML-файле и запускаешь docker compose up. Приложение + база данных + кэш = один файл конфигурации.

Где используется

  • Локальная разработка — полный стек одной командой
  • Тестирование — поднять окружение для интеграционных тестов
  • CI/CD — тестовое окружение в пайплайне
  • Демонстрации — быстрый показ проекта

docker-compose.yml

Базовая структура

# docker-compose.yml
version: '3.8'  # версия синтаксиса (можно опустить в новых версиях)

services:
  # Каждый сервис — отдельный контейнер
  app:
    build: .
    ports:
      - "3000:3000"

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: secret

Полный пример: Node.js + PostgreSQL + Redis

version: '3.8'

services:
  # === Приложение ===
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
      - REDIS_URL=redis://cache:6379
    volumes:
      - .:/app             # монтируем код для hot-reload
      - /app/node_modules  # но не перезаписываем node_modules
    depends_on:
      - db
      - cache
    restart: unless-stopped

  # === База данных ===
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  # === Кэш ===
  cache:
    image: redis:7-alpine
    ports:
      - "6379:6379"

# === Именованные тома ===
volumes:
  postgres_data:

Ключевые секции

services — сервисы

services:
  web:
    # Из образа Docker Hub
    image: nginx:alpine

  app:
    # Собрать из Dockerfile
    build: .
    # или с параметрами
    build:
      context: ./backend
      dockerfile: Dockerfile.dev
      args:
        NODE_VERSION: 20

ports — проброс портов

services:
  app:
    ports:
      - "3000:3000"     # host:container
      - "9229:9229"     # debug порт

volumes — тома и маунты

services:
  app:
    volumes:
      - .:/app                    # bind mount (для разработки)
      - /app/node_modules         # анонимный том
      - app_data:/app/data        # именованный том

  db:
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  app_data:
  db_data:

environment — переменные окружения

services:
  app:
    # Способ 1: список
    environment:
      - NODE_ENV=development
      - API_KEY=abc123

    # Способ 2: словарь
    environment:
      NODE_ENV: development
      API_KEY: abc123

    # Способ 3: из файла
    env_file:
      - .env
      - .env.local

networks — сети

services:
  frontend:
    networks:
      - frontend_net

  backend:
    networks:
      - frontend_net
      - backend_net

  db:
    networks:
      - backend_net     # недоступна из frontend

networks:
  frontend_net:
  backend_net:

depends_on — порядок запуска

services:
  app:
    depends_on:
      db:
        condition: service_healthy   # ждать healthcheck
      cache:
        condition: service_started   # просто запустился

  db:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 5s
      timeout: 5s
      retries: 5

Команды Docker Compose

# === Запуск ===
docker compose up              # запуск (с логами)
docker compose up -d           # запуск в фоне (detached)
docker compose up --build      # пересобрать образы и запустить
docker compose up app          # запустить только сервис app

# === Остановка ===
docker compose down            # остановить и удалить контейнеры
docker compose down -v         # + удалить volumes
docker compose stop            # остановить без удаления

# === Логи ===
docker compose logs            # все логи
docker compose logs app        # логи конкретного сервиса
docker compose logs -f app     # следить за логами (follow)

# === Выполнение команд ===
docker compose exec app sh            # зайти в контейнер
docker compose exec app npm test       # запустить тесты
docker compose exec db psql -U user    # подключиться к БД

# === Информация ===
docker compose ps              # список контейнеров
docker compose top             # процессы в контейнерах
docker compose config          # проверить конфигурацию

# === Масштабирование ===
docker compose up -d --scale app=3    # запустить 3 экземпляра

Пример: фронтенд + бэкенд + БД

version: '3.8'

services:
  # React frontend
  frontend:
    build: ./frontend
    ports:
      - "5173:5173"
    volumes:
      - ./frontend:/app
      - /app/node_modules
    environment:
      - VITE_API_URL=http://localhost:4000

  # Express backend
  backend:
    build: ./backend
    ports:
      - "4000:4000"
    volumes:
      - ./backend:/app
      - /app/node_modules
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/app
      - JWT_SECRET=dev-secret
    depends_on:
      db:
        condition: service_healthy

  # PostgreSQL
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: app
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./backend/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d app"]
      interval: 5s
      timeout: 5s
      retries: 5

  # Adminer (GUI для БД)
  adminer:
    image: adminer
    ports:
      - "8080:8080"
    depends_on:
      - db

volumes:
  pgdata:

Файл .env для Compose

# .env (рядом с docker-compose.yml)
POSTGRES_USER=user
POSTGRES_PASSWORD=secret
POSTGRES_DB=myapp
NODE_ENV=development
# docker-compose.yml
services:
  db:
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

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

Ошибка Проблема Решение
depends_on не ждёт готовности Контейнер запущен, но сервис не готов Используй condition: service_healthy
Потеря данных БД при down Данные в контейнере Используй именованные volumes
node_modules пустой Volume перезаписывает Добавь /app/node_modules как анонимный volume
Порт уже занят Конфликт портов Смени порт хоста: "3001:3000"
Изменения кода не видны Нет bind mount Добавь volumes: - .:/app

Практика

  1. Создай docker-compose.yml для Node.js + MongoDB
  2. Добавь Adminer для просмотра базы данных через браузер
  3. Настрой hot-reload через bind mount для разработки
  4. Используй healthcheck для ожидания готовности БД
  5. Создай .env файл и вынеси туда все переменные

Связанные темы

Ресурсы