DevOps

Docker Compose в продакшене: практическое руководство для небольших команд в 2026 году

Ruslan Ismailov Опубликовано 10 мин чтения
D

Введение: Docker Compose в 2026 году — жив и актуален

Разговоры о том, что Docker Compose «устарел» и годится только для локальной разработки, ведутся уже несколько лет. Тем не менее в 2026 году тысячи стартапов и небольших команд успешно используют его для продакшен-развёртываний. И это не от незнания альтернатив — это осознанный выбор.

Docker Compose остаётся актуальным инструментом там, где важна простота, скорость итерации и минимальные операционные издержки. Kubernetes мощнее, но за мощью стоит сложность: обучение команды, поддержка кластера, настройка RBAC, Helm-чарты. Для команды из двух-пяти человек это зачастую избыточно.

В этой статье мы разберём, как выстроить production-ready инфраструктуру на Docker Compose: от архитектуры файлов до CI/CD и мониторинга, и честно обсудим, когда всё-таки пора смотреть в сторону Kubernetes.

Docker Compose v2 vs v3: ключевые отличия и что использовать сейчас

Долгое время существовала путаница между версиями схемы Compose-файла (v2, v3) и версиями самого инструмента. В 2026 году ситуация прояснилась: Docker официально перешёл на единую спецификацию Compose Specification, которая объединила лучшее из обоих миров.

Что изменилось на практике

  • Поле version больше не обязательно и фактически игнорируется новыми версиями Docker Compose v2+. Его можно убрать из файлов.
  • Директива depends_on теперь поддерживает условия (condition: service_healthy), что делает её полноценным инструментом управления порядком запуска.
  • Секреты и конфиги получили нативную поддержку — не только для Swarm, но и для обычного Compose.
  • Команда docker-compose (с дефисом, Python-версия) устарела. Используйте docker compose (плагин, написанный на Go) — он быстрее и активно поддерживается.

Вывод прост: в 2026 году пишите файлы по Compose Specification без поля version, используйте docker compose вместо docker-compose.

Архитектура production-ready Compose-файла

Хороший продакшен-файл — это не просто список сервисов. Это декларация того, как ваше приложение должно вести себя под нагрузкой, при падении и при обновлении.

Пример базовой структуры

services:
  app:
    image: registry.example.com/myapp:${APP_VERSION:-latest}
    restart: unless-stopped
    networks:
      - internal
      - proxy
    environment:
      - DATABASE_URL=${DATABASE_URL}
    secrets:
      - db_password
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    depends_on:
      db:
        condition: service_healthy
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    networks:
      - internal
    volumes:
      - pg_data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    networks:
      - internal
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes

  nginx:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    networks:
      - proxy
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - certbot_data:/etc/letsencrypt

networks:
  internal:
    driver: bridge
    internal: true
  proxy:
    driver: bridge

volumes:
  pg_data:
  redis_data:
  certbot_data:

secrets:
  db_password:
    file: ./secrets/db_password.txt

Ключевые элементы архитектуры

  • Сети: разделяйте внутреннюю сеть (сервисы между собой) и внешнюю (проксирование). Флаг internal: true запрещает контейнерам в этой сети выходить в интернет — хорошая практика для баз данных.
  • Volumes: всегда используйте именованные тома для данных, требующих персистентности. Никогда не храните продакшен-данные в bind mounts.
  • Health checks: обязательны для любого сервиса, от которого зависят другие. Без них depends_on проверяет только факт запуска контейнера, а не готовность приложения.
  • Restart policies: unless-stopped — разумный дефолт для продакшена. Он перезапускает контейнер при падении, но не трогает его при ручной остановке.
  • Resource limits: ограничивайте CPU и память. Без лимитов один сервис может съесть все ресурсы хоста.

Секреты и конфигурации: безопасное управление переменными окружения

Передача секретов через переменные окружения в .env-файле — самая распространённая ошибка. Такие файлы попадают в репозиторий, в логи CI, в историю команд. В продакшене нужен другой подход.

Уровни управления секретами

  1. Docker Secrets (нативно): файлы монтируются в /run/secrets/ контейнера. Поддерживаются в обычном Compose (не только в Swarm). Показаны в примере выше.
  2. Внешние хранилища: HashiCorp Vault, AWS Secrets Manager, Doppler. Секреты получаются в момент деплоя и передаются как файлы или через environment.
  3. Переменные окружения CI/CD: GitLab CI, GitHub Actions и другие системы позволяют хранить секреты на уровне проекта. В момент деплоя они подставляются в нужные места.

Практическая схема для небольшой команды

Минимальная безопасная схема: секреты хранятся в переменных GitLab/GitHub, при деплое записываются в файлы на сервере, Compose читает их через механизм secrets. Файл .env содержит только несекретные настройки (имена образов, порты, имена баз данных) и может быть в репозитории.

# .env (безопасно коммитить)
APP_VERSION=1.4.2
DB_NAME=myapp_prod
REDIS_MAX_MEMORY=256mb

# secrets/db_password.txt (НЕ коммитить, в .gitignore)
# Создаётся скриптом деплоя из CI/CD переменных

Обновление сервисов без даунтайма

Docker Compose не имеет встроенного rolling update, как Kubernetes. Но нулевой даунтайм достижим при правильной архитектуре.

Стратегия blue-green через nginx

Самый простой подход: держать reverse proxy (nginx или Traefik) снаружи, а приложение обновлять с кратким переключением:

# Обновление без даунтайма
docker compose pull app
docker compose up -d --no-deps --build app

Флаг --no-deps обновляет только указанный сервис без перезапуска зависимостей. Docker сначала запускает новый контейнер, убеждается в прохождении healthcheck, затем останавливает старый. При наличии health check даунтайм сводится к секундам.

Traefik как умный прокси

Для более гладких обновлений многие команды используют Traefik вместо Nginx. Traefik читает лейблы Docker-контейнеров и автоматически перенаправляет трафик на здоровые инстанции:

  app:
    image: registry.example.com/myapp:${APP_VERSION}
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app.rule=Host(`example.com`)"
      - "traefik.http.services.app.loadbalancer.healthcheck.path=/health"

Интеграция с CI/CD пайплайном

Автоматический деплой через Docker Compose в CI/CD — это не rocket science. Типовая схема: сборка образа → пуш в registry → SSH на сервер → docker compose up.

Пример GitLab CI/CD pipeline

stages:
  - build
  - deploy

build:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  only:
    - main

deploy:
  stage: deploy
  script:
    - echo "$DB_PASSWORD" > secrets/db_password.txt
    - export APP_VERSION=$CI_COMMIT_SHORT_SHA
    - docker compose pull
    - docker compose up -d --no-deps app
    - docker compose exec app php artisan migrate --force
  environment:
    name: production
  only:
    - main

Обратите внимание: миграции базы данных запускаются после старта контейнера, но до переключения трафика — это важный порядок. Если используете Laravel или другой фреймворк с системой миграций, убедитесь в их идемпотентности.

Rollback

Откат в Compose-мире тривиален: достаточно поменять тег образа на предыдущий и повторить docker compose up. Фиксируйте теги образов в переменных, не используйте latest в продакшене.

Мониторинг и логирование контейнеров

«Мониторинг — это не опционально в продакшене» — банальная, но справедливая истина. Docker Compose не даёт мониторинг из коробки, но интегрируется с популярными решениями без лишних сложностей.

Логирование

Настройте драйвер логирования на уровне сервиса или глобально в /etc/docker/daemon.json:

  app:
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "5"

Для централизованного логирования: Loki + Grafana — отличный выбор для небольших команд. Promtail собирает логи Docker-контейнеров и отправляет в Loki. Вся связка поднимается тем же Compose.

Метрики

Стек Prometheus + Grafana стал стандартом де-факто. Добавьте в Compose-файл:

  • cAdvisor — метрики контейнеров (CPU, RAM, сеть)
  • Node Exporter — метрики хоста
  • Prometheus — сбор и хранение метрик
  • Grafana — визуализация

Весь стек мониторинга можно вынести в отдельный docker-compose.monitoring.yml и запускать через docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d.

Алерты

Alertmanager (часть экосистемы Prometheus) или простой uptimerobot.com для базовых проверок доступности — достаточно для большинства небольших проектов. Настройте уведомления в Slack или Telegram.

Когда пора переходить на Kubernetes: честные критерии

Docker Compose — отличный инструмент, но у него есть реальные ограничения. Вот честный список сигналов, что пора смотреть в сторону Kubernetes:

Технические триггеры

  • Нужен горизонтальный масштаб: вы хотите запускать 5, 10, 50 реплик одного сервиса на разных машинах. Compose работает на одном хосте. Docker Swarm — промежуточный вариант, но в 2026 году его развитие замедлилось.
  • Требуется автомасштабирование: HPA (Horizontal Pod Autoscaler) в Kubernetes реагирует на нагрузку автоматически. В Compose нужно менять реплики вручную.
  • Сложная оркестрация: десятки сервисов с разными версиями, сложными зависимостями и независимыми циклами деплоя — Kubernetes с Helm значительно удобнее.
  • Multi-region или multi-node: как только появляется потребность в нескольких серверах для одного приложения, Compose перестаёт быть достаточным.
  • Жёсткие SLA: если у вас SLA 99.99%, нужны механизмы автоматического восстановления, rolling updates без даунтайма и circuit breakers — всё это в Kubernetes нативно.

Организационные триггеры

  • Команда выросла до 10+ человек и нескольких независимых команд
  • Появился выделенный DevOps/Platform инженер
  • Количество микросервисов перевалило за 15-20
  • Нужна изоляция окружений (dev/staging/prod) с разными ресурсами на уровне кластера

Когда НЕ нужен Kubernetes

Если ваш монолит или набор из 3-5 сервисов обслуживает 10 000 пользователей в день на одном сервере — Docker Compose справляется отлично. Переход на Kubernetes добавит минимум 2-4 недели на настройку и постоянные операционные издержки. Это время лучше потратить на продукт.

Заключение

Docker Compose в 2026 году — это зрелый, надёжный инструмент для продакшен-развёртываний небольших команд. При правильной архитектуре: разделённые сети, именованные тома, health checks, управление секретами и интеграция с CI/CD — он обеспечивает стабильную работу приложений без операционной сложности Kubernetes.

Ключевые принципы, которые стоит запомнить:

  1. Используйте docker compose (плагин v2) без поля version в файле
  2. Разделяйте сети на внутренние и внешние
  3. Никогда не передавайте секреты через .env-файлы в репозитории
  4. Health checks — обязательны, не опциональны
  5. Фиксируйте версии образов, не используйте latest
  6. Автоматизируйте деплой через CI/CD с первого дня
  7. Добавьте мониторинг до первого инцидента, а не после

Kubernetes — мощный инструмент, но его время приходит с масштабом. Не усложняйте раньше времени. Compose даёт 80% возможностей при 20% сложности — и для большинства небольших команд это идеальное соотношение.

Технологии

Теги

Руслан Исмаилов

Senior Web / Backend разработчик. Senior web/backend разработчик с 9-летним опытом. Стек: PHP, Laravel, PostgreSQL, Redis, Docker, Kubernetes, REST, микросервисы, CI/CD. Подробнее обо мне →