Перейти к содержанию
Innovialabs

Docker Compose в продакшене на одном VPS: как сделать правильно

Практика4 мин

Коротко

Docker Compose на одном VPS вполне подходит для продакшена, если настроить автоперезапуск, healthcheck, ротацию логов, HTTPS через reverse proxy, регулярные бэкапы томов и понятную процедуру обновления.

Можно ли использовать Compose в продакшене

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

Политика перезапуска

Без неё контейнер не поднимется после падения или перезагрузки сервера.

services:
  app:
    image: registry.example.com/app:1.4.2
    restart: unless-stopped
  • unless-stopped — перезапуск всегда, кроме случаев, когда вы остановили контейнер вручную. Хороший выбор по умолчанию.
  • always — поднимет даже то, что вы остановили руками, после рестарта Docker.
  • on-failure — только при ненулевом коде выхода.

Также проверьте, что сам Docker стартует при загрузке: systemctl enable docker.

Секреты и env-файлы

Не храните пароли в docker-compose.yml и в Git. Вынесите их в .env или отдельный файл:

services:
  app:
    env_file: .env.production

Файл с секретами — права 600, добавлен в .gitignore. В репозитории держите .env.example с пустыми значениями, чтобы было видно, какие переменные нужны.

Healthcheck

restart реагирует только на падение процесса. Если приложение зависло, но процесс жив, поможет healthcheck:

services:
  app:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 5s
      retries: 3
  worker:
    depends_on:
      db:
        condition: service_healthy

Учтите: в обычном Docker без Swarm статус unhealthy сам по себе контейнер не перезапускает. Он нужен для depends_on, мониторинга и ваших скриптов. Утилита curl должна быть в образе — или используйте другую проверку.

Ротация логов

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

x-logging: &logging
  driver: json-file
  options:
    max-size: "10m"
    max-file: "5"

services:
  app:
    logging: *logging

Можно задать то же глобально в /etc/docker/daemon.json, но это применится только к новым контейнерам.

Reverse proxy и HTTPS

Не публикуйте порт приложения наружу. Наружу смотрят только 80 и 443 у reverse proxy, а приложение доступно лишь во внутренней сети Compose.

Варианты:

ПроксиЧем удобен
Caddyполучает и продлевает сертификаты Let's Encrypt автоматически, минимальный конфиг
Traefikнастраивается через labels контейнеров, сам находит сервисы
Nginx + certbotпривычный и гибкий, но продление сертификатов настраивается отдельно

Если всё же нужен порт для отладки, привяжите его к localhost: "127.0.0.1:3000:3000". Помните, что Docker пишет свои правила iptables и опубликованный порт может обойти UFW.

Обновления без долгого простоя

Используйте конкретные теги образов, а не latest — так понятно, что запущено, и легко откатиться.

Порядок обновления:

docker compose pull app
docker compose up -d app
docker image prune -f

Сначала скачивается новый образ, пока старый контейнер работает, затем контейнер пересоздаётся — простой сводится к времени старта приложения. Если и это критично, запустите две копии за прокси и обновляйте их по очереди. Миграции базы данных делайте обратно совместимыми, чтобы старая и новая версии кода могли работать с одной схемой.

Бэкапы томов

Данные живут в volumes, и они не переживут гибель диска или сервера.

  • Базы данных бэкапьте штатными средствами (pg_dump, mysqldump), а не копированием файлов работающей БД.
  • Файлы из томов архивируйте и отправляйте за пределы сервера — в объектное хранилище или на другую машину.
  • Запускайте бэкап по расписанию (cron или systemd timer) и следите за ошибками.
  • Периодически проверяйте восстановление на чистом сервере: непроверенный бэкап — это надежда, а не бэкап.

Когда одного сервера мало

Пора думать о нескольких серверах или оркестраторе, если:

  • простой при обслуживании или сбое железа стал недопустим;
  • нагрузку уже не вытянуть вертикальным ростом VPS;
  • нужно независимо масштабировать отдельные сервисы;
  • команда часто выкатывает изменения и нужны канареечные релизы.

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

Частые вопросы

Для одного сервера и небольшой команды Compose проще в настройке и сопровождении. Kubernetes оправдан, когда серверов несколько, нужна отказоустойчивость и есть люди, готовые его поддерживать.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.