fix(observability): контейнерные метрики терялись целиком + два хвоста стека #3108

Merged
lekss361 merged 1 commit from fix/metrics-cadvisor-drop into main 2026-08-26 10:18:11 +00:00
Owner

Три независимых дефекта, найденных на живом проде после того, как стек метрик поднялся (#3106). Симптом, с которого начали, — «в метриках нодата».

1. cAdvisor-метрики не доезжали ВООБЩЕ (главное)

Замер на живом Prometheus: ноль имён container_* при 2034 именах метрик всего.

При этом всё звено выглядело здоровым:

Проверка Результат
cAdvisor отдаёт container_* 880 рядов
scrape-таргет в alloy health = up, last_scrape 10 мс назад
prometheus.scrape.cadvisor / prometheus.relabel.cadvisor_trim оба healthy
remote_write рабочий — node/postgres идут через него же и доезжают
keep-регекс по __name__ совпадает с реальными именами у источника

Методом исключения остаётся второе правило в cadvisor_trim:

rule { source_labels = ["name"], regex = "", action = "drop" }

Замысел был выкинуть безымянные cgroup-ряды (id="/"). Но regex в Alloy документированно дефолтится в (.*), а пустая строка неотличима от незаданного значения — такой drop рискует выкидывать вообще всё, что и наблюдается.

Заменено на однозначное keep regex=".+" — тот же замысел, но результат не зависит от того, как трактуется пустой regex.

Честно: сам механизм (пустой regex → (.*)) я не доказал — в доках Alloy этот случай прямо не описан. Правка выбрана так, чтобы быть верной при любой из трактовок.

2. healthcheck alloy не мог пройти никогда

test: wget -q --spider …, а в образе grafana/alloy нет ни wget, ни curl, ни nc — проверено command -v на живом контейнере. Итог: контейнер вечно unhealthy при полностью исправном alloy (все 10 компонентов healthy). Ложная тревога, которая маскирует настоящие сбои.

Заменено на сырой HTTP через bash /dev/tcp — без внешних утилит.

3. Prometheus раз в минуту ругался на отсутствующий alertmanager

lookup alertmanager: no such host + up{job="alertmanager"}=0.

Alertmanager намеренно за профилем alerts до решения #3078 по каналу доставки — профиль не трогаю, это не дефект. Дефект в том, что prometheus.yml ссылался на сервис безусловно.

Оба места (alerting.alertmanagers и job_name: alertmanager) переведены на file_sd_configs с файлом целей, по умолчанию пустым ([]): целей нет — ошибок разрешения имени тоже нет. Prometheus перечитывает file_sd на лету, поэтому включение профиля сведётся к наполнению файла — без рестарта и без правки этого конфига.

Файл целей смонтирован в сервис prometheus явным volume — с учётом того, что ровно забытый монт сегодня уже положил Caddy (#3103).

Проверка — на живом хосте, не на глаз

alloy fmt alloy-infra.alloy   (grafana/alloy:v1.6.1, одноразовый контейнер)  → exit 0
alloy fmt alloy-apps.alloy                                                   → exit 0
promtool check config          (prom/prometheus:v3.1.0)                      → valid, 16 rules found

Механизм нового healthcheck выполнен внутри работающего gendesign-alloy:

PROBE: первая строка ответа = [HTTP/1.0 200 OK]
PROBE: RESULT=HEALTHY

Наличие bash / head / grep / printf в образе подтверждено command -v — чтобы не повторить ровно ту ошибку, которую чиним пунктом 2.

После мёрджа

Проверить, что count(container_last_seen) перестал быть пустым и gendesign-alloy ушёл из unhealthy.

Три независимых дефекта, найденных на живом проде после того, как стек метрик поднялся (#3106). Симптом, с которого начали, — «в метриках нодата». ## 1. cAdvisor-метрики не доезжали ВООБЩЕ (главное) Замер на живом Prometheus: **ноль имён `container_*`** при 2034 именах метрик всего. При этом всё звено выглядело здоровым: | Проверка | Результат | |---|---| | cAdvisor отдаёт `container_*` | 880 рядов | | scrape-таргет в alloy | `health = up`, `last_scrape` 10 мс назад | | `prometheus.scrape.cadvisor` / `prometheus.relabel.cadvisor_trim` | оба `healthy` | | remote_write | рабочий — `node`/`postgres` идут через него же и доезжают | | keep-регекс по `__name__` | совпадает с реальными именами у источника | Методом исключения остаётся второе правило в `cadvisor_trim`: ```alloy rule { source_labels = ["name"], regex = "", action = "drop" } ``` Замысел был выкинуть безымянные cgroup-ряды (`id="/"`). Но `regex` в Alloy документированно дефолтится в `(.*)`, а пустая строка неотличима от незаданного значения — такой `drop` рискует выкидывать вообще всё, что и наблюдается. Заменено на однозначное `keep regex=".+"` — тот же замысел, но результат не зависит от того, как трактуется пустой regex. Честно: сам механизм (пустой regex → `(.*)`) я **не доказал** — в доках Alloy этот случай прямо не описан. Правка выбрана так, чтобы быть верной при любой из трактовок. ## 2. healthcheck alloy не мог пройти никогда `test: wget -q --spider …`, а в образе `grafana/alloy` **нет** ни `wget`, ни `curl`, ни `nc` — проверено `command -v` на живом контейнере. Итог: контейнер вечно `unhealthy` при полностью исправном alloy (все 10 компонентов `healthy`). Ложная тревога, которая маскирует настоящие сбои. Заменено на сырой HTTP через `bash /dev/tcp` — без внешних утилит. ## 3. Prometheus раз в минуту ругался на отсутствующий alertmanager `lookup alertmanager: no such host` + `up{job="alertmanager"}=0`. Alertmanager намеренно за профилем `alerts` до решения #3078 по каналу доставки — **профиль не трогаю, это не дефект**. Дефект в том, что `prometheus.yml` ссылался на сервис безусловно. Оба места (`alerting.alertmanagers` и `job_name: alertmanager`) переведены на `file_sd_configs` с файлом целей, по умолчанию пустым (`[]`): целей нет — ошибок разрешения имени тоже нет. Prometheus перечитывает file_sd на лету, поэтому включение профиля сведётся к наполнению файла — без рестарта и без правки этого конфига. Файл целей смонтирован в сервис `prometheus` явным volume — с учётом того, что ровно забытый монт сегодня уже положил Caddy (#3103). ## Проверка — на живом хосте, не на глаз ``` alloy fmt alloy-infra.alloy (grafana/alloy:v1.6.1, одноразовый контейнер) → exit 0 alloy fmt alloy-apps.alloy → exit 0 promtool check config (prom/prometheus:v3.1.0) → valid, 16 rules found ``` Механизм нового healthcheck выполнен **внутри работающего** `gendesign-alloy`: ``` PROBE: первая строка ответа = [HTTP/1.0 200 OK] PROBE: RESULT=HEALTHY ``` Наличие `bash` / `head` / `grep` / `printf` в образе подтверждено `command -v` — чтобы не повторить ровно ту ошибку, которую чиним пунктом 2. ## После мёрджа Проверить, что `count(container_last_seen)` перестал быть пустым и `gendesign-alloy` ушёл из `unhealthy`.
lekss361 added 1 commit 2026-08-26 10:15:03 +00:00
fix(observability): контейнерные метрики терялись целиком + два хвоста стека
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
c6e15954ba
Три независимых дефекта, найденных на живом проде после подъёма стека метрик.

1. cAdvisor-метрики не доезжали ВООБЩЕ. В Prometheus ноль имён container_*
   при 2034 именах всего, хотя cAdvisor отдаёт 880 рядов, scrape-таргет в
   alloy health=up с последним скрейпом 10 мс назад, а remote_write рабочий
   (node/postgres идут через него же и доезжают). Методом исключения — потери
   в prometheus.relabel.cadvisor_trim, во втором правиле:

       rule { source_labels = ["name"], regex = "", action = "drop" }

   Замысел был выкинуть безымянные cgroup-ряды (id="/"). Но regex в Alloy
   документированно дефолтится в (.*), и пустая строка неотличима от
   незаданного значения — такой drop рискует выкидывать вообще всё, что и
   наблюдалось. Заменено на однозначное keep regex=".+" — тот же замысел,
   без зависимости от того, как трактуется пустой regex.

2. healthcheck alloy не мог пройти никогда: дёргал wget, которого в образе
   grafana/alloy нет (как и curl, и nc). Контейнер вечно unhealthy при
   полностью исправном alloy — ложная тревога, маскирующая настоящие сбои.
   Заменено на сырой HTTP через bash /dev/tcp, без внешних утилит.

3. Prometheus раз в минуту писал "lookup alertmanager: no such host" и держал
   up{job="alertmanager"}=0. Alertmanager намеренно за профилем alerts до
   решения #3078 — дефект не в профиле, а в безусловной ссылке на сервис.
   Оба места (alerting.alertmanagers и job_name: alertmanager) переведены на
   file_sd_configs с файлом целей, по умолчанию пустым: целей нет — ошибок
   тоже нет. Prometheus перечитывает file_sd на лету, поэтому включение
   профиля сведётся к наполнению файла, без рестарта и правки конфига.
   Файл целей смонтирован в сервис prometheus явным volume.

Проверено на живом хосте, не на глаз:
- alloy fmt обоих .alloy в одноразовом контейнере grafana/alloy:v1.6.1 - exit 0
- promtool check config в prom/prometheus:v3.1.0 - valid, 16 rules found
- механизм нового healthcheck выполнен внутри работающего gendesign-alloy:
  первая строка ответа "HTTP/1.0 200 OK", grep матчится, RESULT=HEALTHY
- наличие bash/head/grep/printf в образе alloy подтверждено command -v
lekss361 merged commit fe8b022ce5 into main 2026-08-26 10:18:11 +00:00
lekss361 deleted branch fix/metrics-cadvisor-drop 2026-08-26 10:18:11 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3108
No description provided.