Наблюдаемость: метрики, ошибки и аналитика
Оглавление · Введение в DevOps
Статус: конфигурация разрабатывается в отдельной ветке; наличие файла не означает публикацию или проверку сервиса на VPS.
Аналитика отвечает на вопрос, какие страницы посещают люди. Сбор ошибок помогает найти место исключения. Метрики показывают состояние системы во времени. Логи описывают отдельные события. Трассировки связывают шаги одного запроса; в первом этапе проекта они не подключаются.
Prometheus собирает метрики, Grafana строит графики и проверяет правила алертов. Node Exporter читает метрики Linux, Blackbox Exporter выполняет HTTP-проверки. Umami предназначен для посещений, GlitchTip — для ошибок Next.js. Все хранилища размещаются на нашем VPS.
Как читать сигнал
/api/health отвечает, что приложение работает. /api/content-health читает
коллекции Strapi без кеша. Кешированная страница может открываться при недоступной
CMS — эти проверки специально разделены. Полная проверка контента выполняется
раз в пять минут, чтобы сама диагностика не создавала лишнюю нагрузку.
Prometheus использует pull: сам запрашивает /metrics у exporter. Label обозначает
измерение, например сервис или экземпляр. Не используйте ID посетителей и полный
URL с query как labels: число временных рядов будет постоянно расти.
Пример PromQL для доли доступной памяти:
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes
Сравнивайте available, а не только free: Linux использует свободную память для кеша. Панель без данных требует проверки источника; её нельзя трактовать как нулевую нагрузку.
Алерт и уведомление
Алерт — состояние правила. Уведомление — доставка этого состояния человеку. Наши правила доступны в Grafana; внешняя доставка по умолчанию отключена. Краткий сбой сначала переводит правило в pending; после выдержки — в firing; устранение причины возвращает его в нормальное состояние.
Telegram будет отдельным практическим упражнением. Создание бота и передача его токена не нужны для штатного деплоя. Не отправляйте в сообщения логи, payload CMS, cookies и секреты. Полный отказ VPS делает недоступными и приложения, и мониторинг.
Где находятся конфигурации
| Файл | Ответственность |
|---|---|
infra/observability/compose.yaml | Сервисы, лимиты, сети и тома |
infra/observability/images.env | Закреплённые версии и digest |
infra/observability/prometheus.yaml | Интервалы сбора и HTTP-цели |
infra/observability/blackbox.yaml | Timeout и ожидаемые ответы |
infra/observability/grafana/provisioning | Источник, правила и политика доставки |
scripts/deploy/observability.sh | Отдельный релиз под общей блокировкой |
scripts/check-observability.sh | Изолированная проверка контейнеров в CI |
Новый стек использует существующую PostgreSQL, но разные базы и роли umami
и glitchtip. Скрипт подготовки сначала проверяет обе роли и владельцев баз;
потом создаёт только отсутствующие объекты. Существующий пароль не сбрасывается.
Данные Strapi не являются данными аналитики и не выдаются её роли.
У нового стека два сетевых назначения. Частная сеть соединяет Prometheus,
exporters и Grafana. Общая atmanki_default соединяет PostgreSQL, Caddy и
публичные приложения. Metrics endpoints не имеют опубликованных портов.
Доступ к панели Grafana не даёт пользователю доступ к Docker socket.
Дашборд и правила
| Правило | Причина | Выдержка |
|---|---|---|
| SiteUnavailable | HTTP-проверка web неуспешна | 2 минуты |
| CmsUnavailable | CMS /_health недоступен | 5 минут |
| ContentUnavailable | Чтение опубликованного контента неуспешно | 5 минут |
| DiskSpaceLow | Свободно менее 15% корневой FS | 5 минут |
| MemoryPressure | Доступно менее 10% памяти | 10 минут |
В файле правила A — PromQL-запрос, B — последнее значение, C — сравнение
с порогом. for задаёт выдержку. NoData и Error оставлены самостоятельными
состояниями: пропавший exporter нельзя показывать исправным.
Content scrape выполняется раз в пять минут. Запрос
last_over_time(probe_success{service="content"}[11m]) удерживает последний
результат между измерениями. Это также означает задержку обнаружения исчезнувшей
метрики до истечения окна; выдержка алерта добавляется отдельно.
Prometheus хранит историю семь дней, TSDB ограничена 1 GiB. WAL и временные
блоки занимают дополнительное место. Лимит истории не освобождает нас от проверки
df -h. GlitchTip удаляет старые события по своей политике 14 дней; история Umami
не имеет нашего автоматического планировщика очистки.
Аналитика и ошибки сайта
Umami подключён через Next Script после загрузки страницы. Сам трекер отслеживает
смену пути; второй обработчик React для того же просмотра не нужен. Допустимый
домен — gheilt.mxsource.xyz, query и hash исключены, Do Not Track учитывается.
В первоначальном наборе собираются просмотры; отдельного контракта пользовательских
событий пока нет. Аналитика не подключается к Storybook, документации и панели CMS.
Идентификатор сайта и браузерный DSN — публичные адреса приёмников, а не пароли
панелей. NEXT_PUBLIC_* встраиваются в JavaScript при сборке. После изменения
такой настройки нужен новый web-образ. Пустые параметры отключают интеграцию.
Серверный GLITCHTIP_DSN задаётся отдельно в environment контейнера.
Sentry SDK отправляет ошибки в наш GlitchTip. Мы используем allowlist полей:
сохраняем тип исключения, release и место в стеке; запросы, cookies, breadcrumbs,
user, extra и произвольные contexts не отправляются. Текст ошибки заменяется
нейтральным Application error: это уменьшает диагностическую детализацию,
зато не переносит содержимое ответа CMS в систему ошибок.
Source map связывает место в собранном JavaScript с исходником TypeScript.
release связывает событие с Git commit; debug ID связывает файл с загруженной
картой. Токен загрузки maps получает только CI через BuildKit secret. Проверять
нужно и browser, и server exception: наличие release в панели ещё не доказывает,
что конкретный стек правильно преобразован. После загрузки карты удаляются из
публичных ресурсов сборки. Приёмник и механизм загрузки должны быть совместимы.
Подготовка и выпуск
Следующие команды выполняются на подготовленном VPS администратором; они
не относятся к запуску локального сайта. Сначала доставьте проверенные release
файлы штатным workflow. Скрипт автоматически генерирует недостающие credentials
в /opt/gheilt/observability/.env с правами 0600, затем создаёт базы и запускает
стек. Конфликт роли/владельца/пароля останавливает подготовку.
Для аудита подготовки без изменений баз:
python3 /opt/gheilt/observability/current/scripts/deploy/provision-observability.py \
/opt/gheilt/observability/.env --dry-run
Dry-run по-прежнему читает каталоги PostgreSQL и проверяет credentials; он печатает только имена и действия. Он не проверяет миграции приложений.
До открытия маршрутов deploy-скрипт заменяет стандартный пароль Umami и создаёт
администратора GlitchTip admin@gheilt.mxsource.xyz. Пароли UMAMI_ADMIN_PASSWORD,
GLITCHTIP_ADMIN_PASSWORD и GRAFANA_ADMIN_PASSWORD хранятся только в серверном .env.
Повторный запуск проверяет их; конфликт останавливает deploy без сброса чужого пароля.
В GlitchTip после входа создайте проект.
Нельзя считать панель защищённой только потому, что у неё собственный поддомен.
Создайте Umami website для домена сайта, затем передайте его ID в CI variables.
Обычный application workflow выпустит web-образ с нужными browser settings.
Упражнение: Telegram
Это необязательное задание; рабочая конфигурация не требует токена бота. Telegram является внешним сервисом, даже если Grafana размещена у нас.
- Создайте учебного бота через BotFather и добавьте его в собственный учебный чат.
- В отдельной локальной Grafana создайте Telegram contact point: токен и chat ID. Не вставляйте токен в Git, скриншот или отчёт.
- Отправьте Test и убедитесь, что сообщение пришло в правильный чат.
- Создайте учебную notification policy, направляющую только учебное правило
этому contact point. Штатная
dashboard-onlypolicy всегда muted; просто добавление contact point ещё не включает доставку. - Укажите grouping по service/environment и repeat interval 1h. Включите resolved.
- Получите firing и resolved на учебной цели. Сравните время измерения, pending, firing и доставки: это разные моменты.
- Удалите учебное правило и contact point после упражнения либо сохраните их в отдельном учебном окружении. Production-конфигурацию не меняйте попутно.
Сообщение должно содержать имя правила, окружение, время начала и ссылку на инструкцию. Не используйте автоматическую вставку полного результата запроса, лога или ошибки datasource. Бот не должен выполнять команды на VPS.
Официальное подключение Telegram.
Упражнение: правило без сбоя сервера
В отдельной учебной Grafana используйте Prometheus query vector(0) и условие
«меньше 1», for: 1m. Это синтетическое значение, не статус настоящего сайта.
Через минуту правило станет firing. Замените запрос на vector(1) и проверьте
восстановление. Удалите правило. Не заполняйте диск и не останавливайте CMS,
чтобы продемонстрировать пороговое сравнение.
Затем поставьте vector(0.12) и условие «меньше 0.15»: это модель 12% свободного
места. Объясните, почему она срабатывает и почему не доказывает наличие проблемы
на настоящем VPS.
Упражнение: отсутствие данных
Создайте учебное правило по несуществующей метрике, задайте NoData как отдельное
состояние и посмотрите результат. Сравните с запросом vector(0): отсутствие ряда
не равно числу ноль. После проверки удалите правило.
Для настоящего отказа HTTP-цели используйте отдельный учебный контейнер в CI или отдельном локальном окружении. Остановите только его, дождитесь pending/firing, поднимите обратно и дождитесь восстановления. Не используйте публичный CMS как аварийную учебную цель.
Если данных нет
| Симптом | Что проверить |
|---|---|
| Нет метрик хоста | up, target Node Exporter, mounts /proc, /sys и host root |
| HTTP probe равен нулю | HTTP-код, TLS, DNS, timeout и маршрут Caddy |
| Content health падает, страница открывается | Чтение Strapi и актуальность кеша — разные пути |
| Нет посещений Umami | Website ID, разрешённый domain, Do Not Track, загрузку script |
| Нет ошибок GlitchTip | DSN, фактическое исключение, фильтр и поддержку envelope |
| Стек не преобразован | Release/debug ID, успешную загрузку карты именно этого файла |
| Алерт виден, сообщения нет | Muted delivery, matching notification policy и contact point |
| Всё исчезло одновременно | VPS и его сеть; мониторинг находится на том же хосте |
При диагностике не печатайте environment контейнеров целиком: там есть пароли. Сверяйте имя настройки, статус контейнера и разрешённые поля ответа.