Шаг 8 · Продакшен · 30 минут

Мониторинг без космолёта: узнаём о сбое раньше пользователя

Для первого проекта не нужен огромный стек наблюдаемости. Нужны четыре сигнала: сервер жив, диск не заполнен, контейнер работает, приложение отвечает снаружи.

Три уровня проверки

Инфраструктура — CPU, память и диск. Процесс — состояние контейнера и его перезапуски. Приложение — реальный HTTPS‑ответ. Если проверять только один уровень, можно пропустить проблему на другом.

1. Смотрим на сервер вручную

uptime
free -h
df -h
htop
sudo systemctl --failed

В uptime три числа load average показывают среднюю очередь задач за 1, 5 и 15 минут. Для одноядерного VPS постоянное значение заметно выше 1 требует внимания. В free -h ориентируйтесь на available, а не просто free: Linux использует свободную память под кэш.

Диск лучше не доводить выше 80–85%. При 100% перестают записываться логи и база, а приложение начинает вести себя странно.

2. Проверяем контейнеры

cd /home/deploy/app
docker compose ps
docker stats --no-stream
docker compose logs --tail=100

Состояние Up — процесс работает. Restarting означает цикл падений. Колонка STATUS с healthcheck надёжнее простого «процесс существует».

3. Добавляем endpoint здоровья

Простейший endpoint FastAPI:

@app.get("/health")
async def health():
    return {"status": "ok"}

В Compose:

healthcheck:
  test: ["CMD", "curl", "-f", "http://127.0.0.1:8000/health"]
  interval: 30s
  timeout: 5s
  retries: 3
  start_period: 20s

Если в образе нет curl, установите его или используйте проверку на Python. После изменения пересоберите контейнер и смотрите docker compose ps.

4. Проверяем снаружи

Внешний uptime‑сервис раз в несколько минут открывает https://example.ru/health. Настройте:

  • ожидаемый HTTP‑код 200;
  • проверку текста ok;
  • уведомление в Telegram или почту;
  • повторную проверку перед алертом, чтобы отсечь краткий сетевой шум.

Это важнее локального healthcheck: внешний монитор замечает проблемы DNS, сертификата, Nginx и самого VPS.

5. Читаем логи, а не гадаем

docker compose logs --since=30m bot
journalctl -p err -S today
journalctl -u nginx --since "1 hour ago"
sudo tail -n 100 /var/log/nginx/error.log

Читайте от симптома ко времени: когда пришёл алерт, какой код вернул Nginx, что писал контейнер за минуту до этого. Не складывайте в логи токены, пароли, полные сообщения пользователей и другие персональные данные.

6. Не даём логам съесть диск

В Compose задайте ротацию:

logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

После изменения контейнер нужно пересоздать. Проверьте занятое Docker место:

docker system df
sudo du -xh /var/lib/docker | sort -h | tail

7. Что делать при алерте

  1. Подтвердить проблему через браузер или curl.
  2. Проверить место, память и load average.
  3. Посмотреть состояние контейнера и последние логи.
  4. Если причина понятна — исправить минимальным действием.
  5. Если непонятна — сохранить логи, откатить последний релиз.
  6. После восстановления записать причину и профилактику.

Безопасная короткая диагностика:

date
uptime
free -h
df -h
docker compose ps
docker compose logs --tail=100

8. Регламент маленького проекта

  • постоянно: внешний uptime и уведомления;
  • раз в неделю: диск, ошибки, доступные security‑обновления;
  • раз в месяц: тест восстановления бэкапа;
  • перед релизом: бэкап и понятный план отката;
  • после сбоя: короткий разбор без поиска виноватых.
Хороший алерт отвечает на три вопроса: что сломалось, где смотреть подтверждение и какое первое безопасное действие выполнить.

Маршрут завершён

У вас есть защищённый VPS, контейнерный запуск, HTTPS, внешние копии и базовая наблюдаемость. Сохраните каталог RateHost как чек‑лист следующего проекта.