fix(observability): агент не падает из-за переменной чужой роли + DSN экспортеров собираются (#3078) #3106
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3106
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/3078-exporter-dsn-and-profiles"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Продолжение после #3105. Стек серверной части поднялся (Prometheus / Loki / Grafana здоровы,
metrics.gendsgn.ruотвечает 401), а агенты не поднялись ни на одном хосте — джобаagent-appsупала целиком.Дефект 1: обязательная переменная чужой роли
INFRA_EXPORTER_DSNнужен экспортеру сprofiles: ["infra"]— сервису, который на продуктовом хосте не поднимается вовсе. Но Compose интерполирует весь файл до фильтрации по профилям, поэтому${VAR:?}роняет команду из-за переменной чужой роли.Цена: вместе с экспортером не поднялись
alloy,node-exporterиcadvisor, которым никакой DSN не нужен. Симметрично упал бы и инфраструктурный агент — на двух продуктовых переменных.Дефект 2: DSN не собирались вовсе
GENDESIGN_EXPORTER_DSNтоже отсутствовал.setup-metrics-exporter-dsn.shчитает только runtime-файл окружения, аDATABASE_URLиTRADEIN_DATABASE_URLживут в основном. Значит подстановка всегда была пустой,add_keyпечатал «нечем заполнить, пропускаю» и выходил с кодом 0 — а compose затем падал на обязательной переменной.Мягкий пропуск встречался с жёстким требованием: скрипт считал ситуацию нормальной, compose — фатальной.
Что стало
docker-compose.metrics-agent.yml${..._EXPORTER_DSN:?}×3${..._EXPORTER_DSN:-}— интерполяция не может упастьdeploy-metrics.ymlCOMPOSE_PROFILES=apps/=infraжёстко::warningи агент поднимается без экспортераsetup-metrics-exporter-dsn.sh:-— это не ослабление. ПустойDATA_SOURCE_NAMEподнял бы экспортер, который молча не отдаёт метрик, — ровно тот тихий отказ, ради которого весь стек и заводится. Поэтому пустой DSN теперь означает «профиль не включаем», а не «поднимаем пустым». Громкость не убрана, а перенесена туда, где роль известна — тот же приём, что уже применён к Alertmanager в джобеserver.Честно про остаток
INFRA_EXPORTER_DSNне собирает никто: скрипт знает только проGENDESIGN_/TRADEIN_и запускается на продуктовом хосте. Пока это так, инфраструктурный агент будет предупреждать, что метрик Postgres инфры нет — вместо того чтобы падать целиком. Отмечено комментарием прямо в воркфлоу, чтобы не выглядело недосмотром.Также в силе:
TRADEIN_EXPORTER_DSNвыводится изTRADEIN_DATABASE_URL, которой на Poincare нет — это #3094. До его закрытия продуктовый профиль экспортеров не включится, и предупреждение об этом теперь будет видно в логе деплоя явно.Тесты
backend/tests/ops/test_3078_exporter_profiles.py, 3 структурных — проверяют оба конца инварианта::?не вернулись в compose;Фальсификация: на исходных файлах краснеют все три.
Проверено помимо тестов:
bash -nскрипта, оба YAML парсятся, в коммите нет CR.Вне этого PR — но сделано и проверено на проде
CADDY_SITESна Beget вернул вinfra: мой же предыдущий пересоздание Caddy подняло контейнер с дефолтом*из compose, и Beget начал грузить чужойapps.caddy. Сейчасgit/errors/obsidian/metricsотвечают, конфиг валиден.На Poincare остаётся
CADDY_SITES=*— он грузит чужойinfra.caddyи выпрашивает сертификат наmetrics.gendsgn.ru, который обслуживает Beget. Это уже стоило лимита Let's Encrypt:HTTP 429 too many failed authorizations (5) for metrics.gendsgn.ru in the last 1h. Сертификат Beget в итоге получил, но пока Poincare продолжает попытки, лимит будет выжигаться снова — а он же нужен для продления живых сертов. Правится строкой в файле окружения Poincare (CADDY_SITES=apps) плюс пересоздание Caddy; файл закрыт хуком, поэтому за владельцем.Refs #3078, #3099, #3105
Джоба agent-apps упала целиком: error while interpolating services.postgres-exporter-infra.environment. DATA_SOURCE_NAME: required variable INFRA_EXPORTER_DSN is missing a value INFRA_EXPORTER_DSN нужен экспортеру с profiles: ["infra"], который на продуктовом хосте не поднимается вовсе. Но compose интерполирует ВЕСЬ файл до фильтрации по профилям, поэтому `${VAR:?}` роняет команду из-за чужой переменной. Вместе с агентом не поднялись alloy, node-exporter и cadvisor, которым никакой DSN не нужен. Симметрично упал бы и инфраструктурный агент - на двух продуктовых переменных. Второй дефект в той же цепочке: GENDESIGN_EXPORTER_DSN тоже отсутствовал. setup-metrics-exporter-dsn.sh читает только runtime-файл окружения бэкенда, а DATABASE_URL и TRADEIN_DATABASE_URL живут в основном. Значит подстановка всегда была пустой, add_key печатал "нечем заполнить" и выходил с кодом 0 - мягкий пропуск встречался с жёстким требованием compose. Стало: - compose: `:-` вместо `:?` у трёх DSN. Интерполяция больше не может упасть. - deploy-metrics.yml: профиль экспортеров включается, только если нужные ЭТОЙ роли DSN заполнены; иначе ::warning и агент поднимается без экспортера. Громкость не убрана, а перенесена туда, где роль известна. Тот же приём, что уже применён к Alertmanager в джобе server. - setup-metrics-exporter-dsn.sh: читает оба файла окружения (базовый, затем runtime - он перекрывает). Пишет по-прежнему только в runtime, лишних копий пароля не заводит. Почему `:-` не ослабление: пустой DATA_SOURCE_NAME поднял бы экспортер, который молча не отдаёт метрик, - ровно тот тихий отказ, ради которого весь стек и заводится. Поэтому пустой DSN теперь означает "профиль не включаем", а не "поднимаем пустым". Известное следствие, отмеченное в коде: INFRA_EXPORTER_DSN не собирает никто - скрипт знает только про GENDESIGN_/TRADEIN_ и работает на продуктовом хосте. Пока это так, инфраструктурный агент будет честно предупреждать, что метрик Postgres инфры нет, вместо того чтобы падать целиком. Тесты (3) структурные, проверяют оба конца инварианта: обязательности не вернулись в compose; каждая DSN-переменная проверяется в деплое; профили не захардкожены. Фальсификация: на исходных файлах краснеют все три.