Docker Compose для продакшена на сервере: частые ошибки и решения
Стек на Docker Compose работает в разработке, а на сервере ведёт себя коварно: после перезагрузки половина контейнеров лежит, база внезапно потеряла данные, приложение убивается по памяти, а логи разрослись и съели диск. Эти ошибки Docker Compose для продакшена на сервере типичны, и у каждой есть понятная причина. Разберём их по схеме «симптом — причина — решение».
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →С чего начинать диагностику
Первым делом посмотрите, в каком состоянии контейнеры и почему они в нём оказались. Команда статуса показывает, что запущено, что упало и что нездорово:
docker compose ps
docker compose logs --tail=100 web
Если контейнер перезапускается по кругу, статус будет мигать между Restarting и Exited. Чтобы понять причину выхода, смотрите код завершения и последние строки лога конкретного сервиса. Отдельно полезно проверить, не упирается ли что-то в память или диск на самом хосте:
docker stats --no-stream
df -h
Эти четыре команды закрывают большинство вопросов диагностики: они показывают, какой сервис падает, из-за чего, и хватает ли серверу ресурсов. Держа их под рукой, вы отличите ошибку конфигурации от нехватки железа. Дальше разберём частые симптомы по отдельности.
Контейнеры не поднимаются после перезагрузки
Классика продакшена: сервер перезагрузился по обновлению или сбою, а сервисы не встали. Причина почти всегда одна — не задана политика перезапуска. Без неё контейнер после остановки хоста так и остаётся лежать.
Добавьте каждому сервису политику unless-stopped, которая поднимает контейнер и после сбоя, и после перезагрузки:
services:
web:
image: myapp:1.4.0
restart: unless-stopped
Вторая причина — не включён автозапуск самого демона Docker. Если служба Docker не стартует при загрузке системы, никакая политика внутри не поможет. Проверьте и включите:
systemctl is-enabled docker
systemctl enable docker
Третья, более тонкая ситуация — контейнеры стартуют, но приложение падает, потому что зависимый сервис (например, база) ещё не готов. Это отдельная проблема гонки запуска, и решается она проверками здоровья, о которых ниже. После настройки политики перезапуска и автозапуска демона перезагрузка перестаёт быть проблемой: весь стек поднимается сам.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
Арендовать VPSКонтейнер убивается по памяти (OOM Killed)
Пугающий симптом: сервис внезапно падает, в статусе Exited (137), а в системном логе — сообщение OOM Killed. Число 137 означает, что процесс убит по нехватке памяти. Причин две, и они противоположны по решению.
Первая — у контейнера нет лимита памяти, он разросся и был убит системой, когда память сервера кончилась. Проверьте потребление:
docker stats --no-stream
dmesg | grep -i oom
Правильное решение — задать лимиты памяти каждому сервису, чтобы прожорливый контейнер убивался в одиночку, не утягивая соседей, и чтобы вы сразу видели виновника:
deploy:
resources:
limits:
memory: 512M
Вторая причина — лимит есть, но занижен, и нормально работающему сервису его не хватает. Здесь нужно, наоборот, поднять лимит под реальные потребности. Ключевой вопрос — хватает ли памяти всему серверу. Если суммарные потребности контейнеров превышают RAM хоста, никакая настройка лимитов не спасёт: вы лишь выбираете, кого убивать первым. Это прямой сигнал, что проекту нужен VPS с большим объёмом памяти.
Потеря данных при пересоздании контейнера
Самая болезненная ошибка: обновили образ базы, контейнер пересоздался — и данные пропали. Причина в том, что данные хранились внутри контейнера, а не в томе. Всё, что не вынесено в volume, живёт только пока существует контейнер, и при пересоздании исчезает.
Данные обязательно монтируют в именованный том, объявленный отдельно. Тогда контейнер можно пересоздавать сколько угодно — том остаётся:
services:
db:
image: postgres:16
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Частая тонкая ошибка — неверный путь монтирования: том подключён не к тому каталогу, где сервис реально хранит данные. Для Postgres это /var/lib/postgresql/data, для других сервисов — свой путь, и его нужно смотреть в документации образа. Проверьте, что тома существуют и данные в них есть:
docker volume ls
docker volume inspect db_data
И помните: наличие тома — не замена бэкапам. Том защищает от пересоздания контейнера, но не от повреждения данных, ошибочного удаления или гибели диска. Настройте регулярное резервное копирование содержимого томов отдельно.
Гонка запуска и неверный depends_on
Симптом: при старте стека приложение падает с ошибкой подключения к базе, но если запустить его повторно, всё работает. Это классическая гонка: приложение стартовало раньше, чем база была готова принимать соединения. Многие думают, что depends_on решает это, но обычный depends_on лишь задаёт порядок запуска, не дожидаясь готовности сервиса.
Правильное решение — условие service_healthy вместе с проверкой здоровья у зависимости:
services:
web:
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
Теперь приложение стартует только после того, как база прошла проверку и реально готова. Дополнительно закладывайте в само приложение устойчивость к временной недоступности зависимостей — повтор подключения с задержкой. Это защищает не только при старте, но и когда база кратковременно перезапускается в процессе работы. Комбинация healthcheck и повторов делает стек устойчивым к гонкам.
Логи съели диск и другие эксплуатационные грабли
Неожиданный сбой: всё работало, а потом сервер встал из-за нехватки места, и виноваты разросшиеся логи контейнеров. По умолчанию Docker пишет логи без ограничения размера, и болтливый сервис за недели заполняет диск. Проверьте, что занимает место:
df -h
du -sh /var/lib/docker/containers/*/*.log
Решение — ограничить размер и ротацию логов, глобально в настройках демона или на уровне сервиса в compose-файле:
services:
web:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Другие частые эксплуатационные грабли: накопление старых неиспользуемых образов, которые тоже едят диск (чистится через docker image prune), и публикация портов контейнеров прямо в интернет вместо привязки к localhost за реверс-прокси. И общий вывод: значительная часть «ошибок Docker Compose» на сервере — это на деле нехватка ресурсов, когда контейнерам тесно по памяти или диску. Тонкая настройка выжимает максимум из имеющегося железа, но когда потолок достигнут, надёжнее взять VPS с запасом RAM и быстрым NVMe. У MAATRIX такие серверы доступны в локациях RU, US и UK с оплатой из России картой или криптой.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
Арендовать VPSОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Почему контейнеры не поднимаются после перезагрузки сервера?
Не задана политика перезапуска или не включён автозапуск демона Docker; добавьте restart: unless-stopped и systemctl enable docker.
Что означает Exited (137) и OOM Killed?
Контейнер убит по нехватке памяти; задайте лимиты памяти сервисам, а если ресурсов не хватает всему серверу — увеличьте объём RAM.
Почему при обновлении образа пропали данные базы?
Данные хранились внутри контейнера, а не в томе; монтируйте их в именованный volume по правильному пути и делайте бэкапы.
Почему depends_on не спасает от ошибки подключения к базе?
Обычный depends_on не ждёт готовности; используйте condition: service_healthy с healthcheck у зависимости и повторы подключения в приложении.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.