diff --git a/README.md b/README.md index 1fa724f..201dfc0 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,10 @@ control-api. | Документ | Для чего | |---|---| -| [docs/SETUP.md](docs/SETUP.md) | Сборка, конфигурация, первый запуск стенда — с нуля | +| [docs/SETUP.md](docs/SETUP.md) | Развёртывание из готовых бинарников (`bin/`) или сборка из исходников, конфигурация, первый запуск стенда — с нуля | | [docs/USAGE.md](docs/USAGE.md) | Повседневная работа: постановка адресов в очередь, наблюдение за статусом, разбор результатов | | [docs/API.md](docs/API.md) | Спецификация HTTP API control-api и примеры запросов (curl) | +| [docs/DIAGRAMS.md](docs/DIAGRAMS.md) | Диаграммы потоков данных: control plane, поток проверки до целевого сервера, поток телеметрии | | [docs/LOCAL_E2E.md](docs/LOCAL_E2E.md) | Полностью офлайн-прогон всей системы одним скриптом — без реального облака и интернета | ## Быстрый старт (60 секунд, без OpenStack) @@ -40,8 +41,9 @@ scripts/run-local-e2e.sh ## Быстрый старт (реальный стенд) -1. Соберите три бинарника и подготовьте конфиги — - [docs/SETUP.md](docs/SETUP.md). +1. Возьмите готовые бинарники из `bin/` (Linux x86_64, статические, без + зависимостей) или соберите из исходников, подготовьте конфиги — + [docs/SETUP.md](docs/SETUP.md#получение-бинарников). 2. Разверните `control-api` на управляющей машине, `validator-agent` — на каждой ВМ-валидаторе, `prober` — на каждой из трёх площадок ([пошагово в docs/SETUP.md](docs/SETUP.md#развёртывание-control-api)). diff --git a/bin/SHA256SUMS b/bin/SHA256SUMS new file mode 100644 index 0000000..03d9480 --- /dev/null +++ b/bin/SHA256SUMS @@ -0,0 +1,3 @@ +f2649ce9ceb052b9d3658cb655b62ef6db4df679bd845850699017a40567f1f9 control-api +e28841e4956b098ccd8c276356ecab3e2a2c278889c6ac1b197163f3928a146e validator-agent +481a6c7fa79b12c9aeecf93411b9329b3023331be2aeb8031bda780b204e5eb1 prober diff --git a/bin/control-api b/bin/control-api new file mode 100755 index 0000000..ae16ea6 Binary files /dev/null and b/bin/control-api differ diff --git a/bin/prober b/bin/prober new file mode 100755 index 0000000..99da874 Binary files /dev/null and b/bin/prober differ diff --git a/bin/validator-agent b/bin/validator-agent new file mode 100755 index 0000000..0e6d152 Binary files /dev/null and b/bin/validator-agent differ diff --git a/docs/DIAGRAMS.md b/docs/DIAGRAMS.md new file mode 100644 index 0000000..6669b5e --- /dev/null +++ b/docs/DIAGRAMS.md @@ -0,0 +1,207 @@ +# Диаграммы потоков данных + +Три диаграммы, поясняющие устройство системы на уровне потоков данных — +дополнение к [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["Оператор"] + CFG["control-api.yaml
(validators, sites, targets,
ip_addresses, check_types)"] + ENV["control-api.env
(OS_AUTH_URL, OS_TOKEN, ...)"] + ADMIN["curl /api/v1/admin/*"] + end + + subgraph CAPI["control-api (управляющая машина, 1 экземпляр)"] + HTTP["HTTP API
/api/v1/agents/*
/api/v1/probers/*
/api/v1/admin/*
/healthz · /whatsmyip"] + ORCH["Оркестратор: Tick раз в
poll_interval_seconds
claim → associate FIP →
ожидание self-check →
checking → aggregate → release
+ lease sweep + heartbeat sweep"] + DB[("SQLite
validators / ip_queue
checks / events")] + OSCLIENT["OpenStack-клиент
(mode: mock | real)"] + end + + OS["OpenStack Neutron
Floating IP API"] + + VA["validator-agent ×N
(на каждой ВМ-валидаторе)"] + PR["prober ×3
(на каждой внешней площадке)"] + + CFG -->|"читается при старте
(инициализация validators, ip_queue)"| CAPI + ENV -->|"переменные окружения процесса"| OSCLIENT + ADMIN --> HTTP + HTTP --> ORCH + ORCH <--> DB + ORCH --> OSCLIENT + OSCLIENT -->|"associate / disassociate
floating ip"| OS + + VA <-->|"register, heartbeat,
GET assignment,
POST self-check/events/
results/complete"| HTTP + PR <-->|"register,
GET assignments,
POST results"| HTTP +``` + +**Пояснение.** `control-api` — единственный компонент с состоянием и +единственная точка принятия решений (какой IP кому назначить, когда +считать проверку завершённой). Конфигурация читается один раз при +старте процесса (горячей перезагрузки нет — изменения требуют +`systemctl restart control-api`, см. [SETUP.md](SETUP.md)). Оркестратор +работает по таймеру независимо от HTTP-запросов — назначение IP +валидаторам и агрегация результатов не привязаны к конкретному входящему +запросу, а выполняются фоновым циклом `Tick`. `validator-agent` и +`prober` — активная сторона: они сами инициируют все HTTP-запросы к +control-api (pull-модель), сам control-api к ним не обращается. + +--- + +## 2. Поток данных: от валидатора к целевому серверу (egress-проверка) + +Как валидатор проверяет, что через назначенный ему публичный адрес +реально работает исходящий доступ в интернет. + +```mermaid +flowchart LR + subgraph VM["ВМ-валидатор (сервисный проект OpenStack)"] + AGENT["validator-agent"] + end + + CAPI["control-api"] + FIP(["Floating IP
203.0.113.10
(адрес под проверкой,
привязан оркестратором заранее)"]) + + subgraph TARGETS["Целевые серверы (targets из конфига)"] + T1["hub.docker.com"] + T2["github.com"] + T3["packages.ubuntu.com"] + end + + AGENT -->|"1 GET /api/v1/whatsmyip
(self-check)"| CAPI + CAPI -.->|"2 наблюдаемый исходящий IP"| AGENT + AGENT ==>|"3 весь исходящий трафик ВМ
идёт через FIP (SNAT облака)"| FIP + FIP ==>|"4 HTTPS GET"| T1 + FIP ==>|"4 HTTPS GET"| T2 + FIP ==>|"4 ICMP echo"| T3 +``` + +**Пояснение.** Шаги 1–2 — самопроверка (self-check): агент обращается к +`control-api` и сравнивает адрес, с которого пришёл его собственный +запрос, с адресом, который ему назначен. Поскольку весь исходящий трафик +ВМ реально идёт через привязанный Floating IP (шаг 3, SNAT на стороне +облака), совпадение подтверждает, что назначение применилось корректно — +только после этого агент переходит к шагу 4 и выполняет проверки из +`check_config` (HTTPS/ICMP/опционально SSH) против целей из конфига. +Каждый результат отправляется обратно в control-api сразу после +выполнения (см. диаграмму телеметрии ниже) — сам этот data-plane трафик +(шаги 3–4) в control-api не проходит и им не наблюдается напрямую, +control-api видит только заявленный агентом результат. + +### Дополнительно: обратное направление (пробер к валидатору) + +Тот же Floating IP одновременно проверяется и «снаружи» — с трёх внешних +площадок, независимо от исходящих проверок агента: + +```mermaid +flowchart LR + subgraph SITES["3 внешние площадки"] + P1["prober site-1"] + P2["prober site-2"] + P3["prober site-3"] + end + + FIP(["тот же Floating IP
203.0.113.10"]) + VM["ВМ-валидатор
(слушает 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
(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
журнал аудита")] + CHECKS[("checks
результаты проверок,
source=egress|inbound-site-N")] + IPQ[("ip_queue
state, *_complete,
overall_result")] + end + + AGG["Агрегация (оркестратор):
по достижении всех *_complete
или по таймауту checking_window_seconds"] + + ADMIN["Оператор:
GET /api/v1/admin/status
GET /api/v1/admin/ips
GET /api/v1/admin/ips/{ip}"] + + VA -->|"config_received,
self_check_result, ..."| EP1 --> EVENTS + VA -->|"success, detected_egress_ip"| EP2 --> EVENTS + EP2 -.->|"успех → egress_complete"| IPQ + VA -->|"check_type, target,
success, latency_ms"| EP3 --> CHECKS + P1 & P2 & P3 -->|"check_type, success,
latency_ms, complete"| EP4 --> CHECKS + EP4 -.->|"complete=true → siteN_complete"| IPQ + + CHECKS --> AGG + IPQ --> AGG + AGG -->|"overall_result:
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`. Как +только все четыре флага выставлены — либо истекло время ожидания +(`checking_window_seconds`) — фоновая агрегация суммирует все строки +`checks` по текущей попытке и записывает итог (`pass`/`partial`/`fail`) +обратно в `ip_queue`. Оператор в любой момент читает уже накопленные +данные через административные `GET`-методы, не дожидаясь завершения +проверки — подробнее о значениях полей см. +[USAGE.md](USAGE.md#значения-полей-ip). diff --git a/docs/SETUP.md b/docs/SETUP.md index 7b81a96..3288641 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -1,16 +1,21 @@ # Подготовка стенда и первичная инициализация -Документ описывает, как собрать компоненты, подготовить конфигурацию и -запустить стенд с нуля — от чистой машины до работающего control-api, -валидаторов и проберов. Если нужно просто быстро посмотреть систему в -работе без реального OpenStack — сразу переходите к разделу +Документ описывает, как подготовить конфигурацию и запустить стенд с нуля +— от чистой машины до работающего control-api, валидаторов и проберов. +Бинарники брать не обязательно из исходников: в репозитории уже лежат +готовые сборки для Linux x86_64 (`bin/`) — это самый быстрый путь к +развёртыванию, см. [«Получение бинарников»](#получение-бинарников). Если +нужно просто быстро посмотреть систему в работе без реального OpenStack — +сразу переходите к разделу [«Быстрая проверка без OpenStack»](#быстрая-проверка-без-openstack-offline-режим). ## Содержание - [Компоненты и роли машин](#компоненты-и-роли-машин) - [Требования](#требования) -- [Сборка бинарников](#сборка-бинарников) +- [Получение бинарников](#получение-бинарников) + - [Вариант A: готовые бинарники из репозитория (рекомендуется)](#вариант-a-готовые-бинарники-из-репозитория-рекомендуется) + - [Вариант B: сборка из исходников](#вариант-b-сборка-из-исходников) - [Быстрая проверка без OpenStack (offline-режим)](#быстрая-проверка-без-openstack-offline-режим) - [Подготовка конфигурации для реального стенда](#подготовка-конфигурации-для-реального-стенда) - [Развёртывание control-api](#развёртывание-control-api) @@ -33,9 +38,12 @@ control-api (см. [API.md](API.md)). ## Требования -- **Go 1.22+** для сборки (проверено на Go 1.26). Собранные бинарники — - статические, дополнительных зависимостей на целевых машинах не требуют - (используется чистый Go-драйвер SQLite, без cgo). +- Целевые серверы (control-api, валидаторы, площадки) — **Linux + x86_64 (amd64)**. Для этой платформы в репозитории уже лежат готовые + бинарники (см. ниже) — устанавливать Go на целевые машины не требуется. +- **Go 1.22+** нужен только если вы пересобираете бинарники из + исходников (проверено на Go 1.26) — например, для другой платформы + (arm64, другая ОС) или после изменения кода. - Для `control-api` в боевом режиме (`openstack.mode: real`) — учётная запись OpenStack с правами на чтение/изменение floating IP (Neutron) в сервисном проекте, и заранее выделенные (allocated) floating IP — @@ -46,15 +54,65 @@ control-api (см. [API.md](API.md)). - `curl`, `sqlite3` (опционально, для ручной инспекции БД) на машине с control-api пригодятся для диагностики. -## Сборка бинарников +## Получение бинарников + +### Вариант A: готовые бинарники из репозитория (рекомендуется) + +В директории `bin/` репозитория уже лежат три готовых бинарника — +собирать их на целевых серверах не нужно, разворачивание сразу +начинается с копирования и запуска (раздел +[«Развёртывание control-api»](#развёртывание-control-api) и далее). + +``` +bin/ +├── control-api # ~11 МБ +├── validator-agent # ~7 МБ +├── prober # ~7 МБ +└── SHA256SUMS +``` + +Характеристики сборки: +- Платформа: `GOOS=linux GOARCH=amd64`. +- `CGO_ENABLED=0` — статическая линковка, без cgo (используется чистый + Go-драйвер SQLite `modernc.org/sqlite`). Дополнительные `.so`-библиотеки + и конкретная версия glibc на целевом сервере **не требуются**. +- Собрано флагами `-trimpath -ldflags="-s -w"` (без путей сборки и + отладочной информации — компактнее и без утечки информации о машине + сборки). + +Убедиться в отсутствии динамических зависимостей и целостности файлов +после переноса на целевой сервер: + +```bash +ldd bin/control-api # => "not a dynamic executable" +file bin/control-api # => ELF 64-bit LSB executable, x86-64, statically linked + +# После scp/rsync на целевой сервер — проверить, что файлы не повреждены: +sha256sum -c bin/SHA256SUMS +``` + +Перенос на целевые серверы, например: + +```bash +scp bin/control-api control-api-host:/tmp/ +scp bin/validator-agent validator-host-01:/tmp/ +scp bin/prober probe-site-1:/tmp/ +``` + +> Если целевая платформа отличается от linux/amd64 (например, ВМ на +> arm64) — готовые бинарники не подойдут, используйте +> [вариант B](#вариант-b-сборка-из-исходников). + +### Вариант B: сборка из исходников Из корня репозитория: ```bash export PATH=$PATH:/usr/local/go/bin # если go не в PATH -go build -o bin/control-api ./cmd/control-api -go build -o bin/validator-agent ./cmd/validator-agent -go build -o bin/prober ./cmd/prober +export CGO_ENABLED=0 GOOS=linux GOARCH=amd64 # поменяйте GOARCH для другой платформы +go build -trimpath -ldflags="-s -w" -o bin/control-api ./cmd/control-api +go build -trimpath -ldflags="-s -w" -o bin/validator-agent ./cmd/validator-agent +go build -trimpath -ldflags="-s -w" -o bin/prober ./cmd/prober ``` Каждый бинарник самодостаточен — скопируйте нужный файл на @@ -67,6 +125,14 @@ go build -o bin/prober ./cmd/prober go build ./... && go test ./... ``` +Пересобирайте из исходников и обновляйте `bin/` с зафиксированными +`SHA256SUMS`, если меняли код — готовые бинарники в репозитории **не +обновляются автоматически**: + +```bash +sha256sum bin/control-api bin/validator-agent bin/prober | sed 's#bin/##' > bin/SHA256SUMS +``` + ## Быстрая проверка без OpenStack (offline-режим) Прежде чем разворачивать реальный стенд, рекомендуется убедиться, что всё