2026-08-21 08:11:58 +03:00
|
|
|
|
# Диаграммы потоков данных
|
|
|
|
|
|
|
|
|
|
|
|
Три диаграммы, поясняющие устройство системы на уровне потоков данных —
|
|
|
|
|
|
дополнение к [API.md](API.md) (протокол) и [USAGE.md](USAGE.md) (работа
|
|
|
|
|
|
оператора). Диаграммы — в формате Mermaid, рендерятся нативно на
|
|
|
|
|
|
GitHub/GitLab и в большинстве современных Markdown-просмотрщиков.
|
|
|
|
|
|
|
|
|
|
|
|
## Как читать диаграммы
|
|
|
|
|
|
|
|
|
|
|
|
Единое условное обозначение стрелок для всех диаграмм:
|
|
|
|
|
|
|
|
|
|
|
|
| Обозначение | Значение |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| `-->` тонкая сплошная | Управляющий вызов / API-запрос |
|
|
|
|
|
|
| `-.->` пунктирная | Ответ, уведомление, асинхронный результат |
|
|
|
|
|
|
| `==>` жирная сплошная | Реальный сетевой трафик проверки (data-plane) — именно то, что валидируется, а не служебный вызов |
|
|
|
|
|
|
|
|
|
|
|
|
## Содержание
|
|
|
|
|
|
|
|
|
|
|
|
- [1. Control plane сервиса](#1-control-plane-сервиса)
|
|
|
|
|
|
- [2. Поток данных: от валидатора к целевому серверу (egress-проверка)](#2-поток-данных-от-валидатора-к-целевому-серверу-egress-проверка)
|
|
|
|
|
|
- [3. Поток данных телеметрии](#3-поток-данных-телеметрии)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. Control plane сервиса
|
|
|
|
|
|
|
|
|
|
|
|
Кто кем управляет и через какой канал: конфигурация оператора, HTTP API
|
|
|
|
|
|
control-api, фоновый оркестратор, база данных, вызовы к OpenStack и опрос
|
|
|
|
|
|
со стороны validator-agent/prober.
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart TB
|
|
|
|
|
|
subgraph OP["Оператор"]
|
2026-08-23 20:39:22 +03:00
|
|
|
|
CFG["control-api.yaml<br/>(bootstrap пустой БД:<br/>validators, sites, targets,<br/>check_types, ip_addresses)"]
|
2026-08-21 08:11:58 +03:00
|
|
|
|
ENV["control-api.env<br/>(OS_AUTH_URL, OS_TOKEN, ...)"]
|
2026-08-23 20:39:22 +03:00
|
|
|
|
ADMIN["curl /api/v1/admin/*<br/>(status/ips/validators,<br/>ips submit/cancel,<br/>config CRUD)"]
|
2026-08-21 08:11:58 +03:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph CAPI["control-api (управляющая машина, 1 экземпляр)"]
|
2026-08-21 11:04:49 +03:00
|
|
|
|
HTTP["HTTP API<br/>/api/v1/agents/*<br/>/api/v1/probers/*<br/>/api/v1/admin/*<br/>/healthz"]
|
2026-08-21 08:11:58 +03:00
|
|
|
|
ORCH["Оркестратор: Tick раз в<br/>poll_interval_seconds<br/>claim → associate FIP →<br/>ожидание self-check →<br/>checking → aggregate → release<br/>+ lease sweep + heartbeat sweep"]
|
2026-08-23 20:39:22 +03:00
|
|
|
|
DB[("SQLite<br/>validators / ip_queue / sites /<br/>target_groups / check_types /<br/>checks / events")]
|
2026-08-21 08:11:58 +03:00
|
|
|
|
OSCLIENT["OpenStack-клиент<br/>(mode: mock | real)"]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
OS["OpenStack Neutron<br/>Floating IP API"]
|
|
|
|
|
|
|
|
|
|
|
|
VA["validator-agent ×N<br/>(на каждой ВМ-валидаторе)"]
|
|
|
|
|
|
PR["prober ×3<br/>(на каждой внешней площадке)"]
|
|
|
|
|
|
|
2026-08-23 20:39:22 +03:00
|
|
|
|
CFG -->|"читается только один раз,<br/>на пустых таблицах (bootstrap)"| DB
|
2026-08-21 08:11:58 +03:00
|
|
|
|
ENV -->|"переменные окружения процесса"| OSCLIENT
|
|
|
|
|
|
ADMIN --> HTTP
|
2026-08-23 20:39:22 +03:00
|
|
|
|
HTTP -->|"config/queue CRUD:<br/>источник истины после<br/>первого изменения"| DB
|
2026-08-21 08:11:58 +03:00
|
|
|
|
HTTP --> ORCH
|
|
|
|
|
|
ORCH <--> DB
|
|
|
|
|
|
ORCH --> OSCLIENT
|
|
|
|
|
|
OSCLIENT -->|"associate / disassociate<br/>floating ip"| OS
|
|
|
|
|
|
|
|
|
|
|
|
VA <-->|"register, heartbeat,<br/>GET assignment,<br/>POST self-check/events/<br/>results/complete"| HTTP
|
|
|
|
|
|
PR <-->|"register,<br/>GET assignments,<br/>POST results"| HTTP
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Пояснение.** `control-api` — единственный компонент с состоянием и
|
|
|
|
|
|
единственная точка принятия решений (какой IP кому назначить, когда
|
2026-08-23 20:39:22 +03:00
|
|
|
|
считать проверку завершённой). `control-api.yaml` используется только как
|
|
|
|
|
|
одноразовый bootstrap для четырёх секций (`validators`, `sites`,
|
|
|
|
|
|
`targets`, `check_types`) — читается лишь пока соответствующая таблица в
|
|
|
|
|
|
БД пуста; `ip_addresses` — отдельный, всегда аддитивный путь постановки в
|
|
|
|
|
|
очередь при каждом старте. После bootstrap все изменения этих сущностей,
|
|
|
|
|
|
включая состав очереди и принудительные повтор/остановку проверки, идут
|
|
|
|
|
|
через `/api/v1/admin/*` — «на лету», без `systemctl restart control-api`
|
|
|
|
|
|
(см. [API.md](API.md#управление-очередью-и-конфигурацией)). Оркестратор
|
2026-08-21 08:11:58 +03:00
|
|
|
|
работает по таймеру независимо от HTTP-запросов — назначение IP
|
|
|
|
|
|
валидаторам и агрегация результатов не привязаны к конкретному входящему
|
2026-08-23 20:39:22 +03:00
|
|
|
|
запросу, читая актуальную конфигурацию из БД на каждом проходе, а не
|
|
|
|
|
|
единожды при старте. `validator-agent` и `prober` — активная сторона: они
|
|
|
|
|
|
сами инициируют все HTTP-запросы к control-api (pull-модель), сам
|
|
|
|
|
|
control-api к ним не обращается.
|
2026-08-21 08:11:58 +03:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. Поток данных: от валидатора к целевому серверу (egress-проверка)
|
|
|
|
|
|
|
|
|
|
|
|
Как валидатор проверяет, что через назначенный ему публичный адрес
|
|
|
|
|
|
реально работает исходящий доступ в интернет.
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart LR
|
|
|
|
|
|
subgraph VM["ВМ-валидатор (сервисный проект OpenStack)"]
|
|
|
|
|
|
AGENT["validator-agent"]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
FIP(["Floating IP<br/>203.0.113.10<br/>(адрес под проверкой,<br/>привязан оркестратором заранее)"])
|
2026-08-21 11:04:49 +03:00
|
|
|
|
IPECHO["Внешний IP-echo сервис<br/>(api.ipify.org и т.п.,<br/>вне облака)"]
|
|
|
|
|
|
CAPI["control-api"]
|
2026-08-21 08:11:58 +03:00
|
|
|
|
|
|
|
|
|
|
subgraph TARGETS["Целевые серверы (targets из конфига)"]
|
|
|
|
|
|
T1["hub.docker.com"]
|
|
|
|
|
|
T2["github.com"]
|
|
|
|
|
|
T3["packages.ubuntu.com"]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2026-08-21 11:04:49 +03:00
|
|
|
|
AGENT ==>|"1 self-check: исходящий трафик<br/>ВМ идёт через FIP (SNAT облака)"| FIP
|
|
|
|
|
|
FIP ==>|"1 GET"| IPECHO
|
|
|
|
|
|
IPECHO -.->|"2 наблюдаемый исходящий IP"| AGENT
|
|
|
|
|
|
AGENT -->|"3 POST self-check {success}"| CAPI
|
|
|
|
|
|
AGENT ==>|"4 проверки: тоже через FIP"| FIP
|
2026-08-21 08:11:58 +03:00
|
|
|
|
FIP ==>|"4 HTTPS GET"| T1
|
|
|
|
|
|
FIP ==>|"4 HTTPS GET"| T2
|
|
|
|
|
|
FIP ==>|"4 ICMP echo"| T3
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-21 11:04:49 +03:00
|
|
|
|
**Пояснение.** Шаги 1–2 — самопроверка (self-check): агент сам (без
|
|
|
|
|
|
участия control-api) обращается к внешнему IP-echo сервису и сравнивает
|
|
|
|
|
|
адрес, с которого пришёл его собственный запрос, с адресом, который ему
|
|
|
|
|
|
назначен. Ресурс для сравнения обязан быть вне облака: OpenStack
|
|
|
|
|
|
применяет SNAT через Floating IP только к трафику, уходящему через
|
|
|
|
|
|
внешнюю сеть — обращение к чему-либо внутри проекта (включая сам
|
|
|
|
|
|
control-api, если он в той же внутренней сети) показало бы приватный
|
|
|
|
|
|
адрес валидатора независимо от корректности привязки FIP. Итог
|
|
|
|
|
|
самопроверки агент затем сообщает control-api отдельным вызовом (шаг 3) —
|
|
|
|
|
|
это уже управляющий, а не проверяемый трафик. Только после успешного
|
|
|
|
|
|
self-check агент переходит к шагу 4 и выполняет проверки из
|
|
|
|
|
|
`check_config` (HTTPS/ICMP/опционально SSH) против целей из конфига —
|
|
|
|
|
|
тем же путём, через тот же FIP. Каждый результат отправляется обратно в
|
|
|
|
|
|
control-api сразу после выполнения (см. диаграмму телеметрии ниже) — сам
|
|
|
|
|
|
этот data-plane трафик (шаги 1 и 4) в control-api не проходит и им не
|
|
|
|
|
|
наблюдается напрямую, control-api видит только заявленный агентом
|
|
|
|
|
|
результат.
|
2026-08-21 08:11:58 +03:00
|
|
|
|
|
|
|
|
|
|
### Дополнительно: обратное направление (пробер к валидатору)
|
|
|
|
|
|
|
|
|
|
|
|
Тот же Floating IP одновременно проверяется и «снаружи» — с трёх внешних
|
|
|
|
|
|
площадок, независимо от исходящих проверок агента:
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart LR
|
|
|
|
|
|
subgraph SITES["3 внешние площадки"]
|
|
|
|
|
|
P1["prober site-1"]
|
|
|
|
|
|
P2["prober site-2"]
|
|
|
|
|
|
P3["prober site-3"]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
FIP(["тот же Floating IP<br/>203.0.113.10"])
|
|
|
|
|
|
VM["ВМ-валидатор<br/>(слушает 22/80/443/8080)"]
|
|
|
|
|
|
|
|
|
|
|
|
P1 ==>|"TCP connect + ICMP echo"| FIP
|
|
|
|
|
|
P2 ==>|"TCP connect + ICMP echo"| FIP
|
|
|
|
|
|
P3 ==>|"TCP connect + ICMP echo"| FIP
|
|
|
|
|
|
FIP -.-> VM
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Именно сочетание двух направлений (egress от валидатора и inbound от трёх
|
|
|
|
|
|
площадок) и даёт полную картину: адрес может нормально работать «наружу»,
|
|
|
|
|
|
но быть заблокирован для конкретных внешних сетей — это увидит только
|
|
|
|
|
|
inbound-проверка, и наоборот.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. Поток данных телеметрии
|
|
|
|
|
|
|
|
|
|
|
|
Как результаты проверок и события аудита от validator-agent и трёх
|
|
|
|
|
|
проберов попадают в базу данных control-api, агрегируются в итоговый
|
|
|
|
|
|
результат и становятся видны оператору.
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart TB
|
|
|
|
|
|
subgraph SOURCES["Источники телеметрии"]
|
|
|
|
|
|
VA["validator-agent<br/>(egress-проверки + self-check)"]
|
|
|
|
|
|
P1["prober site-1"]
|
|
|
|
|
|
P2["prober site-2"]
|
|
|
|
|
|
P3["prober site-3"]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph API["HTTP API control-api"]
|
|
|
|
|
|
EP1["POST /agents/{id}/events"]
|
|
|
|
|
|
EP2["POST /agents/{id}/self-check"]
|
|
|
|
|
|
EP3["POST /agents/{id}/results"]
|
|
|
|
|
|
EP4["POST /probers/{site_id}/results"]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
subgraph DB["SQLite (control-api)"]
|
|
|
|
|
|
EVENTS[("events<br/>журнал аудита")]
|
|
|
|
|
|
CHECKS[("checks<br/>результаты проверок,<br/>source=egress|inbound-site-N")]
|
|
|
|
|
|
IPQ[("ip_queue<br/>state, *_complete,<br/>overall_result")]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
AGG["Агрегация (оркестратор):<br/>по достижении всех *_complete<br/>или по таймауту checking_window_seconds"]
|
|
|
|
|
|
|
|
|
|
|
|
ADMIN["Оператор:<br/>GET /api/v1/admin/status<br/>GET /api/v1/admin/ips<br/>GET /api/v1/admin/ips/{ip}"]
|
|
|
|
|
|
|
|
|
|
|
|
VA -->|"config_received,<br/>self_check_result, ..."| EP1 --> EVENTS
|
|
|
|
|
|
VA -->|"success, detected_egress_ip"| EP2 --> EVENTS
|
|
|
|
|
|
EP2 -.->|"успех → egress_complete"| IPQ
|
|
|
|
|
|
VA -->|"check_type, target,<br/>success, latency_ms"| EP3 --> CHECKS
|
|
|
|
|
|
P1 & P2 & P3 -->|"check_type, success,<br/>latency_ms, complete"| EP4 --> CHECKS
|
|
|
|
|
|
EP4 -.->|"complete=true → siteN_complete"| IPQ
|
|
|
|
|
|
|
|
|
|
|
|
CHECKS --> AGG
|
|
|
|
|
|
IPQ --> AGG
|
|
|
|
|
|
AGG -->|"overall_result:<br/>pass / partial / fail"| IPQ
|
|
|
|
|
|
|
|
|
|
|
|
EVENTS --> ADMIN
|
|
|
|
|
|
CHECKS --> ADMIN
|
|
|
|
|
|
IPQ --> ADMIN
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Пояснение.** Телеметрия стекается в БД из четырёх независимых потоков
|
|
|
|
|
|
(один от агента-валидатора, три — по одному с каждой площадки),
|
|
|
|
|
|
записываясь в две таблицы: `events` — сырой журнал аудита (что и когда
|
|
|
|
|
|
произошло), `checks` — результат каждой отдельной проверки с указанием
|
|
|
|
|
|
источника (`source`: `egress` для валидатора, `inbound-site-1/2/3` для
|
|
|
|
|
|
площадок). Отдельно, по мере поступления данных, выставляются флаги
|
|
|
|
|
|
завершения (`egress_complete`, `site1/2/3_complete`) в `ip_queue`. Как
|
2026-08-21 11:25:52 +03:00
|
|
|
|
только все ожидаемые флаги выставлены — либо истекло время ожидания
|
2026-08-21 08:11:58 +03:00
|
|
|
|
(`checking_window_seconds`) — фоновая агрегация суммирует все строки
|
|
|
|
|
|
`checks` по текущей попытке и записывает итог (`pass`/`partial`/`fail`)
|
|
|
|
|
|
обратно в `ip_queue`. Оператор в любой момент читает уже накопленные
|
|
|
|
|
|
данные через административные `GET`-методы, не дожидаясь завершения
|
|
|
|
|
|
проверки — подробнее о значениях полей см.
|
|
|
|
|
|
[USAGE.md](USAGE.md#значения-полей-ip).
|
2026-08-21 11:25:52 +03:00
|
|
|
|
|
2026-08-26 20:47:54 +03:00
|
|
|
|
> На диаграмме показан пример с тремя площадками — это лишь иллюстрация,
|
|
|
|
|
|
> не ограничение. Площадки опциональны и их число не ограничено: сколько
|
|
|
|
|
|
> их ожидать, определяется списком `sites` в конфиге control-api (пустой
|
|
|
|
|
|
> список — ни одного потока `inbound-site-N`, агрегация ждёт только
|
|
|
|
|
|
> `egress_complete`; N площадок — N параллельных потоков телеметрии). См.
|
2026-08-21 11:25:52 +03:00
|
|
|
|
> [USAGE.md](USAGE.md#управление-площадками-проберами).
|