Продакшн-деплой Docker Compose: 7 ключевых стратегий от health checks до обновлений без простоя

DevOps

«Работает на моей машине» — Кладбище продакшн-контейнеров

Мантра каждого разработчика: «Работает на моей машине.» Но когда контейнеры попадают в продакшн, начинается настоящий кошмар:

  • Контейнеры тихо убиваются OOM Killer, оставляя в логах только Out of memory
  • База данных ещё не готова, контейнеры приложения кричат Connection refused
  • Контейнер падает в 3 часа ночи без политики перезапуска — сервис недоступен до утра
  • Файлы логов заполняют диски, docker logs выводит десятки ГБ неструктурированного текста
  • Продакшн-учётные данные в открытом виде внутри docker-compose.yml, пароли от БД раскрыты

Если вы всё ещё используете docker compose up -d как всю свою продакшн-стратегию — эта статья для вас.

Справочник ключевых концепций

Концепция Назначение Ключевая продакшн-конфигурация
Health Check Определить, действительно ли контейнер готов healthcheck + depends_on.condition
Лимиты ресурсов Ограничить CPU/память, предотвратить перерасход deploy.resources.limits
Политика перезапуска Автоперезапуск при аномальном завершении deploy.restart_policy
Secrets Шифрованное хранение конфиденциальных данных secrets + Docker Secret
Драйвер логирования Структурированное логирование + ротация логов logging.driver + logging.options
Profiles Выборочный запуск сервисов по окружению profiles
Watch Автосинхронизация изменений файлов в контейнеры watch (Compose Watch)

5 Продакшн-проблем

Проблема 1: Неконтролируемый порядок запуска контейнеров

База данных всё ещё инициализируется, пока контейнер приложения пытается подключиться, что приводит к ошибкам запуска. depends_on гарантирует только порядок запуска, а не готовность сервиса.

Проблема 2: Неограниченное потребление ресурсов

Контейнеры без лимитов ресурсов — как автомобили без тормозов. Один контейнер с утечкой памяти может потребить всю память хоста и положить все сервисы.

Проблема 3: Чёрная дыра логов

Драйвер логов json-file по умолчанию не выполняет ротацию. После 3 месяцев работы /var/lib/docker заполняет диск, и все сервисы падают.

Проблема 4: Утечка конфиденциальных данных

Пароли от БД в блоках environment в открытом виде, файлы .env закоммичены в Git, API-ключи захардкожены в образах — это бомбы замедленного действия для продакшн-инцидентов.

Проблема 5: Обновления означают простой

docker compose up -d по умолчанию останавливает старые контейнеры перед запуском новых, делая сервис недоступным во время обновлений. Для сервисов 24/7 это неприемлемо.

7 Продакшн-паттернов

Паттерн 1: Health checks и упорядочивание зависимостей

Проблема: depends_on управляет только порядком запуска, не гарантирует готовность сервиса.

Решение: Использовать healthcheck + depends_on.condition: service_healthy.

services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

  app:
    image: myapp:latest
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    ports:
      - "3000:3000"

Ключевые параметры:

  • interval: Интервал проверки, для продакшена рекомендуется 5-10 секунд
  • timeout: Таймаут одной проверки, рекомендуется 3-5 секунд
  • retries: Подряд идущие неудачи перед пометкой как unhealthy
  • start_period: Льготный период после запуска контейнера, неудачи не засчитываются

Паттерн 2: Лимиты ресурсов и защита от OOM

Проблема: Контейнеры без ограничений конкурируют за ресурсы хоста. Один неконтролируемый контейнер может положить всю машину.

Решение: Использовать deploy.resources для установки лимитов и резерваций CPU и памяти.

services:
  app:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 10s
      timeout: 5s
      retries: 3

  worker:
    image: myworker:latest
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        reservations:
          memory: 512M

Лимиты vs Резервации:

  • limits: Жёсткий потолок, превышен → OOM Kill или CPU throttling
  • reservations: Мягкая гарантия, планировщик пытается выполнить, но не принуждает

Стратегия защиты от OOM:

services:
  critical-service:
    image: critical-app:latest
    deploy:
      resources:
        limits:
          memory: 1G
    cap_add:
      - SYS_PTRACE

На уровне хоста настройте vm.overcommit_memory и скорректируйте политики OOM:

# Проверить OOM Score контейнера
docker inspect --format='{{.State.OOMKilled}}' <container_id>

# Установить политику OOM хоста: не убивать критические процессы
echo -1000 > /proc/<pid>/oom_score_adj

Паттерн 3: Структурированное логирование и ротация логов

Проблема: Драйвер логов json-file по умолчанию не выполняет ротацию; диски заполняются со временем.

Решение: Настроить драйвер логов + политику ротации. Для продакшена рекомендуется драйвер local.

services:
  app:
    image: myapp:latest
    logging:
      driver: local
      options:
        max-size: "10m"
        max-file: "5"
        tag: "{{.Name}}/{{.ID}}"

  nginx:
    image: nginx:1.27-alpine
    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "10"
        tag: "nginx/{{.Name}}"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro

Сравнение драйверов логов:

Драйвер Случай использования Преимущества Недостатки
local Продакшн по умолчанию Авто-ротация, сжатое хранение Только локально
json-file Нужны структурированные JSON-логи Нативная поддержка Docker Требуется ручная настройка ротации
syslog Централизованный сбор логов Можно отправлять удалённо Сложная конфигурация
fluentd Интеграция со стеком EFK Гибкая маршрутизация логов Требуется развёртывание Fluentd

Структурированное логирование на уровне приложения:

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

ENV TZ=UTC
ENV LOG_FORMAT=json

CMD ["node", "server.js"]
const logger = {
  info: (msg, meta = {}) => {
    console.log(JSON.stringify({ level: 'info', msg, ts: new Date().toISOString(), ...meta }));
  },
  error: (msg, meta = {}) => {
    console.error(JSON.stringify({ level: 'error', msg, ts: new Date().toISOString(), ...meta }));
  }
};

Паттерн 4: Управление Secrets

Проблема: Конфиденциальные данные хранятся в открытом виде в compose-файлах или переменных окружения.

Решение: Docker Secrets + переменные окружения с суффиксом _FILE.

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    file: ./secrets/api_key.txt
  jwt_secret:
    file: ./secrets/jwt_secret.txt

services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

  app:
    image: myapp:latest
    environment:
      DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@postgres:5432/appdb
      API_KEY_FILE: /run/secrets/api_key
      JWT_SECRET_FILE: /run/secrets/jwt_secret
    secrets:
      - api_key
      - jwt_secret

Управление файлами secrets:

# Создать директорию secrets
mkdir -p secrets
chmod 700 secrets

# Записать файлы secrets
echo "my-super-secret-password-2026" > secrets/db_password.txt
echo "ak-live-xxxx-yyyy-zzzz" > secrets/api_key.txt
echo "jwt-hs256-secret-key-here" > secrets/jwt_secret.txt

# Установить права: только для чтения root
chmod 600 secrets/*.txt

.gitignore должен включать:

secrets/
*.secret
.env.production
.env.staging

Сравнение Docker Secrets и .env:

Возможность Docker Secrets Файлы .env
Шифрованное хранение Да (в режиме Swarm) Нет
Файловые разрешения Ограничены (/run/secrets/) Зависит от файловой системы
Аудиторский след Да Нет
Межузловая синхронизация Swarm синхронизирует автоматически Ручное распространение
Случай использования Swarm/однохостовый продакшн Разработка

Паттерн 5: Rolling-обновления без простоя

Проблема: docker compose up -d по умолчанию останавливает старые контейнеры перед запуском новых.

Решение: Использовать docker compose up --no-down + health checks + обратный прокси.

services:
  app:
    image: myapp:${APP_VERSION:-latest}
    deploy:
      replicas: 2
      update_config:
        parallelism: 1
        delay: 10s
        order: start-first
        failure_action: rollback
      rollback_config:
        parallelism: 0
        order: stop-first
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 5s
      timeout: 3s
      retries: 3
      start_period: 15s
    labels:
      - "com.toolsku.app=true"
    ports:
      - "3000-3001:3000"

  nginx:
    image: nginx:1.27-alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      app:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/health"]
      interval: 10s
      timeout: 3s
      retries: 3

Конфигурация обратного прокси Nginx:

upstream app_backend {
    server app:3000;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://app_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_next_upstream error timeout http_502 http_503;
    }

    location /health {
        access_log off;
        return 200 'ok';
        add_header Content-Type text/plain;
    }
}

Скрипт обновления без простоя:

#!/bin/bash
set -euo pipefail

NEW_IMAGE="myapp:v2.0.0"
echo "🚀 Запуск обновления без простоя до ${NEW_IMAGE}"

# 1. Загрузить новый образ
docker compose pull app

# 2. Запустить новые контейнеры (не останавливая старые)
docker compose up -d --no-deps --scale app=2 app

# 3. Дождаться готовности новых контейнеров
echo "⏳ Ожидание готовности новых контейнеров..."
sleep 15

# 4. Проверить здоровье нового контейнера
for i in $(seq 1 30); do
  if curl -sf http://localhost:3000/health > /dev/null 2>&1; then
    echo "✅ Новый контейнер здоров"
    break
  fi
  if [ $i -eq 30 ]; then
    echo "❌ Health check не прошёл, откат..."
    docker compose up -d --no-deps --scale app=1 app
    exit 1
  fi
  sleep 2
done

# 5. Уменьшить до 1 реплики
docker compose up -d --no-deps --scale app=1 app

echo "🎉 Обновление успешно завершено"

Паттерн 6: Стек мониторинга Prometheus + Grafana

Проблема: Работа в продакшне без мониторинга — как полёт вслепую — о проблемах вы узнаёте только из жалоб пользователей.

Решение: Развёртывание полного стека мониторинга Prometheus + Grafana.

services:
  prometheus:
    image: prom/prometheus:v2.52.0
    container_name: prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=30d'
      - '--storage.tsdb.retention.size=5GB'
    deploy:
      resources:
        limits:
          memory: 512M
    networks:
      - monitoring

  grafana:
    image: grafana/grafana:11.0.0
    container_name: grafana
    restart: unless-stopped
    ports:
      - "3001:3000"
    environment:
      GF_SECURITY_ADMIN_USER: admin
      GF_SECURITY_ADMIN_PASSWORD_FILE: /run/secrets/grafana_password
    secrets:
      - grafana_password
    volumes:
      - grafana_data:/var/lib/grafana
    deploy:
      resources:
        limits:
          memory: 256M
    depends_on:
      - prometheus
    networks:
      - monitoring

  node-exporter:
    image: prom/node-exporter:v1.8.0
    container_name: node-exporter
    restart: unless-stopped
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--path.rootfs=/rootfs'
    networks:
      - monitoring

  alertmanager:
    image: prom/alertmanager:v0.27.0
    container_name: alertmanager
    restart: unless-stopped
    ports:
      - "9093:9093"
    volumes:
      - ./monitoring/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
    networks:
      - monitoring

secrets:
  grafana_password:
    file: ./secrets/grafana_password.txt

volumes:
  prometheus_data:
  grafana_data:

networks:
  monitoring:
    driver: bridge

Конфигурация Prometheus:

# monitoring/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "alert_rules.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - alertmanager:9093

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']

  - job_name: 'app'
    static_configs:
      - targets: ['app:3000']
    metrics_path: /metrics

Правила алертов:

# monitoring/alert_rules.yml
groups:
  - name: container_alerts
    rules:
      - alert: ContainerDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Container {{ $labels.instance }} is down"

      - alert: HighMemoryUsage
        expr: process_resident_memory_bytes / (1024 * 1024) > 400
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Memory usage exceeds 400MB on {{ $labels.instance }}"

      - alert: DiskSpaceLow
        expr: node_filesystem_avail_bytes / node_filesystem_size_bytes < 0.1
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Disk space below 10% on {{ $labels.instance }}"

Паттерн 7: Мультиоконружение (dev/staging/prod)

Проблема: Конфигурации dev, staging и продакшна смешаны — изменение конфигурации одного окружения рискует затронуть другие.

Решение: Использовать docker-compose.override.yml + стратегию многофайлового наложения.

Структура директорий:

project/
├── docker-compose.yml              # Базовая конфигурация
├── docker-compose.override.yml     # Переопределение для dev (загружается автоматически)
├── docker-compose.staging.yml      # Переопределение для staging
├── docker-compose.prod.yml         # Переопределение для продакшна
├── .env                            # Переменные окружения по умолчанию
├── .env.staging                    # Переменные окружения staging
├── .env.prod                       # Переменные окружения продакшна
├── monitoring/
│   ├── prometheus.yml
│   └── alertmanager.yml
└── secrets/
    ├── db_password.txt
    ├── api_key.txt
    └── grafana_password.txt

Базовая конфигурация docker-compose.yml:

services:
  app:
    image: myapp:${APP_VERSION:-latest}
    environment:
      NODE_ENV: ${NODE_ENV:-development}
      DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@postgres:5432/appdb
      REDIS_URL: redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - app-network

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks:
      - app-network

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

volumes:
  postgres_data:

networks:
  app-network:
    driver: bridge

Переопределение для dev docker-compose.override.yml (загружается автоматически):

services:
  app:
    build: .
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - "3000:3000"
      - "9229:9229"
    environment:
      NODE_ENV: development
      LOG_LEVEL: debug
    deploy:
      resources:
        limits:
          memory: 512M
    command: node --inspect=0.0.0.0:9229 server.js

  adminer:
    image: adminer:latest
    ports:
      - "8080:8080"
    networks:
      - app-network

Переопределение для продакшна docker-compose.prod.yml:

services:
  app:
    image: myapp:${APP_VERSION}
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: production
      LOG_LEVEL: info
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: '2.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
    logging:
      driver: local
      options:
        max-size: "10m"
        max-file: "5"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 15s

  postgres:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          memory: 1G
    logging:
      driver: local
      options:
        max-size: "50m"
        max-file: "10"

  redis:
    deploy:
      resources:
        limits:
          memory: 512M
    command: redis-server --appendonly yes --maxmemory 400mb --maxmemory-policy allkeys-lru
    volumes:
      - redis_data:/data
    logging:
      driver: local
      options:
        max-size: "10m"
        max-file: "3"

  nginx:
    image: nginx:1.27-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.prod.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      app:
        condition: service_healthy
    deploy:
      resources:
        limits:
          memory: 128M
    logging:
      driver: local
      options:
        max-size: "50m"
        max-file: "10"

volumes:
  redis_data:

Команды запуска:

# Разработка (автозагрузка override)
docker compose up -d

# Staging
docker compose -f docker-compose.yml -f docker-compose.staging.yml --env-file .env.staging up -d

# Продакшн
docker compose -f docker-compose.yml -f docker-compose.prod.yml --env-file .env.prod up -d

5 Частых ошибок

Ошибка 1: depends_on не означает готовность сервиса

Неправильно:

services:
  app:
    depends_on:
      - postgres
    # Контейнер postgres запущен, но БД может быть ещё не инициализирована

Правильно:

services:
  app:
    depends_on:
      postgres:
        condition: service_healthy
  postgres:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s

Ошибка 2: Нет лимитов ресурсов

Неправильно:

services:
  app:
    image: myapp:latest
    # Без лимитов ресурсов — одна утечка памяти может потребить весь хост

Правильно:

services:
  app:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 128M

Ошибка 3: Нет ротации логов

Неправильно:

services:
  app:
    image: myapp:latest
    # Драйвер json-file по умолчанию, логи растут бесконечно

Правильно:

services:
  app:
    image: myapp:latest
    logging:
      driver: local
      options:
        max-size: "10m"
        max-file: "5"

Ошибка 4: Конфиденциальные данные в открытом виде

Неправильно:

services:
  postgres:
    environment:
      POSTGRES_PASSWORD: "my-secret-password-123"
      # Пароль в открытом виде в compose-файле — катастрофа при коммите в Git

Правильно:

services:
  postgres:
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

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

Ошибка 5: Использование тега latest

Неправильно:

services:
  app:
    image: myapp:latest
    # Каждый pull может получить другой образ — невоспроизводимо

Правильно:

services:
  app:
    image: myapp:2.1.0
    # Или использовать переменную для управления версиями
    image: myapp:${APP_VERSION:-2.1.0}

Справочник устранения ошибок

Сообщение об ошибке Причина Решение
OOMKilled Контейнер превысил лимит памяти Увеличить лимит memory или оптимизировать использование памяти приложением
Connection refused Зависимый сервис не готов Добавить healthcheck + depends_on.condition
no space left on device Логи/образы заполняют диск Настроить ротацию logging + docker system prune
Цикл restarting Приложение падает при запуске Проверить docker logs <id> и проверить конфигурацию
permission denied Проблема с правами доступа к файлу/директории Проверить директиву user и права томов
port is already allocated Конфликт портов Изменить маппинг портов или остановить конфликтующий процесс
Статус unhealthy Health check не проходит Убедиться, что команда healthcheck корректна
secret not found Файл secret отсутствует Убедиться, что соответствующий файл существует в secrets/
Cannot connect to the Docker daemon Docker не запущен systemctl start docker
image pulling failed Ошибка загрузки образа Проверить сеть/авторизацию в registry/написание имени образа

Расширенная оптимизация

Docker Compose Watch для разработки

Compose Watch автоматически синхронизирует изменения файлов в контейнеры без пересборки образов:

services:
  app:
    build: .
    develop:
      watch:
        - action: sync
          path: ./src
          target: /app/src
        - action: rebuild
          path: ./package.json
        - action: sync+restart
          path: ./config
          target: /app/config
# Запустить режим watch
docker compose watch

Сетевая изоляция и безопасность

services:
  app:
    networks:
      - frontend
      - backend

  postgres:
    networks:
      - backend
    # postgres не в сети frontend — внешний доступ заблокирован

  nginx:
    networks:
      - frontend
    ports:
      - "80:80"

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true
    # internal:true отключает внешний доступ

Оптимизация образов с многоэтапной сборкой

# ---- Этап сборки ----
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# ---- Этап выполнения ----
FROM node:20-alpine AS runner
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && \
    adduser -S appuser -u 1001 -G appgroup

COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

USER appuser
EXPOSE 3000

HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

CMD ["node", "dist/server.js"]

Сравнение инструментов оркестрации

Возможность Docker Compose Kubernetes Nomad Docker Swarm
Сложность Низкая Высокая Средняя Низкая
Деплой на одном хосте ✅ Отлично ❌ Избыточно ⚠️ Приемлемо ✅ Отлично
Мультихостовая оркестрация ❌ Не поддерживается ✅ Основная возможность ✅ Основная возможность ⚠️ Базово
Автомасштабирование ✅ HPA/VPA ⚠️ Вручную
Rolling updates ⚠️ Требуются скрипты ✅ Нативно ✅ Нативно ✅ Нативно
Service discovery ⚠️ DNS ✅ CoreDNS ✅ Consul ✅ DNS
Оркестрация хранилища ✅ CSI ✅ CSI ⚠️ Базово
Кривая обучения Низкая Высокая Средняя Низкая
Масштаб 1-10 сервисов 100+ сервисов 50+ сервисов 10-50 сервисов
Готовность к продакшну ✅ Один хост ✅ Крупный масштаб ✅ Средний-крупный масштаб ⚠️ Сокращающееся сообщество

Рекомендация: Используйте Docker Compose для однохостового/маломасштабного продакшна, Kubernetes — для крупного масштаба, Nomad — если вы в экосистеме HashiCorp. Docker Swarm всё больше маргинализируется — не рекомендуется для новых проектов.

Итоги

Продакшн-деплой Docker Compose — это не просто docker compose up -d. Health checks гарантируют реальную готовность сервисов, лимиты ресурсов предотвращают OOM-лавины, ротация логов избегает исчерпания диска, Secrets защищают конфиденциальные данные, обновления без простоя гарантируют доступность 24/7, стеки мониторинга устраняют слепые зоны, а мультиоконружение разделяет dev/staging/prod. Освойте эти 7 стратегий, и Docker Compose вполне способен на продакшн-деплои малого и среднего масштаба.

Рекомендуемые инструменты

  • Форматирование JSON - Форматировать JSON-конфигурации, связанные с Docker Compose YAML
  • Кодирование Base64 - Кодировать Secrets и конфиденциальные данные конфигурации
  • Калькулятор хешей - Генерировать контрольные суммы файлов конфигурации для обеспечения согласованности деплоев

Попробуйте эти локальные браузерные инструменты — регистрация не требуется →

#Docker#Docker Compose#生产部署#容器编排#2026#DevOps