Стадия жизненного цикла модуля: Общедоступная версия
У модуля есть требования для установки
Обзор
Мониторинг сайтов — система blackbox-мониторинга, встроенная в DOP. Позволяет проверять доступность веб-сайтов, TCP-сервисов и DNS-записей из внешних точек наблюдения (зон).
Агент устанавливается на сервер за пределами кластера, получает конфигурацию из DOP, выполняет проверки и отправляет метрики обратно в DOP. Результаты доступны на дашбордах и через систему алертов.
Поддерживаемые типы проверок: HTTP, TCP/TLS, DNS, Ping (ICMP).
Быстрый старт
- Убедитесь, что функция мониторинга сайтов включена (Admin → Settings →
web_monitoring_enabled) - Создайте зону: Admin → Zones → New Zone (укажите имя, например
world) - Создайте агента: Admin → Agents → New Agent (укажите имя и зону)
- Скопируйте токен агента из карточки
- Установите агент на внешний сервер (см. раздел Установка агента)
- Перейдите в проект: Project → Веб-мониторинг → Добавить сайт
- Укажите домен, выберите зоны, добавьте пробу через preset «HTTPS Check», сохраните
Через 1–2 минуты на дашбордах появятся данные о доступности.
Основные понятия
Зоны
Зона — географическая или сетевая точка наблюдения. Каждый агент принадлежит одной зоне. Сайт можно проверять из нескольких зон одновременно для независимой оценки доступности.
Создание зон: Admin → Zones → New Zone.
Сайты
Сайт — объект мониторинга: доменное имя или IP-адрес. Принадлежит проекту. Каждый сайт содержит одну или несколько проб и общие настройки (период, ping, зоны, лейблы).
Пробы и чеки
Проба — один запрос определённого типа (HTTP, TCP или DNS) к сайту. Каждая проба содержит один или несколько чеков — конкретных условий проверки (например, HTTP status = 200 или время ответа < 5s).
Агент выполняет все чеки при каждом срабатывании пробы и отправляет метрику gogomonia_test (1 = pass, 0 = fail) для каждого чека.
Многошаговый HTTP-сценарий (multihttp) — проба из нескольких HTTP-запросов, выполняемых по порядку: например, вход → профиль → выход. Шаги делят cookie-сессию, могут извлекать переменные из ответов (JSON path, regex, заголовок, cookie, CSS-селектор) и использовать их в следующих шагах как ${name}; у каждого шага свои чеки. См. Многошаговые HTTP-сценарии.
Лейблы
Лейблы — произвольные Prometheus-совместимые key=value пары, добавляемые к метрикам. Используются для группировки, фильтрации и управления алертингом.
Лейблы задаются на трёх уровнях:
- Сайт (
site_labels) — добавляются ко всем метрикам сайта - Сайт (
check_labels) — добавляются ко всем проверкам сайта - Чек (
check_labels) — per-check лейблы, переопределяют site-level
Управление алертингом: лейбл alert=yes (по умолчанию) включает алерты, alert=no — отключает для конкретного чека.
Формат ключей: латинские буквы, цифры, подчёркивания; начинается с буквы или подчёркивания (/^[a-zA-Z_][a-zA-Z0-9_]*$/).
Типы проверок
Каждая проба (HTTP/TCP/DNS) содержит один или несколько чеков. Агент выполняет все чеки при каждом срабатывании пробы и отправляет метрику gogomonia_test (1 = pass, 0 = fail) для каждого чека.
Все pattern-поля (bodyMatch, contentType, answerMatch, location, headers.match, cookies.match) используют формат /regex/ (Go RE2-совместимый). Добавление ! после закрывающего слэша (/pattern/!) инвертирует результат (NOT match). Значение без обрамляющих слэшей сравнивается на полное совпадение как обычная строка.
HTTP-чеки
status — Проверка HTTP status code
Проверяет, что код ответа входит в список допустимых. Используется для контроля корректности ответа сервера.
- Поле: список кодов через запятую
- Формат: целые числа 100–599 или regex в слэшах
- Примеры:
200·200, 301, 302·/2[0-9]{2}/(любой 2xx)
responseTime — Максимальное время ответа
Проверяет, что запрос выполнился быстрее порога. Чек срабатывает в реальном времени: если ответ не пришёл за max, тест помечается как fail ещё до завершения запроса.
- Поле:
max— максимальная длительность - Формат: число + единица:
ms,s,m,h - Примеры:
5s·1500ms·1m
bodyMatch — Regex-проверка тела ответа
Проверяет, что тело HTTP-ответа содержит (или не содержит) указанный паттерн. Полезно для проверки, что страница содержит ожидаемый контент и не показывает ошибку.
- Поле: regex
- Формат:
/regex/или/regex/!(NOT match) - Примеры:
/OK/·/Welcome to/·/error|maintenance/!(не должно содержать)
bodySize — Размер тела ответа
Проверяет, что размер тела ответа попадает в допустимый диапазон. Позволяет обнаружить пустые ответы или аномально большие страницы.
- Поля:
min— минимальный размер (опционально),max— максимальный размер (опционально). Требуется хотя бы одно изminилиmax. - Формат: число + единица:
b,Kb,Mb,Gb - Примеры: min
100b· max10Mb· min1Kbmax5Mb
contentType — Проверка Content-Type заголовка
Проверяет, что заголовок Content-Type в ответе соответствует ожидаемому. Используется для контроля, что сервер возвращает правильный тип контента, а не страницу ошибки.
- Поле: regex
- Формат:
/regex/или/regex/! - Примеры:
/text\/html/·/application\/json/·/image\/.*/
location — Проверка заголовка Location (редиректы)
Проверяет, что заголовок Location в ответе (при 3xx редиректах) соответствует паттерну. Полезно для проверки, что редирект ведёт на правильный URL.
- Поле: regex или точный URL
- Формат:
/regex/,/regex/!или URL, сравниваемый на полное совпадение - Примеры:
/https:\/\/example\.com\//·/\/login$/·https://example.com/
При сравнении URL порт, подразумеваемый схемой, игнорируется: https://example.com:443/
и https://example.com/ считаются одним и тем же адресом, в обе стороны. Любой другой
порт сравнивается как написан. На формат /regex/ это не распространяется — он
матчится с заголовком в том виде, в каком тот пришёл.
sslBasicConstraintsValid — Проверка TLS-сертификата
Комплексная проверка TLS-сертификата: корректность BasicConstraints (CA-сертификаты должны иметь BasicConstraintsValid=true), срок действия leaf-сертификата (NotBefore / NotAfter), соответствие имени хоста (exact и wildcard *.example.com).
- Поля: нет (включается как boolean)
certValidDays — Срок действия сертификата
Проверяет, что TLS-сертификат не истечёт в ближайшие N дней. Используется для заблаговременного обнаружения истекающих сертификатов.
- Поле:
min— минимум дней до истечения - Формат: положительное целое число
- Примеры:
30(предупредить за 30 дней) ·7·90
sslValidDays — Срок действия сертификата (альтернатива)
Аналогичен certValidDays. Нельзя использовать одновременно с certValidDays.
- Поле:
min— минимум дней до истечения - Формат: положительное целое число
headers — Проверка HTTP-заголовков ответа
Проверяет, что заголовки HTTP-ответа содержат указанные значения. Каждая пара: имя заголовка + regex для значения. Все пары должны совпасть (AND-логика).
- Поля: пары
name/match - name: имя заголовка (case-insensitive), например
Content-Type,X-Request-Id - match: regex
/pattern/или/pattern/! - Примеры: name
X-Request-Idmatch/^[a-f0-9-]+$/· nameCache-Controlmatch/no-cache/!
cookies — Проверка cookies в ответе
Проверяет, что cookies HTTP-ответа содержат указанные значения. Каждая пара: имя cookie + regex для значения. Все пары должны совпасть (AND-логика).
- Поля: пары
name/match - name: имя cookie, например
session_id,csrf_token - match: regex
/pattern/или/pattern/! - Примеры: name
session_idmatch/^[a-f0-9]{32}$/· namelangmatch/^(en|ru)$/
jsonPath — Проверка JSON-тела
Проверяет условия над значениями JSON-тела ответа. Каждое условие: JSONPath-выражение, условие и (кроме exists) ожидаемое значение. Все условия должны выполниться (AND-логика). Доступна для HTTP-проб и для шагов многошаговых сценариев.
- Поля: тройки
expression/condition/value - expression: JSONPath, например
$.status,$.items[0].id,$.user.roles[*] - condition:
exists,equals,notEquals,contains,notContains,startsWith,endsWith,matches(regex),gt,gte,lt,lte(числовые) - value: ожидаемое значение; может ссылаться на переменную сценария как
${name} - Примеры:
$.statusequalsok·$.itemsexists ·$.balancegt0·$.user.idequals${user_id}
Многошаговые HTTP-сценарии
Проба multihttp выполняет несколько HTTP-запросов по порядку как одну пробу. Добавляется через меню «Добавить пробу» (тип «Многошаговый HTTP-сценарий») в обоих режимах формы и нужна для потоков, которые имеют смысл только как последовательность: войти и открыть защищённую страницу, создать объект и прочитать его, пройти оформление заказа. В простом режиме доступны интервал, таймаут и общие cookies сценария, а у каждого шага — имя, метод, схема, URL, тело (для POST/PUT/PATCH), переменные и простые чеки (status, responseTime, сертификат); расширенный режим добавляет порт и таймаут шага, следование редиректам, заголовки запроса, Basic Auth, отключение HTTP/2, логирование значений переменных и остальные HTTP-чеки, включая jsonPath, — то же разделение, что и в форме HTTP-пробы.
Настройки сценария:
- интервал — от 30s до 5m (сценарий запускается не чаще раза в интервал; диапазон шире, чем 60s у одиночной пробы, потому что сценарий делает несколько последовательных запросов)
- таймаут — дедлайн всего сценария (по умолчанию интервал минус 5s)
- общие cookies — сохранять cookies между шагами (включено по умолчанию)
- логировать значения переменных — писать извлечённые значения в логи агента (выключено по умолчанию: логируются только имена)
- отключить HTTP/2 для HTTPS — выполнять все шаги по HTTP/1.1; настройка общая для сценария, потому что шаги делят один HTTP-клиент
У каждого шага есть имя, URL (абсолютный — со своими схемой, хостом и портом — или путь, достраиваемый по хосту сайта), схема и порт для URL-пути, метод, тело, заголовки, Basic Auth, таймаут, политика редиректов, переменные и чеки:
- URL отправляется как написан: указывайте его уже закодированным, вместе с query-параметрами (
/search?q=hello%20world). Переменные подставляются как${name}(дословно) или${name|urlencode}(percent-encoding по RFC 3986 — кодируется всё, кромеA-Za-z0-9-._~, пробел →%20, — годится и для значения параметра, и для сегмента пути):/me?sid=${sid|urlencode}. Любой другой фильтр отвергается при сохранении сайта. - Схема и порт достраивают URL-путь (
/api/login→https://<хост сайта>:8443/api/login) — ровно как у HTTP-пробы; новый шаг в форме начинается с HTTPS. Шаг, сохранённый без схемы (через API или старой формой), достраивается схемой изrequestсайта, а без неё — http; форма показывает это эффективное значение. Абсолютный URL несёт свои схему и порт: оба поля показывают их и заблокированы, аscheme/portрядом с абсолютнымurlчерез API — ошибка валидации. - Шаблоны
[[ rndStr ]]и[[ .Site ]]работают в URL, значениях заголовков и Basic Auth шага так же, как в запросе HTTP-пробы — подставляются один раз при загрузке конфига агентом; тело отправляется как написано. - Переменные извлекаются из ответа шага:
jsonPath($.access_token),regex(первая группа захвата или всё совпадение),header(значение заголовка),cookie(значение cookie) илиcssSelector(текст элемента или его атрибут). До 10 на шаг. Переменная, которую не удалось извлечь, проваливает шаг. ${name}— ссылки на переменные предыдущих шагов допустимы в URL, значениях заголовков, теле и в значениях чеков; значение чека может ссылаться и на переменную своего шага (переменные извлекаются до выполнения чеков). Ввод${в одном из этих полей редактора предлагает переменные, доступные этому шагу.- Basic Auth задаётся на шаг (к шагам без своего продолжают применяться настройки запроса сайта); явный заголовок
Authorization— напримерBearer ${token}— имеет приоритет, как и в HTTP-пробе. - Чеки — описанные выше HTTP-чеки плюс
jsonPath; до 10 на шаг. Новый шаг начинается сstatusиresponseTime, как HTTP-проба; каждый тип чека добавляется в шаг один раз (уже добавленный тип пропадает из меню «Проверка»). Уровень алертинга настраивается на сценарии, а не на отдельном чеке шага.
Сценарий останавливается на первом проваленном шаге: ошибка транспорта, неудачная экстракция или провал любого чека (включая responseTime и проверки сертификата). Оставшиеся шаги помечаются пропущенными, все их чеки проваливаются.
Алертинг работает по сценарию, а не по чекам шагов: один алерт GogomoniaScenarioFailed на пробу с серьёзностью из селектора «Уведомления» пробы и списком упавших шагов и проверок. Поэтому у чеков шагов нет настроек уведомлений (checkLabels для них не принимаются); алерт по отдельной проверке GogomoniaCheckFailed относится только к одиночным пробам.
Метрики несут лейбл step: серии по шагам (gogomonia_test{step="login"}, gogomonia_http_response_time_ms_sum{step="login"}, …) плюс серии сценария (gogomonia_probe_request_succeeded{step=""}, gogomonia_multihttp_runs_total, gogomonia_multihttp_duration_ms_sum, gogomonia_multihttp_steps_total{result}). Страница сайта показывает каждый шаг с его чеками и длительность сценария; в дашборде «Сайт веб-мониторинга» раскрывающийся блок «Многошаговые сценарии» даёт на каждый сценарий сайта строку из трёх графиков — статус сценария (одна линия: ok / failed / request failed / ambiguous), длительность прогона и время ответа шагов; статусы отдельных шагов и их чеков — в блоках «Checks (overall)» и «Checks (per server)». Ссылка из алерта GogomoniaScenarioFailed открывает этот дашборд с одним упавшим сценарием.
Для многошаговых сценариев нужны агенты версии 0.3.0 и новее; более старые агенты такие пробы пропускают.
TCP/TLS-чеки
connected — Проверка TCP-соединения
Проверяет, что TCP-соединение (и TLS-хэндшейк, если TLS включён) установлено успешно. Базовый чек доступности TCP-сервиса.
- Поля: нет (включается как boolean)
responseTime — Время установки соединения
Аналогичен HTTP responseTime, но измеряет время установки TCP-соединения (и TLS-хэндшейка при наличии).
- Поле:
max— максимальная длительность - Примеры:
5s·2s
sslBasicConstraintsValid — Проверка TLS-сертификата
Аналогичен HTTP sslBasicConstraintsValid. Проверяет сертификат TCP/TLS соединения.
- Поля: нет (включается как boolean)
certValidDays — Срок действия TLS-сертификата
Аналогичен HTTP certValidDays. Проверяет сертификат TCP/TLS соединения.
- Поле:
min— дней до истечения - Примеры:
30·7
sslValidDays — Срок действия TLS-сертификата (альтернатива)
Аналогичен certValidDays. Нельзя использовать одновременно с certValidDays.
DNS-чеки
gotAnswer — Получен непустой DNS-ответ
Проверяет, что DNS-запрос вернул хотя бы одну запись. Базовый чек — домен резолвится.
- Поля: нет (включается как boolean)
answerMatch — Regex-проверка DNS-ответа
Проверяет, что хотя бы одна запись в DNS-ответе соответствует паттерну. Ответ содержит полную строку записи (например example.com. 300 IN A 1.2.3.4).
- Поле: regex
- Формат:
/regex/или/regex/! - Примеры:
/1\.2\.3\.4/·/IN A/·/IN MX.*mail\./
responseTime — Время DNS-запроса
Аналогичен HTTP responseTime, но измеряет время DNS-запроса.
- Поле:
max— максимальная длительность - Примеры:
2s·500ms
Ping (ICMP)
Ping включается флагом ping: true на уровне сайта. Работает полностью независимо от проб — не требует ни проб, ни чеков. Встроенный тест ping.maxRtt проходит, если RTT < 500ms (порог захардкожен).
Настройка мониторинга
Создание зон
Зона — географическая или сетевая точка наблюдения. Каждый агент принадлежит одной зоне.
Создание: Admin → Zones → New Zone. Укажите имя зоны.
Создание сайтов
Путь: Project → Веб-мониторинг → Добавить сайт.
Два режима формы
Форма создания/редактирования сайта работает в двух режимах.
Простой режим (по умолчанию для новых сайтов):
- Показаны основные поля: host, period, ping, зоны
- Добавление проб через presets (готовые шаблоны)
- Доступные чеки ограничены (см. таблицу ниже)
- TCP: упрощённый переключатель TLS
Расширенный режим (переключатель «Расширенный режим» внизу формы):
- Все дополнительные поля: hosts, probe_all_resolved_ips, site_labels, check_labels, request_defaults
- Полный набор типов чеков
- Группировка чеков
- Per-probe лейблы и period
- TCP: полная настройка TLS (insecureSkipVerify, serverName)
Переключение из расширенного в простой режим блокируется, если в форме есть данные, доступные только в расширенном режиме. Для существующих сайтов режим выбирается автоматически на основе сохранённых настроек.
Доступные чеки по режимам
| Тип пробы | Простой режим | Только расширенный |
|---|---|---|
| HTTP | status, responseTime, certificate (sslBasicConstraintsValid + certValidDays) | bodyMatch, bodySize, contentType, location, headers, cookies, jsonPath |
| TCP | connected, responseTime, certificate | — |
| DNS | gotAnswer, responseTime | answerMatch |
| Многошаговый HTTP | status, responseTime, сертификат (по шагам) | bodyMatch, bodySize, contentType, location, headers, cookies, jsonPath; порт и таймаут шага, редиректы, логирование переменных |
Группировка чеков
В расширенном режиме доступен переключатель «Группировать условия в проверки».
Без группировки (по умолчанию): каждый чек — отдельная проверка с собственным результатом (pass/fail) и собственным алертом.
Каждый тип проверки добавляется один раз: уже добавленный тип (отдельной проверкой или внутри группы) пропадает из меню «Проверка» пробы или шага, а когда заняты все типы, кнопка блокируется. В HTTP-пробе вторая проверка того же типа — например два bodyMatch с разными паттернами и уровнями — добавляется отдельной группой при включённой группировке.
С группировкой: несколько условий (status, bodyMatch, responseTime и т.д.) объединяются в одну логическую проверку с общим именем и общим алертом. Группе назначается уровень severity.
Пример: группа «https-health» может включать status=200 + bodyMatch="/OK/" + responseTime max=5s. При нарушении любого условия срабатывает один общий алерт.
Группировка включается автоматически, если сайт уже содержит чеки с несколькими условиями в одном config.
Параметры сайта
| Параметр | Описание | Режим |
|---|---|---|
| name | Отображаемое имя, уникальное в проекте | оба |
| host | Домен или IP для мониторинга | оба |
| period | Интервал проверок каждого агента. Формат: \d+(s|m), max 60s. Пример: 20s, 1m |
оба |
| ping | Включить ICMP ping (true/false) | оба |
| zones | Из каких зон проверять. Если не указан — проверяется из всех зон | оба |
| hosts | Массив конкретных IP вместо DNS-резолва | расш. |
| probe_all_resolved_ips | Проверять все разрешённые IP, а не только первый | расш. |
| site_labels | Prometheus-лейблы ко всем метрикам сайта | расш. |
| check_labels | Лейблы ко всем проверкам сайта | расш. |
| request_defaults | HTTP defaults: scheme, timeout, headers | расш. |
| probes | Массив проб с чеками | оба |
Распределение агентов внутри интервала
Каждый агент зоны выполняет пробу раз в интервал, но агенты одной зоны не ходят на сайт одновременно: платформа нумерует зарегистрированных агентов зоны (в порядке создания, независимо от того, онлайн они сейчас или нет) и агент k из N начинает пробу на k × интервал / N секунд позже первого. При интервале 60 с и трёх агентах сайт получает запрос каждые 20 с, при двух — каждые 30 с; один агент работает как раньше. Форма сайта показывает под интервалом расчёт по выбранным зонам. Разнос действует на HTTP-, TCP- и многошаговые пробы; DNS-пробы и ping от него не зависят.
Слоты считаются по системным часам, поэтому часы агентов одной зоны должны быть синхронизированы (NTP). Агент сравнивает своё время с временем платформы при каждом опросе конфигурации: расхождение попадает в метрику gogomonia_agent_clock_skew_seconds, при расхождении больше 5 с агент пишет предупреждение в лог. Разнос требует агентов версии 0.6.0 и новее; более старые агенты продолжают выполнять пробы в прежние моменты.
Presets
Presets — готовые шаблоны проб, доступные при создании сайта. Позволяют добавить типовую конфигурацию одним нажатием.
| Preset | Тип пробы | Создаваемые чеки |
|---|---|---|
| HTTPS Check | HTTP GET (https) | status 200, sslBasicConstraintsValid, certValidDays min=30 |
| TCP/TLS | TCP с TLS | connected, certValidDays min=30 |
| DNS | DNS A-запрос | gotAnswer |
| HTTP Redirect | HTTP GET | status 301/302, location |
Запуск вручную («Протестировать»)
У каждой сохранённой пробы на странице сайта есть кнопка Протестировать. Она выполняет пробу немедленно на выбранных агентах — любом доступном, всех агентах одной зоны, всех агентах всех зон или одном конкретном агенте (в списке — все живые агенты зон сайта в виде «Агент <зона> / <имя>») — и показывает результат в модальном окне. Проба выполняется по каждому IP-адресу хоста (все A-записи, как у traceroute) независимо от опции сайта «Проверять все IP»; у сайта со своим списком адресов — по одному IP на запись.
Во вкладке агента каждый проверенный IP — строка: статус, IP и в скобках хост, из которого он получен, время прогона; она разворачивает подробности: отправленный запрос (GET https://…; чувствительные заголовки вроде Authorization и API-ключей замаскированы, значения cookie показываются первыми и последними четырьмя символами — sid=abcd…wxyz, а значения, взятые из хранилища секретов, показываются ссылкой ${secret:<путь>#<ключ>}, из которой пришли), ответ (200 HTTP/2.0, заголовки, тело до 50 КБ; если шаг шёл по редиректам — конечный URL и таблица хопов: статус, откуда, куда, какие cookie выставил хоп; у TCP-пробы — установленное соединение и его время, у DNS-пробы строка начинается с запрошенного хоста и указывает резолвер), извлечённые переменные и ожидаемое/фактическое значение каждого чека (у bodyMatch «получено» описывает страницу: заголовок, размер, тип и первый видимый текст).
Для многошаговых сценариев каждый шаг — отдельная карточка с заголовком «Шаг N из M» и именем шага; она показывает время ответа рядом со статусом, а после — состояние сценария: все накопленные переменные и cookie-jar по всем хостам в виде host: name=value — то, с чем стартует следующий шаг.
Кнопка Логи на странице сайта открывает записи агентов по его пробам. Проваленный запрос или шаг сценария оставляет три вида записей уровня error, каждая читается сама по себе: запись запроса — её сообщение называет первый проваленный тест и причину (check 'logged_in/http.bodyMatch' failed: expected /Deckhouse UI/, got page "Deckhouse" (3522 bytes, text/html) at https://dex.example.com/auth after 4 redirects (+1 more failed test)), а поля несут запрос и ответ с замаскированными секретами (Cookie: _oauth2_proxy=<redacted>, Authorization: Bearer <redacted>), probe.url (как запрошено), при редиректах probe.final_url и probe.redirects (по хопу на строку: 302 https://a → https://b; set-cookie: session=<redacted>), probe.redirect_count, probe.response.summary, checks.failed и tests.failed.
Если ответа не было вовсе (таймаут, отказ соединения), сообщение называет URL, на котором запрос прервался — редирект-хоп помечен (after redirect) и повторён в probe.final_url, — а списков тестов нет: проверять было нечего.
Далее по записи на каждый проваленный тест (test '…' failed: expected …, got … с test.expect, test.actual — у bodyMatch сводка страницы с фрагментом текста — и тем же контекстом ответа); у сценариев — сводка прогона multihttp scenario failed со статусами всех шагов, probe.failed_step и probe.failure.
Та же кнопка есть у каждой пробы в форме создания и редактирования сайта: проба выполняется в том виде, в каком она сейчас заполнена, без сохранения формы — можно править конфигурацию, запускать, смотреть результат и снова править. Форма при этом должна быть валидной (ошибки показываются в окне запуска).
Такие запуски — только по запросу: они не создают метрик и алертов, результат удаляется при закрытии окна. Участвуют агенты, выходившие на связь за последние 90 секунд; HTTP-пробу (одиночную и сценарий) выполняют агенты версии 0.7.0 и новее — более старые отдают трейс со значениями секретов и cookie в открытом виде, поэтому не предлагаются.
Traceroute
Кнопка Traceroute в шапке сайта строит сетевой маршрут от агентов до сайта: выберите, где выполнить (любой доступный агент, все агенты одной зоны, все агенты всех зон или один конкретный агент, умеющий трассировать), протокол и режим — и каждый агент покажет путь до каждого IPv4-адреса хостов сайта (все A-записи, резолв выполняется на самом агенте без кэша).
- Протокол:
ICMP echo(какtraceroute -I) илиTCP— соединения на порт с ограниченным TTL, какtcptraceroute: пробы идут тем же путём и через те же фаерволы, что и трафик проверок. Порт подставляется из проб сайта (явный порт пробы, иначе 80/443 по схеме) и его можно изменить. - Режим:
Стандарт— 30 хопов, 3 пробы на хоп, 1 с на хоп;Тщательный— 30 хопов, 5 проб на хоп, 3 с на хоп. Пробы одного хопа идут параллельно, хопы — последовательно до максимума, без ранней остановки на молчащих хопах. - Результат: по вкладке на агента (зона / имя агента, с точкой по худшему из его результатов и спиннером, пока он не ответил), а во вкладке — по строке на цель: трассируемый IP с хостом, из которого он получен, в скобках, длительность и достигнута ли цель, — и под ней компактная таблица хопов: номер, IP ответившего узла, его обратное DNS-имя и RTT каждой пробы (потерянная проба — красная
*; если хоп потерял часть проб, рядом показанопотеряно/отправлено). Стрелка перед целью сворачивает её таблицу. Цель зелёная, если достигнута без потерь; жёлтая (с потерями), если достигнута, но пробы терялись — на самой цели или частично на промежуточном хопе (хопы, не отвечающие вовсе, — это маршрутизаторы, не отправляющие ICMP-ошибки, потерями они не считаются); красная, если не достигнута за лимит хопов. Иконка буфера обмена у цели помещает в буфер вывод в формате классическогоtraceroute.
Как читать результат
Та же легенда открывается по ссылке Как читать результат под вкладками агентов.
- Строка — один хоп, маршрутизатор на пути к цели;
#— его порядковый номер. На каждый хоп агент отправляет несколько проб (3 или 5 в зависимости от режима); в колонке RTT — время ответа каждой из них, Хост — обратное DNS-имя адреса (пусто, если записи нет). *вместо времени — проба не получила ответа за таймаут режима (1 с или 3 с).- Серая строка без IP, все пробы
*— хоп не ответил ни на одну пробу. Как правило, это маршрутизатор, который вообще не отправляет ICMP Time Exceeded (политика оператора, MPLS-ядро, облачный шлюз); это не проблема, пока отвечают следующие хопы, и потерей это не считается. - Подсвеченная строка с
1/3— хоп ответил не на все пробы:потеряно/отправлено. На промежуточном хопе это обычно ограничение частоты ICMP-ответов на самом роутере, а не потери трафика — реальному трафику ответ роутера не нужен. Потери на самой цели или на всех хопах начиная с какого-то — проблема пути. - Зелёная жирная последняя строка — цель ответила сама, маршрут построен до конца.
- Статусы цели:
ок— достигнута, все пробы ответили;с потерями— достигнута, но часть проб потеряна на цели или на промежуточном хопе;ошибка—цель не достигнута за N хопов: после последнего ответившего маршрутизатора никто не ответил, то есть цель не отвечает на ICMP echo или её закрывает файрвол (попробуйте TCP-режим на порту сервиса);ошибка запуска— трассировка не выполнилась (нет прав на raw-сокет, IPv6-адрес, ошибка агента), причина — в строке цели. - У сайта с несколькими A-записями — по строке на адрес; адреса могут размещаться в разных местах, поэтому их маршруты и статусы различаются.
Трассируется только IPv4: IPv6-хост показывается с пометкой и пропускается. Как и для «Протестировать», нужны агенты, выходившие на связь за последние 90 секунд, версии 0.4.0 и новее; агент должен работать от root или с CAP_NET_RAW (systemd-unit установщика это обеспечивает), иначе каждая цель будет отмечена ошибкой. Результат удаляется при закрытии окна.
Маршрут, где не ответил ни один хоп (* * * на всех строках), — это то, что отдаёт сеть, а не сбой агента: многие облачные сети и NAT-шлюзы не пропускают ICMP Time Exceeded от маршрутизаторов, и системный traceroute с хоста агента показывает те же звёздочки. В такой сети используйте TCP-режим — сама цель отвечает на connect, поэтому её достижимость и RTT видны даже при полностью молчащих промежуточных хопах. Для сравнения запустите на хосте агента системный traceroute -T -p 443 <host>: он идёт тем же путём, что и агент.
Что учесть с точки зрения безопасности
Разовый запуск и traceroute уходят с агентов мониторинга, а не из браузера, и куда именно — ничем не ограничено:
- агенты зоны общие для всех проектов платформы, поэтому запуск достаёт всё, что достают они: внутренние сети площадки, где установлены агенты, loopback хоста агента, сервис метаданных облака, в котором он работает;
- оператор видит ответ на этот запрос, до 50 КБ тела, а TCP-traceroute показывает, открыт ли порт;
- редиректы отслеживаются на любой хост, поэтому цель запуска не обязательно та, для которой его начали.
Запуск требует права править сайты проекта (роли user и admin, AI-ассистент от имени такого пользователя) — то же право, которое и так позволяет отправить запрос конфигурацией куда угодно. Выдавайте эти роли соответственно и размещайте агентов в сетевом сегменте, доступность которого соответствует тому, что позволено видеть проектам платформы. Роль viewer может только смотреть результат чужого запуска. Платформа намеренно не ограничивает адреса запуска: это принятая часть модели доверия к этим ролям, а границей служит сетевой сегмент, в котором стоят агенты.
Запуск из формы сайта выполняет пробу в том виде, как она заполнена, без сохранения — и не оставляет записи в журнале аудита: аудит ведётся только по сохранённым конфигурациям. Такой запуск может ссылаться на секреты проекта так же, как сохранённый сайт (их читает то же право на редактирование), поэтому факт использования секрета в запуске, который так и не был сохранён, потом не проследить; AI-ассистенту ссылки на секреты в составленном им самим запуске запрещены — только в сохранённых сайтах.
Секреты
Пароли, токены и API-ключи, которые нужны проверкам (basic auth, заголовок Authorization и другие заголовки, тела запросов, шаги сценариев, ожидаемые значения проверок), не обязательно хранить в платформе: в любом строковом поле конфигурации сайта можно указать ссылку на секрет, которую backend разрешает из хранилища секретов, совместимого с HashiCorp Vault, — Deckhouse Stronghold или HashiCorp Vault — только в момент передачи конфигурации агентам. В базе данных платформы, публичном API, журнале аудита и выгрузках webmon-cli остаётся ссылка, а не значение.
${secret:<путь>#<ключ>}путь— путь к секрету KV v2 внутри единственного KV-хранилища, настроенного для платформы (ui.secretsStore.kv.mount, по умолчаниюsecret);ключ— ключ внутри этого секрета. Сегменты пути могут содержать буквы, цифры,_ . -.- Относительный путь (
${secret:app/prod#token}) замкнут на проект: он разрешается в<mount>/<pathPrefix>/<имя space>/<имя проекта>/app/prod(pathPrefixпо умолчаниюdop/web-monitoring). Относительные ссылки доступны любому проекту без дополнительных прав. Переименование space или проекта меняет этот префикс — перенесите секреты соответственно. - Абсолютный путь начинается с
/(${secret:/team-a/prod/db#password}) и разрешается в<mount>/team-a/prod/db. Абсолютные ссылки разрешены только под префиксами, которые администратор платформы перечислил в настройках проекта (Настройки → Веб-мониторинг → Разрешённые абсолютные пути секретов, по одному полю на префикс, например/team-a/;/разрешает всё хранилище; раздел показывается только при настроенном хранилище секретов). Совпадение проверяется по границе сегмента:/team-a/разрешает/team-a/prod/db, но не/team-abc/x. Пустой список (по умолчанию) запрещает абсолютные пути. - Имя
secretзарезервировано под этот синтаксис и не может использоваться как переменная сценария. - Ссылки допустимы в полях запроса и в ожидаемых значениях проверок. В метках метрик (
siteLabels,checkLabels), именах и экстракторах переменных они запрещены: подставленное там значение стало бы меткой всех серий пробы и было бы видно каждому, кто может читать метрики проекта.
Кто может прочитать секрет. Ссылка разрешается в запрос, который отправляют агенты, поэтому любой, кто может править сайты проекта (роли user и admin, API-токен с доступом к веб-мониторингу, AI-ассистент от имени такого пользователя), может направить проверку на подконтрольный себе хост и получить значение там. Право править сайты равносильно праву читать все секреты, на которые проект может ссылаться: выдавайте роль соответственно и держите список разрешённых абсолютных путей как можно уже. Роль viewer не может ни править сайты, ни запускать разовые проверки, ни получать каталог секретов. Чего платформа не показывает никогда — это само значение: в базе, публичном API, журнале аудита, выгрузках webmon-cli, логах агентов и трейсах разовых запусков на его месте стоит ссылка.
В форме сайта ввод ${ в поле, принимающем ссылки (путь и URL запроса, заголовки, тело запроса, basic auth, ожидаемые значения проверок), открывает список того, что туда можно подставить: внутри шага сценария — переменные, извлечённые предыдущими шагами, как ${имя}; при настроенном хранилище секретов — секреты под префиксом проекта и под разрешёнными абсолютными префиксами, как ${secret:путь#ключ} (только пути и имена ключей, никогда значения). Продолжайте печатать, чтобы сузить список; выбор — стрелками и Enter или кликом. Если хранилище не разрешает платформе листинг префикса, список об этом сообщает — путь вводится вручную.
При сохранении сайта каждая новая ссылка читается из хранилища: несуществующий путь или ключ, путь, который платформе запрещено читать, абсолютный путь вне списка проекта или недоступное хранилище — ошибки валидации, конфигурация не сохраняется. Редактирование сайта без изменения его ссылок к хранилищу не обращается.
В рантайме backend читает значения, когда формирует конфигурацию для агентов, и передаёт их рядом с ней; агент подставляет их в сам запрос, поэтому значение, похожее на шаблон или ссылку на переменную, уходит как данные:
- проба выполняется только тогда, когда у каждой её ссылки есть значение: секрет никогда не заменяется заглушкой, поэтому проба без значения не попадает в конфигурацию, которую выполняет агент, — остальные пробы сайта и его ping продолжают работать. На странице сайта указаны ссылка и причина, а для проекта срабатывает алерт
GogomoniaSiteRejected; - если хранилище недоступно, проект остаётся на своей конфигурации, а агенты продолжают проверять его со значениями последнего успешного формирования; на остальную зону это не влияет. Проба, значений для которой у агента нет вовсе (он перезапустился при недоступном хранилище или ссылка новая), не выполняется до ответа хранилища; это покрывает платформенный алерт
WebMonitoringSecretsStoreUnavailable— проект такую проблему не починит. Агенты старше 0.8.2 не подставляют ссылки сами: им эндпоинт состояния отвечает 503, и они остаются на текущей конфигурации до ответа хранилища; - если отдельная ссылка перестала разрешаться (секрет удалён или перенесён, изменилась политика, сузили список проекта), использующие её пробы не выполняются, а на странице сайта указана ссылка; остальной сайт продолжает мониториться. Агенту старше 0.8.2 вместо этого не отдаётся сайт целиком — он не умеет пропускать отдельную пробу;
- ротация секретов подхватывается автоматически: раз в 5 минут backend сравнивает версии KV используемых секретов с последними увиденными и при изменении повышает версию конфигурации, чтобы агенты перечитали её. Разовые запуски (Протестировать) разрешают ссылки в момент, когда агент забирает задание; ссылка, которую в этот момент разрешить нельзя, завершает запуск ошибкой с её указанием.
Те же ссылки можно использовать в conf.yaml, который синхронизируется через webmon-cli (см. Управление конфигурацией из Git): API проверяет их при синхронизации так же, как форма, а выгрузки возвращают ссылки, а не значения.
Существующие учётные данные в открытом виде автоматически не мигрируются: положите значение в хранилище и замените его в конфигурации сайта ссылкой.
Настройка платформы
Порядок настройки с Deckhouse Stronghold в том же кластере; отличия для HashiCorp Vault — в конце раздела. Полное описание параметров ui.secretsStore — в справочнике конфигурации модуля. В примерах используются KV-хранилище dop-secrets, префикс web-monitoring и политика dop-web-monitoring.
1. Доступ администратора к Stronghold. Команды выполняются CLI d8 stronghold (совместим с vault, читает VAULT_ADDR и VAULT_TOKEN). Администратор из management.administrators входит через метод oidc_deckhouse (d8 stronghold login -method=oidc -path=oidc_deckhouse). В режиме management.mode: Automatic root-токен хранится в Secret stronghold-keys пространства имён d8-stronghold (ключ rootToken); он подходит для первичной настройки из консоли — не выводите его на экран:
export VAULT_ADDR=https://stronghold.<publicDomainTemplate> # адрес из Ingress модуля stronghold
export VAULT_TOKEN="$(kubectl -n d8-stronghold get secret stronghold-keys -o jsonpath='{.data.rootToken}' | base64 -d)"
d8 stronghold status # Initialized true, Sealed false
d8 stronghold auth list # kubernetes_local/ настроен модулем2. Адрес хранилища. Backend проверяет TLS-сертификат по системному набору CA и по имени хоста. Если API на порту 8200 отдаёт сертификат Ingress (выписан на публичное имя), укажите публичный адрес https://stronghold.<publicDomainTemplate> без caCert. Внутренний адрес https://stronghold.d8-stronghold.svc:8200 подходит, только если сертификат выписан на это имя; его CA указывается в ui.secretsStore.caCert. Проверка сертификата из кластера:
kubectl -n d8-observability-platform run tls-check --rm -i --restart=Never --image=alpine/openssl -- \
s_client -connect stronghold.d8-stronghold.svc:8200 -servername stronghold.d8-stronghold.svc </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -ext subjectAltName3. KV v2 и раскладка путей. Платформа работает с одним KV v2 (ui.secretsStore.kv.mount). Секреты проектов лежат под <mount>/<pathPrefix>/<space>/<проект>/... и доступны проектам по относительным ссылкам. Для секретов, общих для нескольких проектов, заведите отдельный префикс (например shared/): проекты ссылаются на него абсолютными путями, разрешёнными в настройках проекта.
d8 stronghold secrets list # существующие хранилища
d8 stronghold secrets enable -path=dop-secrets -version=2 kv # если KV v2 ещё нет4. Политика платформы. data — чтение значений при формировании конфигурации агентов; metadata — отслеживание ротации (current_version) и список секретов в форме сайта (list; без него пути вводятся вручную). Политика должна покрывать pathPrefix и каждый абсолютный префикс, который планируется разрешать проектам:
# dop-web-monitoring.hcl
path "dop-secrets/data/web-monitoring/*" { capabilities = ["read"] }
path "dop-secrets/metadata/web-monitoring/*" { capabilities = ["read", "list"] }
path "dop-secrets/data/shared/*" { capabilities = ["read"] }
path "dop-secrets/metadata/shared/*" { capabilities = ["read", "list"] }d8 stronghold policy write dop-web-monitoring dop-web-monitoring.hcl5. Аутентификация платформы. Поддерживаются два способа.
Вариант А — метод Kubernetes (auth.method: Kubernetes, по умолчанию). Backend входит в хранилище projected-токеном ServiceAccount backend-secrets пространства имён d8-observability-platform (создаётся модулем, RBAC не требуется) и получает токен хранилища с политикой роли; токен продлевается автоматически. Роль в методе kubernetes_local:
d8 stronghold write auth/kubernetes_local/role/dop-web-monitoring \
bound_service_account_names=backend-secrets \
bound_service_account_namespaces=d8-observability-platform \
policies=dop-web-monitoring ttl=1hПроверка роли и политики до включения интеграции — токеном того же ServiceAccount:
JWT=$(kubectl -n d8-observability-platform create token backend-secrets --duration=10m)
d8 stronghold write -field=token auth/kubernetes_local/login role=dop-web-monitoring jwt="$JWT" > /tmp/dop.token
VAULT_TOKEN=$(cat /tmp/dop.token) d8 stronghold kv list -mount=dop-secrets web-monitoring/ # список или пустой ответ, но не 403
rm /tmp/dop.tokenВариант Б — статический токен (auth.method: Token). Backend обращается к хранилищу токеном из Kubernetes Secret (имя — auth.token.secretName, по умолчанию secrets-store-token; ключ token). Вход в хранилище не выполняется, ServiceAccount backend-secrets не используется. Выпустите orphan-токен с политикой платформы через роль метода token и положите его в Secret:
d8 stronghold write auth/token/roles/dop-web-monitoring \
allowed_policies=dop-web-monitoring orphan=true renewable=true token_type=service
d8 stronghold token create -role=dop-web-monitoring -policy=dop-web-monitoring \
-display-name=dop-web-monitoring -ttl=768h -field=token \
| kubectl -n d8-observability-platform create secret generic secrets-store-token --save-config --from-file=token=/dev/stdinСрок жизни токена ограничен max_lease_ttl метода token (по умолчанию 768 часов). Платформа токен не продлевает: до истечения срока выпустите новый токен, обновите Secret и перезапустите backend и backend-scheduler — значение Secret передаётся в переменную окружения при старте пода. После перезапуска отзовите прежний токен (d8 stronghold token revoke -accessor <accessor>; accessor и display_name токенов показывает d8 stronghold token lookup -accessor по списку d8 stronghold list auth/token/accessors).
d8 stronghold token create -role=dop-web-monitoring -policy=dop-web-monitoring \
-display-name=dop-web-monitoring -ttl=768h -field=token \
| kubectl -n d8-observability-platform create secret generic secrets-store-token --from-file=token=/dev/stdin \
--dry-run=client -o yaml | kubectl apply -f -
kubectl -n d8-observability-platform rollout restart deployment/backend deployment/backend-schedulerИстёкший или отозванный токен хранилище не отличает от запрета политикой и отвечает 403: ни одна ссылка на секрет не разрешается, пробы с секретами не выполняются, на странице сайта показывается причина access denied, а сайты с новыми ссылками не сохраняются до замены токена.
6. Включение в модуле. mount и pathPrefix должны совпадать с политикой; секция auth — по выбранному варианту:
# kubectl edit moduleconfig observability-platform
spec:
settings:
ui:
secretsStore:
enabled: true
address: https://stronghold.<publicDomainTemplate> # см. шаг 2
auth:
method: Kubernetes # вариант А
kubernetes:
path: kubernetes_local
role: dop-web-monitoring
# method: Token # вариант Б
# token:
# secretName: secrets-store-token
kv:
mount: dop-secrets
pathPrefix: web-monitoringDeckhouse перекатывает backend и backend-scheduler: поды получают переменные SECRETS_STORE_* из ConfigMap backend-envs, в варианте А — ServiceAccount backend-secrets и projected-токен в /var/run/secrets/secrets-store/token, в варианте Б — переменную SECRETS_STORE_TOKEN из Secret. Интеграция готова, когда ввод ${ в поле пароля формы сайта предлагает ссылки ${secret:…} (а для проекта, у которого секретов ещё нет, — заметку с его префиксом dop-secrets/web-monitoring/<space>/<проект>).
7. Секрет и ссылка на него. Секрет кладётся под префикс проекта, в конфигурации сайта указывается ссылка; при сохранении backend читает каждую новую ссылку из хранилища:
d8 stronghold kv put -mount=dop-secrets web-monitoring/<space>/<проект>/httpbin user=monitor password='...'
d8 stronghold kv put -mount=dop-secrets shared/api token='...' # для абсолютной ссылки ${secret:/shared/api#token}request:
basicAuth:
username: ${secret:httpbin#user} # относительно префикса проекта
password: ${secret:httpbin#password}
headers:
- name: Authorization
value: Bearer ${secret:/shared/api#token} # абсолютный путь: нужен префикс /shared/ в настройках проектаАбсолютные пути разрешает администратор платформы в настройках проекта (Настройки → Веб-мониторинг → Разрешённые абсолютные пути секретов, например /shared/; администраторы проекта видят список только для чтения). Ссылку на несуществующий ключ, запрещённый политикой путь или абсолютный путь вне списка форма и API отклоняют с указанием ссылки.
8. Ротация и отказы. Новая версия секрета (kv put) подхватывается автоматически: backend-scheduler раз в 5 минут сравнивает current_version используемых секретов и при изменении повышает версию конфигурации, агенты перечитывают её на следующем опросе; независимо от этого агент раз в 10 минут запрашивает полную конфигурацию и применяет её, если содержимое изменилось.
Если секрет удалён или доступ к нему отозван, использующие его пробы перестают выполняться, а на странице сайта указана ссылка — секрет никогда не заменяется заглушкой. Если хранилище недоступно, агенты продолжают проверки с уже имеющимися значениями, пробы без значений не выполняются, а сайты с новыми ссылками не сохраняются до восстановления хранилища (агентам старше 0.8.2 на весь запрос состояния отвечают 503, и они остаются на прежней конфигурации). Значения секретов в пути URL не защищаются: агент записывает строку запроса в журнал проверки и маскирует только заголовки Authorization, Cookie и подобные — ссылки следует использовать в basicAuth, заголовках и телах запросов, а не в path.
Типичные ошибки: 403 при чтении — политика не покрывает путь (data/) или его метаданные (metadata/), либо истёк или отозван статический токен; 404 — нет такого пути или ключа (в политике KV v2 путь содержит сегмент data/, в командах kv — нет); login failed with HTTP 403 в логах backend — роль метода Kubernetes не привязана к backend-secrets/d8-observability-platform, у роли задан audience, отличный от ui.secretsStore.auth.kubernetes.audience, либо хранилищу не хватает прав на TokenReview API (для Vault в кластере — ClusterRole system:auth-delegator у его ServiceAccount); certificate verify failed — адрес не совпадает с именами в сертификате (шаг 2).
HashiCorp Vault. Отличия: KV-хранилище должно быть версии 2 и называться так, как указано в политике и в ui.secretsStore.kv.mount; метод Kubernetes включается и настраивается вручную, путь метода — kubernetes (ui.secretsStore.auth.kubernetes.path: kubernetes); в ui.secretsStore.address указывается адрес Vault (внутри кластера — http(s)://<service>.<namespace>.svc:8200). Статический токен выпускается так же, командами vault:
vault secrets enable -version=2 -path=dop-secrets kv
vault auth enable kubernetes
# Vault внутри кластера: токен пода backend проверяется через TokenReview API от имени
# ServiceAccount самого Vault — ему нужна ClusterRole system:auth-delegator:
# kubectl create clusterrolebinding vault-auth-delegator \
# --clusterrole=system:auth-delegator --serviceaccount=<namespace Vault>:<ServiceAccount Vault>
vault write auth/kubernetes/config kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443"
# Vault вне кластера: укажите ему адрес кластера и либо выдайте reviewer-токен
# (token_reviewer_jwt), либо включите ui.secretsStore.auth.kubernetes.grantTokenReview: true,
# чтобы ServiceAccount платформы мог сам вызывать TokenReview API.
vault policy write dop-web-monitoring dop-web-monitoring.hcl
vault write auth/kubernetes/role/dop-web-monitoring \
bound_service_account_names=backend-secrets \
bound_service_account_namespaces=d8-observability-platform \
policies=dop-web-monitoring ttl=1hЕсли у роли указан явный audience, то же значение задаётся в ui.secretsStore.auth.kubernetes.audience. ui.secretsStore.namespace передаёт заголовок X-Vault-Namespace для пространств имён Stronghold или Vault Enterprise; в остальных случаях он остаётся пустым. Собственный CA хранилища указывается в ui.secretsStore.caCert.
Что агенты сообщают о конфигурации
Платформа проверяет сайт при сохранении, но последнее слово за агентом: выражения переменных сценария и проверок он компилирует своими движками (Go RE2, ojg, cascadia), эффективные таймауты считает сам и значения секретов держит у себя. Сайт или проба, которые он отверг, не дают метрик вовсе, поэтому ни один алерт проверок по ним не сработает — вердикт каждого агента показывается на странице сайта и выносится бейджем в список сайтов:
- сайт отвергнут целиком — конфигурация не прошла валидацию агента (выражение, которое он не компилирует, таймаут выше посчитанного им предела, ключ, неизвестный этой версии агента). Этот агент не мониторит сайт вообще;
- проба не выполняется — у её ссылки
${secret:...}нет значения: ссылка не разрешается или хранилище секретов не удалось прочитать. Остальные пробы сайта и его ping продолжают работать; - проба выполняется со значениями секретов прежней конфигурации — хранилище секретов недоступно, и агент продолжает проверки с тем, что у него уже есть.
Агент применяет сохранённую конфигурацию и отчитывается в течение минуты, поэтому вердикт появляется вскоре после сохранения; обновите страницу сайта, чтобы его увидеть. Отвергнутая конфигурация дополнительно поднимает проектный алерт GogomoniaSiteRejected, а недоступное хранилище секретов — платформенный WebMonitoringSecretsStoreUnavailable: владелец проекта хранилище не починит. Агенты старше 0.8.2 вердикты не присылают: для них отвергнутый сайт виден только в их журнале и в gogomonia_agent_config_problem_sites.
Требования к проектам
Для работы мониторинга сайтов у проекта должен быть API-токен с правом «Метрики: запись» (write_metrics). Этот токен создаётся автоматически при создании проекта.
Если токен удалён — в разделе Веб-мониторинг отображается предупреждение, а агент не получает конфигурацию для этого проекта.
Установка агента
Требования
- Linux (amd64)
- Сетевой доступ до DOP API (
api.<domain>)
Ручная установка
- Создать агента в Admin UI: Admin → Agents → New Agent (указать имя и зону)
- Скопировать токен из карточки агента
- На целевом сервере:
# Скачать бинарь
curl -o /usr/local/bin/gogomonia-agent \
"https://update.<domain>/gogomonia-agent/storage/latest/linux/amd64/gogomonia-agent"
chmod +x /usr/local/bin/gogomonia-agent
# Конфиг
mkdir -p /usr/local/gogomonia-agent/etc
cat > /usr/local/gogomonia-agent/etc/config.yaml <<EOF
dop_api_url: "https://api.<domain>"
EOF
# Токен
echo -n "<TOKEN>" > /usr/local/gogomonia-agent/agent.token
# Запуск
/usr/local/bin/gogomonia-agentКонфигурация агента
Файл config.yaml:
dop_api_url: "https://api.dop.example.com"
proxy:
url: "" # HTTP proxy (опционально)
no_verify_tls: false
poll_interval: 60s # опрос изменений конфигурации
force_poll_interval: 10m # полный запрос стейта: подхватывает изменения без смены версии, не короче poll_intervalПеременные окружения
| Переменная | Описание | По умолчанию |
|---|---|---|
GOGOMONIA_CONFIG_PATH |
Путь к config.yaml | /usr/local/gogomonia-agent/etc/config.yaml |
GOGOMONIA_TOKEN_PATH |
Путь к файлу с токеном | /usr/local/gogomonia-agent/agent.token |
GOGOMONIA_UUID_PATH |
Путь к файлу UUID | /usr/local/gogomonia-agent/agent.uuid |
GOGOMONIA_PUSH_URL |
Override для remote write URL | (из state API) |
GOGOMONIA_POLL_INTERVAL |
Период опроса изменений конфигурации | 60s |
GOGOMONIA_FORCE_POLL_INTERVAL |
Период полного запроса стейта (не короче GOGOMONIA_POLL_INTERVAL) |
10m |
Управление конфигурацией из Git
Утилита converter позволяет хранить конфигурацию сайтов в git-репозитории в декларативном YAML-формате с поддержкой Go-шаблонов и синхронизировать её с DOP через API. Это GitOps-подход: validate на merge request, sync на merge в master.
Защита от изменений через UI
По умолчанию все сайты в DOP редактируются через UI — это касается и тех, что создаются webmon-cli. Если хочется явно зафиксировать в git, что конкретный сайт управляется только через API (чтобы оператор случайно не поправил его в UI и не получил, как следствие, расхождение между git и DOP), задайте в YAML флаг uiEditable: false. Доступно начиная с webmon-cli v0.5.1:
defaults:
uiEditable: false # все сайты в файле — только через API
targets:
- name: managed-site
host: managed.example.com
# uiEditable наследуется из defaults → false
- name: editable-site
host: editable.example.com
uiEditable: true # точечное исключение: оставить редактирование в UIСемантика:
uiEditable: true— поведение по умолчанию: сайт можно редактировать в UI и через API.uiEditable: false— в UI у сайта появляется бейдж «Только через API», кнопка редактирования становится неактивной; удаление (и из UI, и из API) и обновление через API по-прежнему доступны.- Поле отсутствует в YAML —
webmon-cliничего не передаёт серверу, сервер сохраняет значение, заданное ранее (для новых сайтов —true). - Приоритет:
targets[].uiEditable→defaults.uiEditable→ значение, ранее сохранённое в DOP.
Подробнее о поле в API-контракте — в разделе API → Параметры сайтов.
Скачивание
Бинарь: webmon-cli.
curl -o /usr/local/bin/webmon-cli \
"https://update.<domain>/webmon-cli/storage/latest/linux/amd64/webmon-cli"
chmod +x /usr/local/bin/webmon-cliКоманды
Первый аргумент — команда: sync или validate. Параметры задаются только переменными окружения.
sync — синхронизация конфигов в DOP
Создаёт, обновляет и (при DELETE_ORPHANS=true) удаляет сайты в DOP по содержимому YAML-файлов.
export DOP_API_URL="https://api.<domain>/api/v1/observability"
export CONFIGS_DIR=/path/to/configs
export DOP_WEB_MON_TOKEN_MYPROJECT="<API-token>"
webmon-cli syncvalidate — локальная валидация
Проверяет конфиги без применения: формат полей, допустимые ключи, deprecated поля, дупликаты. Загружает список зон из API для проверки.
export DOP_API_URL="https://api.<domain>/api/v1/observability"
export CONFIGS_DIR=/path/to/configs
webmon-cli validateВажно: DOP_API_URL обязателен и для validate (загрузка зон). Токен для validate не требуется.
Глобальные переменные окружения
| Переменная | Описание | По умолчанию |
|---|---|---|
DOP_API_URL |
URL backend API (обязательно, валидный URL) | — |
CONFIGS_DIR |
Путь к дереву конфигов | . |
LOG_LEVEL |
Уровень логов (zap): debug, info, warn, error |
info |
COMMON_TEMPLATES |
Каталоги с общими .tpl-шаблонами, через запятую |
— |
DRY_RUN |
План без применения (true / 1 / yes) |
false |
DELETE_ORPHANS |
Удалять сайты в DOP, отсутствующие в конфигах | false |
SKIP_DUPLICATES |
Пропускать дубликаты вместо ошибки | false |
Маппинг проектов и токены
Для каждого каталога проекта задаются переменные окружения. Суффикс формируется из имени папки: все символы кроме букв и цифр заменяются на _, результат приводится к верхнему регистру.
Примеры: папка myapp → MYAPP, папка my-client → MY_CLIENT.
| Переменная | Описание | Для sync |
|---|---|---|
DOP_WEB_MON_TOKEN_{FOLDER} |
API-токен с правом «Мониторинг сайтов» | обязательно |
DOP_WEB_MON_SPACE_{FOLDER} |
Override имени рабочего пространства | по умолчанию = имя папки |
DOP_WEB_MON_PROJECT_{FOLDER} |
Override имени проекта | по умолчанию = имя папки |
Структура репозитория
{team-repo}/
.helpers/helpers.tpl # общие Go-шаблоны (Sprig)
{project}/conf.yaml # конфигурация сайтов
.gitlab-ci.yml- Проект = любая папка, содержащая
*.yamlфайлы - Шаблоны
.tplзагружаются изCOMMON_TEMPLATESи.helpers/каталогов по пути вверх от папки проекта - Шаблоны используют синтаксис Go
text/templateс библиотекой Sprig - Конфиги рендерятся как шаблоны перед парсингом YAML
Формат conf.yaml
# Лейблы уровня юнита — добавляются ко всем сайтам
siteLabels: # опционально, map[string]string
env: production
checkLabels: # опционально, map[string]string
alert: "yes"
# Значения по умолчанию для всех сайтов
defaults: # опционально
ping: "true" # "true"/"yes" → включить ping
period: "20s" # формат: \d+(s|m), max 60s
uiEditable: false # опционально, bool: false = в UI сайт API-only
request: # defaults для HTTP-запросов
scheme: https # http / https
timeout: 10s # формат: \d+(ms|s|m), max 300s
headers: # массив {name, value}
- name: User-Agent
value: "monitoring/1.0"
# Список целей мониторинга (обязателен, минимум 1)
targets:
- name: example-main # ОБЯЗАТЕЛЬНО: уникальное имя сайта
host: example.com # ОБЯЗАТЕЛЬНО: домен или IP
hosts: # опционально: фиксированные IP вместо DNS
- 93.184.216.34
probeAllResolvedIPs: "true" # опционально: проверять все IP при DNS resolve
period: 30s # override периода
ping: true # override ping
uiEditable: true # опционально: override defaults.uiEditable
siteLabels: # merge с unit-level
env: staging
checkLabels: # merge с unit-level
alert: "no"
request: # override request defaults
scheme: https
timeout: 5s
probes: # >= 1 проба, если ping=false
- name: https-main # ОБЯЗАТЕЛЬНО: уникальное, без пробелов/кавычек/скобок/пайпов
period: 30s # опционально: override периода
siteLabels: # опционально: merge с site-level
component: api
checkLabels: # опционально: merge с site-level
alert: "yes"
request: # полная HTTP-конфигурация
scheme: https
path: /healthz
method: GET # GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
port: 443 # 1-65535
timeout: 5s # max 300s
headers:
- name: Accept
value: application/json
basicAuth:
username: user
password: pass
data: '{"key":"value"}'
disableHttp2ForHttps: "true" # строка в кавычках: "true" или "false"
checks: # ОБЯЗАТЕЛЬНО: >= 1 чек
- name: status-ok # ОБЯЗАТЕЛЬНО: уникальное, без пробелов/кавычек/скобок/пайпов
status: [200, 301]
- name: response-time
responseTime:
max: 5s
- name: body-check
bodyMatch: "/OK/"
- name: size-check
bodySize:
min: 100b
max: 10Mb
- name: content-type
contentType: "/text\\/html/"
- name: ssl-check
sslBasicConstraintsValid: true
- name: cert-expiry
certValidDays:
min: 30
checkLabels:
alert: "no"Legacy-формат: вместо
targetsможно использоватьsitesс ключамиsite(вместоhost/name) иservers(вместоhosts). Оба формата поддерживаются, ноtargets— рекомендуемый. Совмещениеsite+hostилиservers+hostsв одной записи вызовет ошибку.
TCP-проба (вместо request):
tcp:
port: 443
timeout: 5s
tls:
insecureSkipVerify: false
serverName: example.comDNS-проба (вместо request):
dns:
type: A # A, AAAA, CNAME, MX, NS, TXT, SOA, SRV, PTR, CAA
query: example.com # ОБЯЗАТЕЛЬНО: домен для запроса
timeout: 2sМногошаговый HTTP-сценарий (multihttp: вместо request; у самой пробы checks нет, чеки живут в шагах). Шаги выполняются по порядку с общим cookie jar; ${name} — переменная, извлечённая предыдущим шагом. Логин за Dex (OIDC) и открытие защищённой страницы:
- name: dex-login
period: 60s # 30s..5m; таймаут сценария по умолчанию = period − 5s
multihttp:
timeout: 50s # опционально, дедлайн всех шагов вместе, <= period
cookies: "true" # опционально, общие cookies между шагами (по умолчанию true)
logVariables: "false" # опционально, логировать значения переменных, не только имена (по умолчанию false)
disableHttp2ForHttps: "false" # опционально, HTTP/1.1 для всех шагов (один клиент на сценарий)
steps:
- name: open_console # 1. консоль -> цепочка редиректов -> страница Dex «выберите способ входа»
url: /?from=console # путь → хост сайта; абсолютные http(s):// URL тоже допустимы; отправляется как есть
followRedirects: "true"
variables:
- name: login_link # href коннектора «Email», несёт одноразовый state
type: cssSelector # jsonPath | regex | header | cookie | cssSelector
expression: 'a[href^="/auth/local"]'
attribute: href # только для cssSelector: атрибут вместо текста элемента
checks:
- name: chooser
status: [200]
bodyMatch: "/select a login method/"
- name: open_login_form # 2. форма логина; её action несёт state запроса
url: "https://dex.example.com${login_link}"
followRedirects: "true"
variables:
- name: login_action
type: cssSelector
expression: form.login-form
attribute: action
checks:
- name: form
status: [200]
- name: submit # 3. POST учётных данных -> callback ставит сессионную cookie -> главная
url: "https://dex.example.com${login_action}"
method: POST
headers:
- name: Content-Type
value: application/x-www-form-urlencoded
data: "login=monitor%40example.com&password=secret"
timeout: 20s # опционально, таймаут шага <= таймаута сценария
followRedirects: "true"
checks:
- name: logged_in
status: [200]
bodyMatch: "/Deckhouse UI/"
responseTime:
max: 15s
- name: protected_page # 4. открывается с сессионной cookie, без редиректа на Dex
url: "/?state=${login_link|urlencode}" # переменная закодирована для query
basicAuth: # опционально, учётные данные только этого шага
username: monitor
password: "${secret:app/prod#password}"
checks:
- name: authorized
status: [200]Поля шага: name (обязательно, уникально в пробе), url (обязательно; отправляется как написан — уже закодированным и с query-параметрами внутри, отдельного списка query нет), scheme (http/https) и port (1..65535), достраивающие URL-путь прежде request сайта (схема по умолчанию http; рядом с абсолютным url оба отвергаются), method (по умолчанию GET), headers (список {name, value}), basicAuth ({username, password} шага; явный заголовок Authorization имеет приоритет), data (тело запроса), timeout (если шаг его не задаёт — request.timeout сайта, иначе 10s; форма показывает это эффективное значение подсказкой в поле), followRedirects, variables (до 10 на шаг), checks (до 10 на шаг; те же чеки, что у HTTP-проб, плюс jsonPath; checkLabels на чеках шагов недопустимы — лейблы алертинга сценария задаются на пробе).
${name} допустимо в url, значениях headers, data и в значениях чеков; ${name|urlencode} подставляет значение закодированным (RFC 3986), любой другой фильтр — ошибка валидации. Сценарий останавливается на первом проваленном шаге; остальные шаги считаются проваленными. Нужны агенты 0.3.0 и новее; basicAuth, scheme, port шага, шаблоны [[ ]] в шагах, disableHttp2ForHttps и ${name|urlencode} требуют агентов 0.5.0 и новее (более старые агенты такие сценарии не получают).
Правила валидации:
nameиhost— обязательные поля каждой цели- Если
ping: falseиprobesпусто — ошибка - Тип пробы определяется наличием ключа:
tcp:→ tcp,dns:→ dns,multihttp:→ multihttp, иначе http multihttp: 1..10 шагов с уникальными именами, хотя бы один чек суммарно по шагам, безchecksна уровне пробы;period30s..5m;timeout<=period,timeoutшага <=timeoutсценария;${name}может ссылаться только на переменные предыдущих шагов (в значениях чеков — и своего шага), единственный фильтр —urlencode; выражения переменныхregex,jsonPath,cssSelectorиjsonPathчеков должны компилироваться — иначе агент отверг бы весь сайт;steps[].queryотвергается (unknown key "query": put the parameters into url and encode variable values with ${name|urlencode});typeпеременной — один изjsonPath,regex,header,cookie,cssSelector(attributeтолько сcssSelector)- Зоны определяются из
siteLabels.zone; пустые зоны = все зоны certVerify/sslVerify— deprecated, вызывают предупреждение (используйтеsslBasicConstraintsValid)- Неизвестные ключи на любом уровне — ошибка парсинга (отклоняются YAML-парсером)
requestна уровне сайта/defaults допускает толькоscheme,timeout,headers. Ключи проб (port,method,pathи др.) задаются только в probe-levelrequestcertValidDaysиsslValidDays— нельзя использовать одновременноbodySizeподдерживаетminи/илиmaxresponseTimeподдерживает толькоmax(неmin); форматmax:\d+(ms|s|m)(безh)- Эффективный
period(override пробы → сайт → unit-default) должен быть>=responseTime.maxкаждого чека
CI/CD интеграция
Converter предназначен для использования в GitLab CI: validate на MR, sync на merge в master.
stages:
- validate
- apply
variables:
DOP_CONVERTER_URL: "https://update.${DOP_BASE_DOMAIN}/webmon-cli/storage/${DOP_CONVERTER_VERSION}/linux/amd64/webmon-cli"
.download_converter: &download_converter
image: alpine:${DOP_WEB_MONITORING_ALPINE_VERSION}
before_script:
- apk add --no-cache curl
- curl -sSL -o webmon-cli "${DOP_CONVERTER_URL}"
- chmod +x webmon-cli
validate:
<<: *download_converter
stage: validate
variables:
DOP_API_URL: "${DOP_API_URL}"
CONFIGS_DIR: "."
script:
- ./webmon-cli validate
apply:
<<: *download_converter
stage: apply
variables:
DOP_API_URL: "${DOP_API_URL}"
CONFIGS_DIR: "."
script:
- ./webmon-cli sync
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'Переменные CI/CD:
| Переменная | Описание | Где задать |
|---|---|---|
DOP_WEB_MON_TOKEN_{FOLDER} |
API-токен для каталога проекта | Settings → CI/CD → Variables (masked) |
DOP_API_URL |
URL API бэкенда | Settings → CI/CD → Variables |
DOP_BASE_DOMAIN |
Базовый домен для скачивания converter | Group-level Variables |
DOP_CONVERTER_VERSION |
Версия converter (например 0.4.1 или latest) |
Group-level Variables |
DOP_WEB_MONITORING_ALPINE_VERSION |
Версия образа Alpine для CI-джоб | Group-level Variables |
Важно: подставьте {FOLDER} в соответствии с именем каталога проекта после санитизации. Папка myapp → DOP_WEB_MON_TOKEN_MYAPP.
Метрики
Имена метрик используют технический префикс gogomonia_ — это внутреннее имя компонента, сохранённое для обратной совместимости.
Probe-метрики (per-project tenant)
| Метрика | Тип | Описание |
|---|---|---|
gogomonia_test |
gauge | Результат check/test (1=pass, 0=fail) |
gogomonia_probe_request_succeeded |
gauge | Probe request успешен (1/0) |
gogomonia_http_requests_sent |
counter | HTTP запросы отправлены |
gogomonia_http_responses_received |
counter | HTTP ответы получены |
gogomonia_http_response_time_ms_sum |
counter | Сумма HTTP response time (ms) |
gogomonia_http_body_size_bytes |
counter | Сумма размера HTTP тел |
gogomonia_http_requests_in_flight |
gauge | HTTP запросы в процессе |
gogomonia_tcp_requests_sent |
counter | TCP запросы |
gogomonia_tcp_responses_received |
counter | TCP успешные соединения |
gogomonia_tcp_response_time_ms_sum |
counter | TCP response time |
gogomonia_tcp_requests_in_flight |
gauge | TCP в процессе |
gogomonia_dns_requests_sent |
counter | DNS запросы |
gogomonia_dns_responses_received |
counter | DNS ответы |
gogomonia_dns_response_time_ms_sum |
counter | DNS response time |
gogomonia_dns_requests_in_flight |
gauge | DNS в процессе |
gogomonia_ping_rtt_ms |
gauge | Ping RTT (ms) |
gogomonia_ping_requests_sent |
counter | Ping запросы отправлены |
gogomonia_ping_responses_received |
counter | Ping ответы получены |
gogomonia_site_resolved |
gauge | DNS resolve статус сайта (1=ok, 0=fail) |
gogomonia_site_config_problem |
gauge | Проба, которую агент не выполняет так, как она настроена, или выполняет с устаревшими значениями секретов; лейблы site, probe, kind (см. Что агенты сообщают о конфигурации) |
gogomonia_site_resolve_tries_sum |
counter | Попытки DNS resolve |
gogomonia_site_resolve_success_sum |
counter | Успешные DNS resolve |
gogomonia_server_ips |
gauge | IP-адреса, разрешённые для сайта |
Лейблы: instance, zone, project, site, server, probe, check, test
Agent selfmon-метрики
| Метрика | Тип | Описание |
|---|---|---|
gogomonia_agent_info |
gauge | Информация об агенте (всегда 1) |
gogomonia_agent_up |
gauge | Heartbeat (1 = жив) |
gogomonia_agent_start_time_seconds |
gauge | Unix timestamp старта |
gogomonia_agent_config_version |
gauge | Версия применённого конфига |
gogomonia_agent_config_sites_count |
gauge | Кол-во сайтов в конфиге |
gogomonia_agent_config_probes_count |
gauge | Кол-во проб |
gogomonia_agent_config_checks_count |
gauge | Кол-во чеков |
gogomonia_agent_config_problem_sites |
gauge | Пробы применённого конфига, которые агент не выполняет так, как они настроены, по kind |
gogomonia_agent_config_last_fetch_seconds |
gauge | Время последнего получения конфига |
gogomonia_agent_config_fetch_errors_total |
counter | Ошибки получения конфига |
gogomonia_agent_clock_skew_seconds |
gauge | Часы агента минус часы платформы (по заголовку Date последнего ответа /state), секунды |
gogomonia_agent_checks_ok |
gauge | Кол-во чеков со статусом OK |
gogomonia_agent_checks_failed |
gauge | Кол-во чеков со статусом FAIL |
gogomonia_agent_checks_no_data |
gauge | Кол-во чеков без данных |
gogomonia_agent_remote_write_errors_total |
counter | Ошибки remote write |
gogomonia_agent_remote_write_samples_total |
counter | Отправлено samples |
gogomonia_agent_remote_write_queue_length |
gauge | Размер буфера remote write |
gogomonia_agent_dns_resolve_errors_total |
counter | Ошибки DNS resolve |
gogomonia_agent_http_request_errors_total |
counter | Ошибки HTTP запросов |
gogomonia_agent_tcp_request_errors_total |
counter | Ошибки TCP запросов |
gogomonia_agent_dns_query_errors_total |
counter | Ошибки DNS запросов |
gogomonia_agent_log_push_queue_length |
gauge | Длина очереди отправки логов |
gogomonia_agent_log_push_errors_total |
counter | Ошибки отправки логов |
Лейблы: instance, zone, uuid, hostname, version
Дашборды
При включении мониторинга сайтов в проекте автоматически появляются дашборды:
- Overall Status — сводная таблица всех сайтов проекта: availability, response times, статус чеков
- Zone Status — детализация по зонам: per-zone метрики, сравнение доступности между зонами
- Site by Instance — drill-down по сайту: per-server/per-instance метрики, scatter-plot времени ответа, блок «Многошаговые сценарии» (статус, длительность и время ответа шагов каждого сценария)
Дополнительные системные дашборды (Go Runtime, Logs) доступны для мониторинга здоровья самих агентов.