Почему падает деплой или контейнер
Большинство проблем распознаются по одному признаку: на каком этапе всё пошло не так. Ниже разбор по этапам. Начните с того, чтобы понять, где именно остановилось; для этого есть логи.
Где смотреть причину
- Логи сборки: показываются в реальном времени во время деплоя. Здесь видно, собрался ли образ.
- Логи выполнения: хвост логов работающего контейнера в реальном времени. Здесь видно, что происходит после запуска.
- Статус сервиса:
running,errorи другие. - Telegram-алерты: платформа присылает уведомления о падении, нехватке памяти и провале деплоя, если вы подключили бота.
Дальше идут частые случаи по этапам.
Сборка не проходит
Образ не собрался, до запуска дело не дошло. Смотрите логи сборки, типичные причины:
- Зависимость не объявлена. Пакет есть локально, но не записан в манифест (
requirements.txt,package.json,composer.json). Добавьте и закоммитьте. - Нет команды запуска. Сборщик не знает, чем запускать приложение. См. подготовку кода и статью по вашему стеку.
- Ошибка компиляции (например, в сборке TypeScript). Причина видна в самих логах сборки, ближе к концу.
- «Не поняли, чем собирать проект». В корне репозитория нет файла, по которому определяется стек. Проверьте, что манифест лежит именно в корне и закоммичен: частый случай, когда он попал под правило в
.gitignore.
Собралось, но домен отдаёт 502
Сборка прошла, контейнер запущен, но по домену возникает ошибка 502. Почти всегда это порт: приложение слушает не тот порт или только localhost. Условие простое: слушать порт из переменной PORT на адресе 0.0.0.0. Подробно с примерами в подготовке кода.
Домен отвечает, но приходит не то
Сборка прошла, статус зелёный, домен открывается. Но вместо ответа приложения приходит содержимое сайта: на /api/… возвращается HTML вместо JSON, а POST отвечает 405 Method Not Allowed. Это значит, что ваш серверный код не запущен, а запросы обслуживает веб-сервер, раздающий собранные файлы.
Причина одна: у сервиса выбран тип «Статический сайт», хотя в репозитории есть свой сервер. Типичный случай, когда Express и фронтенд на Vite/React лежат в одном репозитории. Нужен тип «Сервер с HTTP». Пока не было успешного развёртывания, тип меняется в настройках сервиса, после этого потребуется создать сервис заново. Подробнее в статье «Статический сайт».
Контейнер перезапускается (краш-луп)
Контейнер поднимается и почти сразу падает, снова поднимается, и так по кругу. Смотрите логи выполнения: причина видна в них. Частые случаи:
- Не задана переменная окружения, которую читает код (токен, строка подключения). Задайте её и передеплойте, см. «Переменные окружения».
- Приложение падает с исключением при старте: ошибка в коде инициализации, недоступная база данных, неверные параметры подключения.
- Не проходит health-check. Если вы включили проверку, но путь или порт указаны неверно, платформа считает контейнер нездоровым и перезапускает его. Проверьте путь проверки или временно отключите её, см. типы сервисов.
Контейнеру не хватает памяти
Иногда контейнер перезапускается из-за нехватки памяти. Типовые приложения укладываются в ресурсы проекта, поэтому сначала проверьте, не расходует ли приложение память сверх необходимого. Чаще всего причина в коде:
- Слишком много рабочих процессов. Серверы вроде
gunicornпо умолчанию запускают несколько воркеров, и каждый держит копию приложения в памяти. Задайте разумное число явно (например,gunicorn --workers 2): часто это главный источник расхода. - Данные грузятся в память целиком. Большие файлы, выборки из базы, ответы внешних API стоит обрабатывать потоково или порциями, а не загружать полностью.
- Утечки памяти. Потребление растёт со временем: проверьте, что ресурсы (соединения, буферы) освобождаются.
Этих шагов почти всегда достаточно. Повышать тариф стоит только тогда, когда приложению много памяти нужно по самой его задаче: обработка больших объёмов данных, машинное обучение. Это выбор под конкретную нагрузку, а не обязательное условие работы.
После деплоя пропали данные
Это не сбой, а ожидаемое поведение: файловая система контейнера обнуляется при каждом деплое и перезапуске. Постоянные данные нужно хранить в базе данных проекта. Подробно и с решением в «Данные не сохраняются в контейнере».
Маршрут диагностики
| Что видите | Куда смотреть | Частая причина |
|---|---|---|
| Деплой завершился ошибкой | Логи сборки | Зависимости или команда запуска |
| Деплой успешен, домен отдаёт 502 | не требуется | Порт / привязка к 0.0.0.0 |
| Домен отвечает, но API отдаёт HTML | не требуется | Выбран тип «Статический сайт» вместо «Сервер с HTTP» |
Сервис в статусе error, перезапуски | Логи выполнения | Переменные окружения, ошибка при старте, health-check |
| Работал, потом упал сам | Логи выполнения, Telegram-алерт | Нехватка памяти или необработанное исключение |
| Пропали данные | не требуется | Данные хранились в файлах контейнера |