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

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

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

Время чтения: 16 мин DevOps и автоматизация
docker-composedockerконтейнерyamldevopsмикросервисdeployment

Содержание

Руководство по 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 — безопасно управлять зависимостями сервисов.