Перейти к основному содержимому
Вернуться в категорию

Руководство по Docker Compose: Управление многоконтейнерными приложениями

Определение и управление многоконтейнерными приложениями с Docker Compose: зависимости сервисов, переменные окружения, проверки работоспособности, масштабирование и развёртывание в production. Полное руководство.

Время чтения: 16 мин DevOps и автоматизация
docker-composedockerконтейнерyamldevopsмикросервисdeployment
Автор
REXE Teknoloji Network & Security Team
Редактор
REXE Teknoloji Technical Editorial
Первая публикация
Последнее обновление

Руководство по Docker Compose: Управление многоконтейнерными приложениями

Docker Compose — инструмент, позволяющий определять и управлять несколькими Docker-контейнерами с помощью единого YAML-файла. Он незаменим для микросервисных архитектур, веб-приложений и сред разработки.

Что такое Docker Compose?

С Docker Compose вы можете:

  • Определять несколько сервисов в одном файле docker-compose.yml
  • Управлять зависимостями между сервисами
  • Централизованно управлять конфигурациями сетей и томов
  • Запускать/останавливать весь стек одной командой

Docker Compose v2 запускается командой docker compose (без дефиса) и интегрирован в Docker CLI. Старая команда docker-compose по-прежнему поддерживается.

Базовая структура docker-compose.yml

hljs yaml
version: '3.9'

services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    restart: unless-stopped

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: секретный_пароль
      MYSQL_DATABASE: моё_приложение
    volumes:
      - db_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  db_data:

Сервисы, тома и сети

Определение сервисов

hljs yaml
services:
  app:
    build:
      context: ./app
      dockerfile: Dockerfile
    image: моё-приложение:latest
    container_name: app-container
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: production
      DB_HOST: database
    depends_on:
      database:
        condition: service_healthy
    networks:
      - app-network
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

Определение томов

hljs yaml
volumes:
  # Именованный том (управляется Docker)
  db_data:
    driver: local

  # Внешний том (предварительно созданный)
  existing_volume:
    external: true

  # Пользовательские параметры драйвера
  nfs_volume:
    driver: local
    driver_opts:
      type: nfs
      o: addr=192.168.1.100,rw
      device: ":/nfs/share"

Определение сетей

hljs yaml
networks:
  # Стандартная bridge-сеть
  app-network:
    driver: bridge

  # С пользовательской подсетью
  custom-net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

  # Внешняя сеть
  existing-net:
    external: true

depends_on и Healthcheck

Управляйте порядком запуска сервисов с помощью depends_on:

hljs yaml
services:
  web:
    image: nginx:alpine
    depends_on:
      api:
        condition: service_healthy
      db:
        condition: service_healthy

  api:
    build: ./api
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: пароль
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

depends_on контролирует только порядок запуска. Без condition: service_healthy нельзя гарантировать готовность сервиса.

Переменные окружения и env_file

Прямое определение

hljs yaml
services:
  app:
    image: моё-приложение:latest
    environment:
      - NODE_ENV=production
      - PORT=3000
      - DB_HOST=database
      - DB_PORT=5432

Использование файла .env

hljs yaml
services:
  app:
    image: моё-приложение:latest
    env_file:
      - .env
      - .env.production

Файл .env:

hljs bash
# .env
NODE_ENV=production
DB_HOST=database
DB_PORT=5432
DB_NAME=моё_приложение
DB_USER=пользователь
DB_PASS=секретный_пароль
JWT_SECRET=очень_секретный_ключ
REDIS_URL=redis://redis:6379

Добавьте .env в .gitignore. Никогда не коммитьте конфиденциальную информацию в Git.

Масштабирование (--scale)

Вы можете горизонтально масштабировать сервисы с Docker Compose:

hljs bash
# Запустить сервис api с 3 экземплярами
docker compose up -d --scale api=3

# Изменить количество запущенных экземпляров
docker compose up -d --scale api=5

# Масштабировать конкретный сервис
docker compose scale api=3 worker=2

Конфигурация балансировщика нагрузки для масштабирования:

hljs yaml
services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - api

  api:
    build: ./api
    # Не определяйте ports — nginx будет маршрутизировать
    expose:
      - "3000"
    environment:
      NODE_ENV: production

Override-файлы

Используйте override-файлы для разных окружений:

hljs yaml
# docker-compose.override.yml (разработка)
services:
  app:
    build:
      context: .
      target: development
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      NODE_ENV: development
    command: npm run dev

  db:
    ports:
      - "5432:5432"  # Открыть наружу в разработке
hljs yaml
# docker-compose.prod.yml (production)
services:
  app:
    image: registry.example.com/моё-приложение:latest
    restart: always
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '1.0'
          memory: 1G

Использование:

hljs bash
# Разработка (override применяется автоматически)
docker compose up -d

# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Лучшие практики для production

Полный пример для production

hljs yaml
version: '3.9'

services:
  nginx:
    image: nginx:1.25-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - certbot_data:/etc/letsencrypt:ro
    depends_on:
      - api
    restart: always
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  api:
    image: registry.example.com/api:${APP_VERSION:-latest}
    env_file: .env.production
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: always
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M

  db:
    image: postgres:15-alpine
    env_file: .env.production
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 256mb --maxmemory-policy allkeys-lru
    volumes:
      - redis_data:/data
    restart: always
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3

volumes:
  postgres_data:
  redis_data:
  certbot_data:

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

hljs bash
# Запустить все сервисы
docker compose up -d

# Запустить конкретный сервис
docker compose up -d api

# Следить за логами
docker compose logs -f
docker compose logs -f api

# Остановить сервисы
docker compose down

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

# Перезапустить сервис
docker compose restart api

# Просмотреть статус сервисов
docker compose ps

# Выполнить команду в сервисе
docker compose exec api bash

# Пересобрать образы
docker compose build --no-cache
docker compose up -d --build

# Проверить конфигурацию
docker compose config

Заключение

Docker Compose — наиболее практичный способ управления многоконтейнерными приложениями. Он обеспечивает согласованную среду от разработки до production. С override-файлами можно гибко настраивать разные окружения, а с healthcheck и depends_on — безопасно управлять зависимостями сервисов.

Часто задаваемые вопросы

Что делает команда docker compose config?

'docker compose config' показывает итоговую конфигурацию после применения всех override-файлов и переменных окружения. Полезна для отладки и проверки правильности конфигурации.

Я использую depends_on, но сервис пытается подключиться до готовности зависимости. Почему?

'depends_on' по умолчанию ждёт только запуска контейнера, а не его готовности. Используйте 'condition: service_healthy', чтобы ждать прохождения healthcheck. Также рекомендуется добавить логику повторных попыток в приложение.

Подходит ли Docker Compose для production?

Docker Compose подходит для развёртывания на одном сервере. Если нужна оркестрация на нескольких серверах, предпочтительнее Kubernetes или Docker Swarm. Docker Compose широко используется в production для приложений малого и среднего масштаба.

Как переменные из файла .env используются в docker-compose.yml?

Docker Compose автоматически читает файл .env в том же каталоге. Обращайтесь к значениям с синтаксисом '${VARIABLE_NAME}'. Например: 'image: myapp:${APP_VERSION:-latest}'. Используйте ':-' для значений по умолчанию.

Как избежать конфликтов портов при масштабировании сервисов?

Используйте 'expose' вместо 'ports' для масштабируемых сервисов. Expose открывает порт только для внутренней сети. Направляйте внешний трафик через балансировщик нагрузки (nginx, traefik). Так несколько экземпляров могут использовать один и тот же внутренний порт.

В чём разница между docker compose down и docker compose stop?

'docker compose stop' останавливает контейнеры, но не удаляет их. 'docker compose down' останавливает и удаляет контейнеры. Флаг '-v' также удаляет тома. 'stop' рекомендуется для разработки, 'down' следует использовать осторожно в production.

Связанные статьи

Автоматизация серверов с Ansible: Infrastructure as Code

Установка Ansible, файл инвентаря, написание playbook, структура ролей, переменные, зашифрованный vault, ad-hoc команды и автоматизация конфигурации серверов. Пошаговое руководство.

20 мин
ansibleавтоматизацияinfrastructure as code
Сетевой трафикВходящий GbpsИсходящий Gbps