Enhance EvoBGP architecture plan by refining the overview, updating todos with detailed descriptions of Docker configurations, and adding a new section on Docker Compose topology. Improved clarity on service roles and resource requirements for both reference and microVPS profiles.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: EvoBGP архитектура
|
||||
overview: 'Оба профиля по умолчанию на PostgreSQL (один движок, одни миграции). reference — микросервисы + PG + брокер; microVPS — evobgp-all + контейнер PG (жёсткий тюнинг). SQLite — опция только для одного контейнера без PG.'
|
||||
overview: Оба профиля по умолчанию на PostgreSQL (один движок, одни миграции). reference — микросервисы + PG + брокер; microVPS — evobgp-all + контейнер PG (жёсткий тюнинг). SQLite — опция только для одного контейнера без PG.
|
||||
todos:
|
||||
- id: schema-db
|
||||
content: "Схема БД: PostgreSQL (основной); опционально SQLite (microVPS single-container); модули, ревизии, jobs"
|
||||
@@ -12,13 +12,13 @@ todos:
|
||||
content: REST (refresh, apply, preview, rollback, bundle API) и async jobs
|
||||
status: pending
|
||||
- id: node-agent
|
||||
content: evobgp-agent на мастере; evobgp-node на реплике (отдельная ВМ)
|
||||
content: evobgp-agent + bird2 в Docker на мастере; evobgp-node + тот же паттерн на реплике (отдельная ВМ)
|
||||
status: pending
|
||||
- id: observability
|
||||
content: Метрики, алерты префиксов и BGP-сессий
|
||||
status: pending
|
||||
- id: docker-ms
|
||||
content: Compose profiles reference + microVPS, лимиты, логи, prune
|
||||
content: Compose profiles reference + microVPS; сервисы bird2 + evobgp-agent; сеть BGP; лимиты; логи; prune
|
||||
status: pending
|
||||
- id: go-modules
|
||||
content: Monorepo internal/*, cmd/evobgp-all и cmd/* для reference
|
||||
@@ -40,6 +40,7 @@ Control-plane на **Go**, анонс префиксов через **BIRD**, п
|
||||
1. [Два эталонных профиля](#1-два-эталонных-профиля-развёртывания)
|
||||
2. [Логическая модель и термины](#2-логическая-модель-общая-для-обоих-профилей)
|
||||
3. [Сервисы и контейнеры](#3-сервисы-сравнение-профилей)
|
||||
- [3.1. Топология Docker Compose](#31-топология-docker-compose)
|
||||
4. [База данных, ETL, ER-схема](#4-база-данных-etl-er-схема)
|
||||
5. [Модули префиксов и FQDN](#5-модули-префиксов-as-cdn-домены)
|
||||
6. [REST API](#6-rest-api)
|
||||
@@ -57,20 +58,20 @@ Control-plane на **Go**, анонс префиксов через **BIRD**, п
|
||||
Один и тот же **код** в дереве `internal/` (все подпакеты), две **упаковки** в Docker Compose.
|
||||
|
||||
|
||||
| Критерий | **reference** (эталон) | **microVPS** |
|
||||
| ---------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| **Назначение** | Production control-plane без жёсткого лимита RAM; горизонтальное масштабирование воркеров | Один хост: маленькая VPS / вложенная ВМ |
|
||||
| **CPU** | 2+ vCPU (рекомендуется) | **1 vCPU** |
|
||||
| **RAM** | 4+ ГиБ (ориентир) | **~1 ГиБ** |
|
||||
| **Диск под Docker + данные** | по объёму проекта | **7–10 ГиБ** (бюджет; не весь диск ОС) |
|
||||
| **ОС** | Linux (в т.ч. Ubuntu 22.04/24.04) | **Ubuntu 24.04 LTS** (референс) |
|
||||
| **Контейнеры Go** | 5 образов: `api`, `scheduler`, `ingest`, `render`, `deploy` | **1** образ: `evobgp-all` |
|
||||
| **БД** | **PostgreSQL** (отдельный сервис или managed) | **PostgreSQL** в контейнере (**жёсткий** тюнинг под 1 ГиБ) |
|
||||
| **Очередь** | **NATS JetStream** или **Redis Streams** (на выбор) | **Нет брокера** — `job_audit` в **PostgreSQL** + `SKIP LOCKED` / малый пул коннектов |
|
||||
| **Reverse proxy** | Traefik / Nginx (опционально) | **Нет** — прямой порт API |
|
||||
| **Object storage** | MinIO / S3 опционально для артефактов | Только **локальный volume** или небольшие BLOB в БД |
|
||||
| **BIRD** | Хост или privileged-контейнер + `evobgp-agent` | **Предпочтительно на хосте**; иначе +1 контейнер BIRD |
|
||||
| **Контейнеры (итого)** | 5 Go + PG + брокер (+ опц. proxy) | **2:** `evobgp-all` + **postgres** (+ опц. BIRD-контейнер); без 5×Go и без брокера |
|
||||
| Критерий | **reference** (эталон) | **microVPS** |
|
||||
| ---------------------------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| **Назначение** | Production control-plane без жёсткого лимита RAM; горизонтальное масштабирование воркеров | Один хост: маленькая VPS / вложенная ВМ |
|
||||
| **CPU** | 2+ vCPU (рекомендуется) | **1 vCPU** |
|
||||
| **RAM** | 4+ ГиБ (ориентир) | **~1 ГиБ** |
|
||||
| **Диск под Docker + данные** | по объёму проекта | **7–10 ГиБ** (бюджет; не весь диск ОС) |
|
||||
| **ОС** | Linux (в т.ч. Ubuntu 22.04/24.04) | **Ubuntu 24.04 LTS** (референс) |
|
||||
| **Контейнеры Go** | 5 образов: `api`, `scheduler`, `ingest`, `render`, `deploy` | **1** образ: `evobgp-all` |
|
||||
| **БД** | **PostgreSQL** (отдельный сервис или managed) | **PostgreSQL** в контейнере (**жёсткий** тюнинг под 1 ГиБ) |
|
||||
| **Очередь** | **NATS JetStream** или **Redis Streams** (на выбор) | **Нет брокера** — `job_audit` в **PostgreSQL** + `SKIP LOCKED` / малый пул коннектов |
|
||||
| **Reverse proxy** | Traefik / Nginx (опционально) | **Нет** — прямой порт API |
|
||||
| **Object storage** | MinIO / S3 опционально для артефактов | Только **локальный volume** или небольшие BLOB в БД |
|
||||
| **BIRD** | **BIRD 2** в **Docker** (privileged / нужные capabilities) + контейнер `**evobgp-agent`** с общим volume | То же: **bird2** + **evobgp-agent** + **postgres** + **evobgp-all** |
|
||||
| **Контейнеры (итого)** | 5×Go + **postgres** + брокер + **bird2** + **evobgp-agent** (+ опц. proxy) | **4:** **evobgp-all** + **postgres** + **bird2** + **evobgp-agent** (+ опц. нода вне VPS) |
|
||||
|
||||
|
||||
```mermaid
|
||||
@@ -79,13 +80,21 @@ flowchart LR
|
||||
R1[5x Go]
|
||||
R2[(PostgreSQL)]
|
||||
R3[(Broker)]
|
||||
R4[bird2]
|
||||
R5[evobgp-agent]
|
||||
R1 --> R2
|
||||
R1 --> R3
|
||||
R1 --> R5
|
||||
R5 --> R4
|
||||
end
|
||||
subgraph micro [microVPS]
|
||||
M1[evobgp-all]
|
||||
M2[(PostgreSQL)]
|
||||
M3[bird2]
|
||||
M4[evobgp-agent]
|
||||
M1 --> M2
|
||||
M1 --> M4
|
||||
M4 --> M3
|
||||
end
|
||||
```
|
||||
|
||||
@@ -101,28 +110,28 @@ flowchart LR
|
||||
|
||||
- **BGP-сервер (ваш)** — процесс **BIRD**, который **анонсирует** префиксы и держит сессии.
|
||||
- **Клиенты** — **внешние** роутеры (BGP-пиры), подключающиеся **к вам** и **получающие** маршруты. Это не контейнеры EvoBGP.
|
||||
- **Мастер** — control-plane + первичный BIRD (и `evobgp-agent` рядом с ним).
|
||||
- **EvoBGP-нода (опционально)** — отдельная площадка: **только** pull подписанного **бандла** с мастера + локальный BIRD; **своей** полной БД и ingest **нет**.
|
||||
- **Мастер** — control-plane + **BIRD 2** в **контейнере** и контейнер `**evobgp-agent`** (общий volume: сгенерированные `bird.d`, сокет/канал для `birdc`).
|
||||
- **EvoBGP-нода (опционально)** — отдельная площадка: **только** pull подписанного **бандла** с мастера + **BIRD 2 в Docker** (тот же паттерн agent + bird2); **своей** полной БД и ingest **нет**.
|
||||
|
||||
**Быстрый путь данных:** БД → ingest (CDN / DoH / AS) → render (префиксы + community + ревизия) → deploy → файлы BIRD → `birdc configure` → клиентские сессии.
|
||||
**Быстрый путь данных:** БД → ingest (CDN / DoH / AS; **IP_RANGES** только читаются при render из БД) → render (префиксы + community + ревизия) → deploy → файлы BIRD → `birdc configure` → клиентские сессии.
|
||||
|
||||
---
|
||||
|
||||
## 3. Сервисы (сравнение профилей)
|
||||
|
||||
|
||||
| Сервис | Назначение | reference | microVPS |
|
||||
| -------------------- | ---------------------------------------------- | ----------------------- | ------------------------ |
|
||||
| **evobgp-api** | REST, CRUD, задачи, `/jobs` | отдельный контейнер | goroutine в `evobgp-all` |
|
||||
| **evobgp-scheduler** | Интервалы модулей/CDN → события | отдельный контейнер | goroutine в `evobgp-all` |
|
||||
| **evobgp-ingest** | CDN, DoH, материализация в БД | отдельный контейнер | goroutine в `evobgp-all` |
|
||||
| **evobgp-render** | Итоговые префиксы, ревизия, текст BIRD | отдельный контейнер | goroutine в `evobgp-all` |
|
||||
| **evobgp-deploy** | Доставка на мастерский BIRD, публикация бандла | отдельный контейнер | goroutine в `evobgp-all` |
|
||||
| **evobgp-agent** | На хосте мастерского BIRD: файлы, `birdc` | бинарь/контейнер у BIRD | то же |
|
||||
| **evobgp-node** | Реплика: pull бандла, локальный BIRD | отдельный хост | **не на microVPS** |
|
||||
| Сервис | Назначение | reference | microVPS |
|
||||
| -------------------- | --------------------------------------------------------------- | -------------------------------- | ------------------------ |
|
||||
| **evobgp-api** | REST, CRUD, задачи, `/jobs` | отдельный контейнер | goroutine в `evobgp-all` |
|
||||
| **evobgp-scheduler** | Интервалы модулей/CDN → события | отдельный контейнер | goroutine в `evobgp-all` |
|
||||
| **evobgp-ingest** | CDN, DoH, материализация в БД | отдельный контейнер | goroutine в `evobgp-all` |
|
||||
| **evobgp-render** | Итоговые префиксы, ревизия, текст BIRD | отдельный контейнер | goroutine в `evobgp-all` |
|
||||
| **evobgp-deploy** | Доставка на мастерский BIRD, публикация бандла | отдельный контейнер | goroutine в `evobgp-all` |
|
||||
| **evobgp-agent** | Контейнер рядом с **bird2**: запись конфигов, `birdc configure` | то же (общий volume с **bird2**) | то же |
|
||||
| **evobgp-node** | Реплика: pull бандла, локальный BIRD | отдельный хост | **не на microVPS** |
|
||||
|
||||
|
||||
**Инфраструктура reference:** PostgreSQL, NATS или Redis, опционально Traefik, MinIO.
|
||||
**Инфраструктура reference:** PostgreSQL, NATS или Redis, опционально Traefik, MinIO, **bird2** + **evobgp-agent** в Docker.
|
||||
|
||||
### Зависимости (профиль reference)
|
||||
|
||||
@@ -148,11 +157,69 @@ flowchart TB
|
||||
DEP --> DB
|
||||
DEP --> MQ
|
||||
DEP --> AG[evobgp-agent]
|
||||
AG --> BIRD[BIRD мастер]
|
||||
AG --> BIRD2[bird2]
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 3.1. Топология Docker Compose
|
||||
|
||||
Целевая упаковка: **все компоненты мастера в Compose**, включая **BIRD 2** (`bird2`). Пара **bird2 + evobgp-agent** делает **общий именованный volume** (или bind-mount) для каталога конфигурации и точки управления `birdc` (см. образ/entrypoint в репозитории).
|
||||
|
||||
**Сеть для BGP:** на практике для входящих TCP **179** часто нужны `network_mode: host` (Linux), **macvlan/ipvlan** или публикация портов / отдельный L3-интерфейс — выбор фиксируется в профиле Compose и документации оператора; контейнер **bird2** получает **privileged** и набор **capabilities** (`NET_ADMIN`, и при необходимости `NET_RAW`), плюс `sysctls` под forwarding, если не на host-сети.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph refDocker [profile_reference]
|
||||
subgraph goRef [Сервисы Go]
|
||||
API1[evobgp-api]
|
||||
SCH1[scheduler]
|
||||
ING1[ingest]
|
||||
REN1[render]
|
||||
DEP1[deploy]
|
||||
end
|
||||
PG1[(postgres)]
|
||||
BR1[broker]
|
||||
subgraph bgpRef [Стек BGP Docker]
|
||||
AG1[evobgp-agent]
|
||||
B21[bird2]
|
||||
end
|
||||
VOL1[vol_bird_config]
|
||||
API1 --> PG1
|
||||
API1 --> BR1
|
||||
SCH1 --> PG1
|
||||
SCH1 --> BR1
|
||||
ING1 --> PG1
|
||||
ING1 --> BR1
|
||||
REN1 --> PG1
|
||||
REN1 --> BR1
|
||||
DEP1 --> PG1
|
||||
DEP1 --> BR1
|
||||
DEP1 --> AG1
|
||||
AG1 --> VOL1
|
||||
B21 --> VOL1
|
||||
AG1 -->|birdc| B21
|
||||
end
|
||||
subgraph microDocker [profile_microVPS]
|
||||
ALL[evobgp-all]
|
||||
PG2[(postgres)]
|
||||
subgraph bgpMicro [Стек BGP Docker]
|
||||
AG2[evobgp-agent]
|
||||
B22[bird2]
|
||||
end
|
||||
VOL2[vol_bird_config]
|
||||
ALL --> PG2
|
||||
ALL --> AG2
|
||||
AG2 --> VOL2
|
||||
B22 --> VOL2
|
||||
AG2 -->|birdc| B22
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
|
||||
На **реплике** (`evobgp-node`) — тот же паттерн **bird2 + evobgp-agent** в Docker на отдельном хосте; pull бандла и `birdc configure` без полной БД (см. §9).
|
||||
|
||||
---
|
||||
|
||||
## 4. База данных, ETL, ER-схема
|
||||
@@ -160,17 +227,17 @@ flowchart TB
|
||||
### 4.1. Группы сущностей
|
||||
|
||||
|
||||
| Область | Назначение |
|
||||
| ------------------------------------------------------ | ----------------------------------------------------------------------- |
|
||||
| **module** | Тип `AS_PREFIXES` / `CDN_CIDRS` / `DOMAINS`, расписание, DoH, приоритет |
|
||||
| **module_cdn_source** | URL/inline CDN; свой `refresh_interval` опционально |
|
||||
| **doh_profile** | URL DoH, таймауты, секреты по ссылке |
|
||||
| **module_domain_entry** / **module_as_entry** | FQDN или ASN/префикс + `community_id` |
|
||||
| **bgp_community** | Справочник community для BIRD |
|
||||
| **bgp_peer** | Клиентский пир; `speaker_id` NULL = все спикеры в бандле |
|
||||
| **bgp_speaker** | master / replica, `last_applied_revision_id` |
|
||||
| **config_revision** / **revision_materialized_prefix** | История, diff, откат |
|
||||
| **job_audit** | Асинхронные задачи; в reference дополняет брокер |
|
||||
| Область | Назначение |
|
||||
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **module** | Тип `AS_PREFIXES` / `CDN_CIDRS` / `DOMAINS` / `IP_RANGES`, расписание, DoH, приоритет |
|
||||
| **module_cdn_source** | URL + `source_kind` (формат тела списка); примеры наброска: `text_cidr_lines`, `json_prefix_list`, `custom`; ETag; свой `refresh_interval` опционально |
|
||||
| **doh_profile** | URL DoH, таймауты, секреты по ссылке |
|
||||
| **module_domain_entry** / **module_as_entry** / **module_ip_range_entry** | FQDN; или ASN/префикс; или **только CIDR/диапазон** + `community_id` (`IP_RANGES`) |
|
||||
| **bgp_community** | Справочник community для BIRD |
|
||||
| **bgp_peer** | Клиентский пир; `speaker_id` NULL = все спикеры в бандле |
|
||||
| **bgp_speaker** | master / replica, `last_applied_revision_id` |
|
||||
| **config_revision** / **revision_materialized_prefix** | История, diff, откат |
|
||||
| **job_audit** | Асинхронные задачи; в reference дополняет брокер |
|
||||
|
||||
|
||||
### 4.2. ETL
|
||||
@@ -181,6 +248,7 @@ flowchart LR
|
||||
CDN[CDN fetch]
|
||||
DOH[DoH]
|
||||
AS[AS из БД]
|
||||
IPR[IP ranges из БД]
|
||||
end
|
||||
subgraph tr [Transform]
|
||||
NORM[Нормализация CIDR]
|
||||
@@ -195,6 +263,7 @@ flowchart LR
|
||||
CDN --> NORM
|
||||
DOH --> NORM
|
||||
AS --> NORM
|
||||
IPR --> NORM
|
||||
NORM --> DEDUP --> COMM
|
||||
COMM --> DB
|
||||
COMM --> REV
|
||||
@@ -215,8 +284,10 @@ erDiagram
|
||||
module ||--o{ module_cdn_source : contains
|
||||
module ||--o{ module_domain_entry : contains
|
||||
module ||--o{ module_as_entry : contains
|
||||
module ||--o{ module_ip_range_entry : contains
|
||||
bgp_community ||--o{ module_domain_entry : tags
|
||||
bgp_community ||--o{ module_as_entry : tags
|
||||
bgp_community ||--o{ module_ip_range_entry : tags
|
||||
bgp_community ||--o{ module_cdn_source : tags
|
||||
bgp_speaker ||--o{ bgp_peer : scope
|
||||
module ||--o{ config_revision : produces
|
||||
@@ -229,20 +300,21 @@ erDiagram
|
||||
### 4.4. Пояснения к таблицам
|
||||
|
||||
|
||||
| Таблица | Назначение | Ключевые поля | Кто использует |
|
||||
| -------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------ |
|
||||
| **tenant** | Multi-tenant | `id`, `name`, `slug` | API, все сервисы |
|
||||
| **module** | Блок политики | `type`, `enabled`, `priority`, `doh_profile_id`, `refresh_interval_sec`, `cron_expr`, `default_community_id` | API, scheduler, ingest, render |
|
||||
| **doh_profile** | DoH | `url`, таймауты, ссылка на секрет | DOMAINS, ingest |
|
||||
| **module_cdn_source** | Строка CDN | `source_kind`, `url`, `etag`, `refresh_interval_sec`, `community_id` | ingest, render |
|
||||
| **module_domain_entry** | FQDN | `fqdn`, `community_id`, метаданные резолва | ingest, render |
|
||||
| **module_as_entry** | AS/префикс | `asn`, `prefix`, `community_id` | API, render |
|
||||
| **bgp_community** | Справочник | `kind`, значения, уникальность в tenant | API, render |
|
||||
| **bgp_peer** | Клиентский пир | neighbor, ASN, политики, `bgp_speaker_id` (NULL = все спикеры) | API, render, бандл |
|
||||
| **bgp_speaker** | Экземпляр BIRD | `role` master/replica, endpoint, `last_applied_revision_id` | deploy, нода |
|
||||
| **config_revision** | История | `hash`, артефакт, `parent_revision_id` | render, deploy, rollback |
|
||||
| **revision_materialized_prefix** | Снимок префиксов | `revision_id`, `prefix`, `community_id`, `source` | preview, diff, откат |
|
||||
| **job_audit** | Задачи | `kind`, `status`, `idempotency_key` | API, воркеры |
|
||||
| Таблица | Назначение | Ключевые поля | Кто использует |
|
||||
| -------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
|
||||
| **tenant** | Multi-tenant | `id`, `name`, `slug` | API, все сервисы |
|
||||
| **module** | Блок политики | `type`, `enabled`, `priority`, `doh_profile_id`, `refresh_interval_sec`, `cron_expr`, `default_community_id` | API, scheduler, ingest, render |
|
||||
| **doh_profile** | DoH | `url`, таймауты, ссылка на секрет | DOMAINS, ingest |
|
||||
| **module_cdn_source** | Строка CDN | `source_kind` (набросок: `text_cidr_lines`, `json_prefix_list`, `custom`), `url`, `etag`, `refresh_interval_sec`, `community_id` | ingest, render |
|
||||
| **module_domain_entry** | FQDN | `fqdn`, `community_id`, метаданные резолва | ingest, render |
|
||||
| **module_as_entry** | AS/префикс | `asn`, `prefix`, `community_id` | API, render |
|
||||
| **module_ip_range_entry** | Статический CIDR | `prefix` (CIDR), `community_id`; без ASN и без внешнего URL — модуль типа `IP_RANGES` | API, render |
|
||||
| **bgp_community** | Справочник | `kind`, значения, уникальность в tenant | API, render |
|
||||
| **bgp_peer** | Клиентский пир | neighbor, ASN, политики, `bgp_speaker_id` (NULL = все спикеры) | API, render, бандл |
|
||||
| **bgp_speaker** | Экземпляр BIRD | `role` master/replica, endpoint, `last_applied_revision_id` | deploy, нода |
|
||||
| **config_revision** | История | `hash`, артефакт, `parent_revision_id` | render, deploy, rollback |
|
||||
| **revision_materialized_prefix** | Снимок префиксов | `revision_id`, `prefix`, `community_id`, `source` | preview, diff, откат |
|
||||
| **job_audit** | Задачи | `kind`, `status`, `idempotency_key` | API, воркеры |
|
||||
|
||||
|
||||
Дополнительно: `**global_settings`** (KV); `**module_cdn_fetch_log`** (опционально, TTL).
|
||||
@@ -253,12 +325,17 @@ erDiagram
|
||||
|
||||
## 5. Модули префиксов (AS / CDN / домены)
|
||||
|
||||
### Продуктовая трактовка
|
||||
|
||||
| Тип | Ввод | Поведение |
|
||||
| ---------- | -------------- | -------------------------------------------------------- |
|
||||
| **AS** | ASN / префиксы | Таблица + опционально внешний `PrefixProvider` |
|
||||
| **CDN** | URL или список | Fetch, ETag, интервал модуля или строки |
|
||||
| **Домены** | FQDN | В BIRD попадают **только** IP-префиксы после DoH-резолва |
|
||||
В терминах продукта **модуль** — это один из **четырёх видов источника префиксов**: **AS** (`AS_PREFIXES`), **CDN** (`CDN_CIDRS`), **DOMAINS** (`DOMAINS`), **IP-диапазоны** (`IP_RANGES`). Наполнение задаётся либо **записями в таблице** (ASN или префикс + `community_id`; FQDN + `community_id` для доменов; **CIDR + `community_id`** для `IP_RANGES` без ASN и без внешнего URL), либо для CDN — **источником по URL** с полем `source_kind`, определяющим формат скачанного списка и парсер. Строка сущности `**module`** в БД — это экземпляр модуля выбранного типа (расписание, приоритет, DoH для доменов и т.д.); `**module_id` в API** — идентификатор экземпляра, а не «имя типа». При минимальном развёртывании (один bird2, мало пиров) допустим **один экземпляр на каждый нужный тип** или узкий набор экземпляров — это не противоречит модели.
|
||||
|
||||
|
||||
| Тип | Ввод | Поведение |
|
||||
| ---------------- | ---------------------------- | ------------------------------------------------------------------------- |
|
||||
| **AS** | ASN / префиксы | Таблица + опционально внешний `PrefixProvider` |
|
||||
| **CDN** | URL или список | Fetch, ETag, интервал модуля или строки |
|
||||
| **Домены** | FQDN | В BIRD попадают **только** IP-префиксы после DoH-резолва |
|
||||
| **IP-диапазоны** | CIDR (IPv4/IPv6) + community | Только таблица `module_ip_range_entry`; без IRR/ASN-семантики и без fetch |
|
||||
|
||||
|
||||
**FQDN:** воркер резолвит через **DoH-профиль** модуля → `/32` / `/128` (или политика) → материализация в БД → генерация static include для BIRD.
|
||||
@@ -267,6 +344,8 @@ erDiagram
|
||||
|
||||
## 6. REST API
|
||||
|
||||
Наброски путей, ролей и контрактов вынесены в **[docs/evobgp-api-sketches.md](docs/evobgp-api-sketches.md)** (`/v1`, задачи, бандлы нод).
|
||||
|
||||
- `POST /modules/{id}/refresh`
|
||||
- `POST /apply`, `POST /speakers/{id}/apply` или `/bird/apply`
|
||||
- `GET /revisions`, `POST /revisions/{id}/rollback`
|
||||
@@ -291,7 +370,7 @@ erDiagram
|
||||
- Canary: несколько `bgp_speaker` или подмножество пиров по фильтру.
|
||||
- Метрики: размер префикс-сета, ошибки DoH/CDN, `birdc show protocols`.
|
||||
- Секреты BGP — Vault / K8s secrets, не plaintext в БД.
|
||||
- Last-known-good конфиг на хосте BIRD.
|
||||
- Last-known-good конфиг на **volume** / bind-mount, общий для **bird2** и **evobgp-agent** (или снимок на хосте при bind-mount).
|
||||
|
||||
---
|
||||
|
||||
@@ -325,7 +404,7 @@ erDiagram
|
||||
- нормальные **advisory locks** / `SKIP LOCKED` для очереди `job_audit`;
|
||||
- проще подключить **внешний** managed Postgres при росте.
|
||||
|
||||
На **microVPS** отдельный контейнер `postgres` — **осознанная плата** за единообразие (2 контейнера: `evobgp-all` + `postgres`).
|
||||
На **microVPS** отдельные контейнеры `**postgres`** и стек **bird2 + evobgp-agent** — **осознанная плата** за единообразие с **reference** (минимум: `evobgp-all` + `postgres` + `bird2` + `evobgp-agent`).
|
||||
|
||||
### PostgreSQL: память и CPU (ориентиры)
|
||||
|
||||
@@ -352,11 +431,11 @@ Raft, HTTP/`gorqlite`; для HA control-plane; не замена дефолтн
|
||||
### Контейнеры
|
||||
|
||||
|
||||
| Вариант | Состав |
|
||||
| --------------- | ----------------------------------------------------------------------------- |
|
||||
| **A (целевой)** | **evobgp-all** + **postgres** (официальный образ Postgres, volume для данных) |
|
||||
| **B** | A + контейнер **BIRD** (privileged), если BIRD не на хосте Ubuntu |
|
||||
| **C (опция)** | Только **evobgp-all** + SQLite на volume — профиль **microVPS_sqlite** |
|
||||
| Вариант | Состав |
|
||||
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **A (целевой)** | **evobgp-all** + **postgres** + **bird2** + **evobgp-agent** (общий volume конфигов BIRD; см. [§3.1](#31-топология-docker-compose)) |
|
||||
| **B (опция)** | Без отдельного PG — профиль **microVPS_sqlite** + тот же стек **bird2** + **evobgp-agent** |
|
||||
| **C (legacy)** | BIRD только на хосте ОС — **не целевой путь**, только для отладки или жёстких ограничений Docker |
|
||||
|
||||
|
||||
### Бюджет диска 7–10 ГиБ
|
||||
@@ -376,8 +455,8 @@ Raft, HTTP/`gorqlite`; для HA control-plane; не замена дефолтн
|
||||
### CPU и RAM
|
||||
|
||||
- Worker pool ingest/render: **1–2**; без агрессивного параллелизма на одном ядре.
|
||||
- `deploy.resources`: лимиты на контейнеры **evobgp-all** и **postgres** (например PG `mem_limit` **256m–384m**, приложение **384m–512m** — подобрать по `free -m` на хосте).
|
||||
- Ориентир суммарно: **~350–650 МиБ** простой, **~450–800 МиБ** пик (**PG + Go + система + BIRD**) — на **1 ГиБ** нужны swap или ещё более жёсткий `shared_buffers`.
|
||||
- `deploy.resources`: лимиты на **evobgp-all**, **postgres**, **bird2**, **evobgp-agent** (на PG ориентир **256m–384m**, на пару **bird2+agent** заложить **128m–256m** — уточнить по `docker stats`).
|
||||
- Ориентир суммарно: **~400–750 МиБ** простой, **~550–900 МиБ** пик (**PG + Go + bird2 + система**) — на **1 ГиБ** обычно нужны **swap** и жёсткий тюнинг PG/`bird2`.
|
||||
|
||||
### Tuning PostgreSQL (microVPS)
|
||||
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
# EvoBGP — наброски HTTP API
|
||||
|
||||
**Статус:** черновик для согласования; не спецификация реализации. Базовый префикс: **`/v1`**. Модель данных и термины — в архитектурном плане (модули, `bgp_speaker`, `config_revision`, `job_audit`).
|
||||
|
||||
---
|
||||
|
||||
## 1. Общие соглашения
|
||||
|
||||
| Тема | Решение (набросок) |
|
||||
|------|---------------------|
|
||||
| **Аутентификация** | Заголовок `Authorization: Bearer <api_key>` или mTLS на edge; ключи привязаны к tenant и роли. |
|
||||
| **Multi-tenant** | Все сущности в скоупе tenant: либо из ключа, либо явный префикс `X-Tenant-Id` (только для супер-ролей). |
|
||||
| **Идентификаторы** | UUID v7 или ULID в URL; в JSON — строки. |
|
||||
| **Время** | ISO 8601 UTC (`2026-04-03T12:00:00Z`). |
|
||||
| **Ошибки** | Тело `application/problem+json` (RFC 9457): `type`, `title`, `status`, `detail`, `instance`, опционально `errors[]` по полям. |
|
||||
| **Идемпотентность** | Для мутаций, создающих задачи или побочные эффекты: заголовок `Idempotency-Key` (опционально обязателен для `POST` apply/refresh). |
|
||||
| **Пагинация** | `?cursor=<opaque>&limit=50` (cursor-based); ответ: `items`, `next_cursor`, `has_more`. |
|
||||
| **Асинхронные операции** | `202 Accepted`, заголовок `Location: /v1/jobs/{job_id}`; тело `{ "job_id", "status": "queued" }`. |
|
||||
| **Версионирование** | Несовместимые изменения — новый префикс `/v2`. |
|
||||
|
||||
---
|
||||
|
||||
## 2. Системные и служебные
|
||||
|
||||
| Метод | Путь | Назначение |
|
||||
|-------|------|------------|
|
||||
| `GET` | `/v1/health` | Liveness (процесс жив). |
|
||||
| `GET` | `/v1/ready` | Readiness (БД, брокер при reference, и т.д.). |
|
||||
| `GET` | `/v1/version` | Версия сборки API и control-plane (`git_sha`, `build_time`). |
|
||||
|
||||
---
|
||||
|
||||
## 3. Модули префиксов (`module`)
|
||||
|
||||
### Связь с продуктом
|
||||
|
||||
**ASN / CDN / DOMAINS / IP-диапазоны** в продуктовой формулировке — это **четыре вида модулей**. Поле **`type`** в `POST /v1/modules` выбирает вид: `AS_PREFIXES`, `CDN_CIDRS`, `DOMAINS` или **`IP_RANGES`**. Дочерние ресурсы: **`as-entries`**, **`cdn-sources`**, **`domain-entries`** — как раньше; **`ip-range-entries`** — статические **CIDR + `community_id`** (без ASN и без URL). **`module_id`** в пути — идентификатор **конкретного экземпляра** модуля, а не имя типа.
|
||||
|
||||
Типы: `AS_PREFIXES`, `CDN_CIDRS`, `DOMAINS`, `IP_RANGES` (как в плане).
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/modules` | Список модулей tenant (фильтры: `?type=`, `?enabled=`). |
|
||||
| `POST` | `/v1/modules` | Создать модуль. |
|
||||
| `GET` | `/v1/modules/{module_id}` | Детали модуля. |
|
||||
| `PATCH` | `/v1/modules/{module_id}` | Частичное обновление (расписание, DoH, приоритет, `enabled`). |
|
||||
| `DELETE` | `/v1/modules/{module_id}` | Мягкое удаление или `enabled=false` — зафиксировать в плане реализации. |
|
||||
|
||||
**CDN-источники модуля**
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/modules/{module_id}/cdn-sources` | Список строк CDN. |
|
||||
| `POST` | `/v1/modules/{module_id}/cdn-sources` | Добавить источник (URL + `source_kind` + опционально `community_id`). |
|
||||
| `PATCH` | `/v1/modules/{module_id}/cdn-sources/{source_id}` | URL, `source_kind`, `community_id`, свой `refresh_interval_sec`. |
|
||||
| `DELETE` | `/v1/modules/{module_id}/cdn-sources/{source_id}` | Удалить. |
|
||||
|
||||
**Записи AS / домены**
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/modules/{module_id}/as-entries` | Список ASN/префиксов. |
|
||||
| `POST` | `/v1/modules/{module_id}/as-entries` | Добавить. |
|
||||
| `PATCH` | `/v1/modules/{module_id}/as-entries/{entry_id}` | Обновить. |
|
||||
| `DELETE` | `/v1/modules/{module_id}/as-entries/{entry_id}` | Удалить. |
|
||||
| `GET` | `/v1/modules/{module_id}/domain-entries` | FQDN + community. |
|
||||
| `POST` | `/v1/modules/{module_id}/domain-entries` | Добавить. |
|
||||
| `PATCH` | `/v1/modules/{module_id}/domain-entries/{entry_id}` | Обновить. |
|
||||
| `DELETE` | `/v1/modules/{module_id}/domain-entries/{entry_id}` | Удалить. |
|
||||
|
||||
**Записи IP-диапазонов** (только для `type: IP_RANGES`)
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/modules/{module_id}/ip-range-entries` | Список CIDR + `community_id`. |
|
||||
| `POST` | `/v1/modules/{module_id}/ip-range-entries` | Добавить запись (`prefix`, `community_id`). |
|
||||
| `PATCH` | `/v1/modules/{module_id}/ip-range-entries/{entry_id}` | Обновить. |
|
||||
| `DELETE` | `/v1/modules/{module_id}/ip-range-entries/{entry_id}` | Удалить. |
|
||||
|
||||
**Refresh (ingest)**
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `POST` | `/v1/modules/{module_id}/refresh` | Запуск ingest для модуля (CDN / DoH / AS по типу). Для **`IP_RANGES`** обычно **не требуется** (данные только в БД); возможен **`204`** / no-op или отказ **`400`**, если тип не поддерживает refresh — зафиксировать в реализации. |
|
||||
|
||||
**Пример тела создания модуля (набросок)**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "CDN_CIDRS",
|
||||
"name": "edge-v4",
|
||||
"enabled": true,
|
||||
"priority": 10,
|
||||
"doh_profile_id": null,
|
||||
"refresh_interval_sec": 3600,
|
||||
"cron_expr": null,
|
||||
"default_community_id": "550e8400-e29b-41d4-a716-446655440000"
|
||||
}
|
||||
```
|
||||
|
||||
Пример модуля **`IP_RANGES`** (набросок): `type: "IP_RANGES"`, `doh_profile_id: null`, далее строки через `ip-range-entries` с полями `prefix` (например `203.0.113.0/24`) и `community_id`.
|
||||
|
||||
---
|
||||
|
||||
## 4. DoH-профили (`doh_profile`)
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/doh-profiles` | Список. |
|
||||
| `POST` | `/v1/doh-profiles` | Создать (URL, таймауты; секрет — ссылка на vault id или отдельный `POST .../secret`). |
|
||||
| `GET` | `/v1/doh-profiles/{id}` | Детали (без раскрытия секрета). |
|
||||
| `PATCH` | `/v1/doh-profiles/{id}` | Обновить. |
|
||||
| `DELETE` | `/v1/doh-profiles/{id}` | Удалить, если не используется модулями. |
|
||||
|
||||
---
|
||||
|
||||
## 5. BGP community (`bgp_community`)
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/communities` | Список справочника. |
|
||||
| `POST` | `/v1/communities` | Создать. |
|
||||
| `GET` | `/v1/communities/{id}` | Детали. |
|
||||
| `PATCH` | `/v1/communities/{id}` | Обновить. |
|
||||
| `DELETE` | `/v1/communities/{id}` | Удалить при отсутствии ссылок. |
|
||||
|
||||
---
|
||||
|
||||
## 6. Пиры (`bgp_peer`)
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/peers` | Список (`?speaker_id=`, пагинация). |
|
||||
| `POST` | `/v1/peers` | Создать пира. |
|
||||
| `GET` | `/v1/peers/{id}` | Детали. |
|
||||
| `PATCH` | `/v1/peers/{id}` | Политики, neighbor, ASN, привязка к `bgp_speaker_id` или `null` = все спикеры. |
|
||||
| `DELETE` | `/v1/peers/{id}` | Удалить / отключить. |
|
||||
|
||||
---
|
||||
|
||||
## 7. Спикеры BIRD (`bgp_speaker`)
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/speakers` | Список (master / replica, endpoint). |
|
||||
| `POST` | `/v1/speakers` | Зарегистрировать спикер (реплика, canary). |
|
||||
| `GET` | `/v1/speakers/{id}` | Детали + `last_applied_revision_id`. |
|
||||
| `PATCH` | `/v1/speakers/{id}` | Метаданные, endpoint. |
|
||||
|
||||
---
|
||||
|
||||
## 8. Ревизии конфигурации (`config_revision`)
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/revisions` | История ревизий (`?module_id=`, `?limit=`). |
|
||||
| `GET` | `/v1/revisions/{revision_id}` | Метаданные: хэш, родитель, время, артефакты. |
|
||||
| `GET` | `/v1/revisions/{revision_id}/prefixes` | Материализованный снимок префиксов (пагинация). |
|
||||
| `GET` | `/v1/revisions/{revision_id}/preview` | Превью фрагментов BIRD (read-only, без apply). |
|
||||
| `POST` | `/v1/revisions/{revision_id}/rollback` | Создать **новую** ревизию с содержимым отката; часто **`202`**. |
|
||||
|
||||
**Сравнение ревизий (набросок)**
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/revisions/{a}/diff/{b}` | Diff префиксов / метаданных (формат — зафиксировать: JSON patch или табличный). |
|
||||
|
||||
---
|
||||
|
||||
## 9. Применение конфигурации (deploy / BIRD)
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `POST` | `/v1/apply` | Применить текущую целевую ревизию на всех спикерах (или по политике по умолчанию). **`202`**. |
|
||||
| `POST` | `/v1/speakers/{id}/apply` | Применить на одном спикере (canary). **`202`**. |
|
||||
| `POST` | `/v1/bird/reload` | Опционально: явный мягкий reload политики (если отделён от apply); иначе часть `apply`. |
|
||||
|
||||
**Тело `POST /v1/apply` (набросок, опционально)**
|
||||
|
||||
```json
|
||||
{
|
||||
"revision_id": "01JQXYZ...",
|
||||
"strategy": "all_speakers",
|
||||
"dry_run": false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Задачи (`job_audit`)
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/jobs` | Список задач (`?status=`, `?kind=`, cursor). |
|
||||
| `GET` | `/v1/jobs/{job_id}` | Статус, прогресс, ошибка, связанные сущности. |
|
||||
| `POST` | `/v1/jobs/{job_id}/cancel` | Запрос отмены (best-effort). |
|
||||
|
||||
**Пример ответа `GET /v1/jobs/{id}`**
|
||||
|
||||
```json
|
||||
{
|
||||
"job_id": "01JQXYZ...",
|
||||
"kind": "module_refresh",
|
||||
"status": "running",
|
||||
"idempotency_key": "client-abc-123",
|
||||
"created_at": "2026-04-03T10:00:00Z",
|
||||
"started_at": "2026-04-03T10:00:01Z",
|
||||
"finished_at": null,
|
||||
"error": null,
|
||||
"meta": { "module_id": "01JQM..." }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Реплики (`evobgp-node`): бандлы
|
||||
|
||||
Вызываются **нодой** с отдельным ключом / mTLS (роль `node`).
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/speakers/{speaker_id}/revisions/latest` | Указатель на последнюю опубликованную ревизию для ноды. |
|
||||
| `GET` | `/v1/speakers/{speaker_id}/bundle/{revision_id}` | Скачивание подписанного бандла (архив + `manifest.json` + подпись). |
|
||||
| `POST` | `/v1/nodes/enroll` | Регистрация ноды (обмен ключами, привязка к `speaker_id`) — детали протокола отдельно. |
|
||||
|
||||
Заголовки для бандла: `Content-Type: application/octet-stream` или multipart; контроль целостности по `manifest` (SHA-256) и подписи (например Ed25519).
|
||||
|
||||
---
|
||||
|
||||
## 12. Глобальные настройки и операторские флаги (опционально)
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/v1/settings` | KV вроде `global_settings` (лимиты CDN, feature flags). |
|
||||
| `PATCH` | `/v1/settings` | Частичное обновление (только роль operator). |
|
||||
|
||||
---
|
||||
|
||||
## 13. Набросок матрицы прав (роли)
|
||||
|
||||
| Ресурс | `viewer` | `editor` | `operator` | `node` |
|
||||
|--------|----------|----------|------------|--------|
|
||||
| GET модули, ревизии, peers | да | да | да | нет* |
|
||||
| PATCH модули, peers | нет | да | да | нет |
|
||||
| apply, rollback | нет | нет | да | нет |
|
||||
| bundle / enroll | нет | нет | нет | да |
|
||||
|
||||
\*Нода не ходит в общий CRUD; только §11.
|
||||
|
||||
---
|
||||
|
||||
## 14. Что вынести в следующую итерацию
|
||||
|
||||
- Полная **OpenAPI 3.1** схема (`openapi.yaml`) из этого документа.
|
||||
- Webhooks: `POST` на URL клиента по завершении `job` (опционально).
|
||||
- SSE/WebSocket для стрима статуса долгих jobs.
|
||||
- Rate limits по ключу и по tenant в ответах (`RateLimit-*` заголовки).
|
||||
|
||||
---
|
||||
|
||||
## 15. Связь с архитектурным планом
|
||||
|
||||
| Тема плана | Раздел здесь |
|
||||
|------------|----------------|
|
||||
| REST, jobs | §1, §10 |
|
||||
| refresh, apply, rollback, preview, `IP_RANGES` | §3, §8, §9 |
|
||||
| peers, speakers, communities, DoH | §4–§7 |
|
||||
| bundle API, нода | §11 |
|
||||
|
||||
Файл плана: `.cursor/plans/evobgp_архитектура_0e73ef02.plan.md` (§6 REST API).
|
||||
+2313
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
extends:
|
||||
- recommended
|
||||
|
||||
rules:
|
||||
no-server-example.com: off
|
||||
operation-4xx-response: off
|
||||
Reference in New Issue
Block a user