75 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| EvoBGP архитектура | Оба профиля по умолчанию на PostgreSQL (один движок, одни миграции). reference — микросервисы + PG + брокер; microVPS — evobgp-all + контейнер PG (жёсткий тюнинг). SQLite — опция только для одного контейнера без PG. REST API проработан в §7 плана (пути /v1, jobs, бандлы нод); OpenAPI — канон при появлении схемы. |
|
false |
EvoBGP — архитектурный план
Control-plane на Go, анонс префиксов через BIRD, политика и история в SQL-БД, управление по REST. Репозиторий кода пока пустой — документ задаёт целевую архитектуру.
Содержание
- Структура репозитория (файлы и пакеты)
- Два эталонных профиля
- Логическая модель и термины
- Сервисы и контейнеры
- 7.1. Общие соглашения
- 7.2. Системные и служебные
- 7.3. Модули префиксов
- 7.4. DoH-профили
- 7.5. BGP community
- 7.6. Пиры
- 7.7. Спикеры BIRD
- 7.8. Ревизии конфигурации
- 7.9. Применение конфигурации
- 7.10. Задачи
- 7.11. Реплики и бандлы
- 7.12. Глобальные настройки
- 7.13. Матрица прав
- 7.14. Следующие итерации
- 7.15. Связь API с разделами плана
- Генерация BIRD и ревизии
- Эксплуатация и масштаб пиров
- Реплика evobgp-node
- Выбор СУБД
- Профиль microVPS — детализация
- Снижение рисков (меры и процессы)
- Тестирование BIRD2 и матрица сценариев
- CI/CD (Gitea Actions)
- Риски и этапы внедрения
- Web UI (Svelte, shadcn-svelte)
1. Структура репозитория (файлы и пакеты)
Monorepo на Go: общая логика в internal/*, отдельные бинарники в cmd/*. Цель — одна кодовая база для профилей reference (несколько процессов) и microVPS (evobgp-all).
Принципы:
**cmd/** — только точки входа: флаги, переменные окружения, сборка зависимостей (DI), запуск; без доменной логики.**internal/** — весь прикладной код; внешние модули Go не могут импортировать эти пакеты (правило компилятора).- Слои:
domain(модели и инварианты без I/O) →repositoryи адаптеры к БД/внешним API → пакеты воркеров (оркестрация) → транспорт (httpapi,jobs, клиент к агенту). - Один код — две упаковки: микросервисы и
evobgp-allиспользуют одни и те же пакетыinternal/*; отличается только набор процессов вcmd/*. **docs/,**scripts/— как сейчас в репозитории (контракт API: docs/openapi.yaml, вспомогательные скрипты).**deploy/**— Dockerfiles,docker-composeс профилямиreference/microVPS, при необходимости entrypoint’ы для bird2 / evobgp-agent; инфраструктура не смешивается сinternal/.
Целевое дерево каталогов (ориентир; имена подпакетов можно уточнить при первой итерации кода, роли каталогов зафиксированы):
EvoBGP/
├── cmd/
│ ├── evobgp-api/ # REST + постановка jobs (reference)
│ ├── evobgp-scheduler/
│ ├── evobgp-ingest/
│ ├── evobgp-render/
│ ├── evobgp-deploy/
│ ├── evobgp-all/ # microVPS: те же пакеты, один процесс / несколько goroutine
│ ├── evobgp-agent/ # рядом с bird2: запись конфигов, birdc
│ └── evobgp-node/ # pull бандла, проверка подписи, apply
├── internal/
│ ├── config/ # загрузка конфигурации (ENV, файлы)
│ ├── platform/ # логирование, метрики, трассировка, health
│ ├── db/ # пул, транзакции; embed миграций или вызов migrate
│ ├── repository/ # SQL по сущностям (tenant, module, peer, revision, jobs, …)
│ ├── domain/ # типы и правила без I/O (префиксы, community, ревизии)
│ ├── httpapi/ # роуты OpenAPI, middleware, валидация, маппинг в сервисы
│ ├── jobs/ # задачи: сейчас in-memory Registry в процессе API; PG job_audit / брокер — целевое расширение (см. примечание ниже §2)
│ ├── scheduler/ # триггеры по расписанию модулей
│ ├── ingest/ # CDN, DoH, нормализация, запись в БД
│ ├── render/ # материализация префиксов, ревизия, текст артефактов BIRD
│ ├── birdfmt/ # шаблоны и сборка include-фрагментов (альтернатива имени: bird/)
│ ├── deploy/ # доставка на volume, взаимодействие с evobgp-agent / бандлы
│ ├── bundle/ # упаковка и подпись бандла для evobgp-node
│ └── signing/ # ключи, проверка подписи на ноде
├── migrations/ # SQL миграции PostgreSQL (единый набор для обоих профилей)
├── deploy/
│ ├── compose/ # docker-compose с профилями
│ └── docker/ # Dockerfile на бинарь + общие слои
├── docs/
├── scripts/
├── go.mod
├── go.sum
└── README.md
Соответствие сервисам плана:
| Сервис (план) | Код |
|---|---|
| evobgp-api | cmd/evobgp-api, internal/httpapi, internal/jobs, internal/repository |
| evobgp-scheduler | cmd/evobgp-scheduler, internal/scheduler, internal/jobs, internal/repository |
| evobgp-ingest | cmd/evobgp-ingest, internal/ingest, internal/repository |
| evobgp-render | cmd/evobgp-render, internal/render, internal/birdfmt, internal/repository |
| evobgp-deploy | cmd/evobgp-deploy, internal/deploy, internal/bundle, internal/repository |
| evobgp-all | cmd/evobgp-all — поднимает HTTP и воркеры, импортируя те же internal/* |
| evobgp-agent | cmd/evobgp-agent, internal/deploy (запись на volume, birdc) |
| evobgp-node | cmd/evobgp-node, internal/bundle, internal/signing, internal/birdfmt / internal/deploy |
Поток пакетов (упрощённо):
flowchart TB
subgraph entry [cmd]
API[evobgp-api]
W[scheduler ingest render deploy]
end
subgraph internal [internal]
HTTP[httpapi]
J[jobs]
R[repository]
DBpkg[db]
REN[render]
BF[birdfmt]
DEP[deploy]
end
PG[(PostgreSQL)]
AG[evobgp-agent]
API --> HTTP
HTTP --> J
HTTP --> R
W --> J
W --> R
R --> DBpkg
DBpkg --> PG
REN --> BF
REN --> R
DEP --> R
DEP --> AG
2. Два эталонных профиля развёртывания
Один и тот же код в дереве 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 | 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) |
flowchart LR
subgraph ref [reference]
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
Правило: логика домена одинакова; один движок БД — PostgreSQL (одинаковые миграции и SQL). Отличаются число процессов Go, наличие брокера и настройки PG.
Примечание (текущий код vs целевая очередь): исполнение async jobs идёт через in-memory
jobs.Registryв процессеevobgp-api/evobgp-all; таблицаjob_auditв миграциях заложена под будущую персистенцию и идемпотентность между процессами. В reference Compose отдельныйevobgp-schedulerне читает эту очередь, а вызываетPOST .../modules/{id}/refreshпо HTTP. NATS в compose — для будущей интеграции; см. docs/architecture.md.
Опция
microVPS_sqlite: один контейнерevobgp-allбез PG — только если критичен абсолютный минимум контейнеров; иначе не рекомендуется как основной путь.
3. Логическая модель (общая для обоих профилей)
- BGP-сервер (ваш) — процесс BIRD, который анонсирует префиксы и держит сессии.
- Клиенты — внешние роутеры (BGP-пиры), подключающиеся к вам и получающие маршруты. Это не контейнеры EvoBGP.
- Мастер — control-plane + BIRD 2 в контейнере и контейнер
**evobgp-agent** (общий volume: сгенерированныеbird.d, сокет/канал дляbirdc). - EvoBGP-нода (опционально) — отдельная площадка: только pull подписанного бандла с мастера + BIRD 2 в Docker (тот же паттерн agent + bird2); своей полной БД и ingest нет.
Быстрый путь данных: БД → ingest (CDN / DoH / AS; IP_RANGES только читаются при render из БД) → render (префиксы + community + ревизия) → deploy → файлы BIRD → birdc configure → клиентские сессии.
4. Сервисы (сравнение профилей)
| Сервис | Назначение | 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, bird2 + evobgp-agent в Docker.
Зависимости (профиль reference)
flowchart TB
subgraph cp [Control plane]
API[evobgp-api]
SCH[scheduler]
ING[ingest]
REN[render]
DEP[deploy]
end
DB[(PostgreSQL)]
MQ[(Broker)]
API --> DB
API --> MQ
SCH --> DB
SCH --> MQ
ING --> DB
ING --> MQ
REN --> DB
REN --> MQ
DEP --> DB
DEP --> MQ
DEP --> AG[evobgp-agent]
AG --> BIRD2[bird2]
4.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-сети.
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 без полной БД (см. §10).
5. База данных, ETL, ER-схема
5.1. Группы сущностей
| Область | Назначение |
|---|---|
| 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 дополняет брокер |
5.2. ETL
flowchart LR
subgraph ex [Extract]
CDN[CDN fetch]
DOH[DoH]
AS[AS из БД]
IPR[IP ranges из БД]
end
subgraph tr [Transform]
NORM[Нормализация CIDR]
DEDUP[Дедуп]
COMM[Community]
end
subgraph ld [Load]
DB[(SQL БД)]
REV[revision]
ART[артефакты BIRD]
end
CDN --> NORM
DOH --> NORM
AS --> NORM
IPR --> NORM
NORM --> DEDUP --> COMM
COMM --> DB
COMM --> REV
REV --> ART
5.3. ER (упрощённо)
erDiagram
tenant ||--o{ module : owns
tenant ||--o{ bgp_community : owns
tenant ||--o{ bgp_peer : owns
tenant ||--o{ bgp_speaker : owns
doh_profile ||--o{ module : uses
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
config_revision ||--o{ revision_materialized_prefix : snapshot
module ||--o{ job_audit : tasks
5.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 (набросок: 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).
В reference очередь: брокер + job_audit; в microVPS — только БД и идемпотентность в job_audit.
6. Модули префиксов (AS / CDN / домены)
Продуктовая трактовка
В терминах продукта модуль — это один из четырёх видов источника префиксов: 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.
7. REST API
Статус: черновик для согласования и реализации; каноничная машиночитаемая форма — docs/openapi.yaml (по мере заполнения). Ниже — единая проработка путей и семантики (консолидация с docs/evobgp-api-sketches.md). Базовый префикс: **/v1**. Термины: §3, §5, §6.
7.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. |
7.2. Системные и служебные
| Метод | Путь | Назначение |
|---|---|---|
GET |
/v1/health |
Liveness (процесс жив). |
GET |
/v1/ready |
Readiness (БД, брокер при reference, и т.д.). |
GET |
/v1/version |
Версия сборки API и control-plane (git_sha, build_time). |
7.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** в пути — идентификатор конкретного экземпляра модуля, а не имя типа (согласовано с §6).
| Метод | Путь | Описание |
|---|---|---|
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 — зафиксировать в реализации. |
Пример тела создания модуля (набросок)
{
"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.
7.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} |
Удалить, если не используется модулями. |
7.5. BGP community (bgp_community)
| Метод | Путь | Описание |
|---|---|---|
GET |
/v1/communities |
Список справочника. |
POST |
/v1/communities |
Создать. |
GET |
/v1/communities/{id} |
Детали. |
PATCH |
/v1/communities/{id} |
Обновить. |
DELETE |
/v1/communities/{id} |
Удалить при отсутствии ссылок. |
7.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.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. |
7.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 или табличный). |
7.9. Применение конфигурации (deploy, BIRD)
| Метод | Путь | Описание |
|---|---|---|
POST |
/v1/apply |
Применить текущую целевую ревизию на всех спикерах (или по политике по умолчанию). **202**. |
POST |
/v1/speakers/{id}/apply |
Применить на одном спикере (canary). **202**. |
POST |
/v1/bird/reload |
Опционально: явный мягкий reload политики (если отделён от apply); иначе часть apply. |
Тело POST /v1/apply (набросок, опционально)
{
"revision_id": "01JQXYZ...",
"strategy": "all_speakers",
"dry_run": false
}
Связь с безопасным применением: §13 (двухфазный deploy, LKG).
7.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}
{
"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..." }
}
7.11. Реплики evobgp-node: бандлы
Вызываются нодой с отдельным ключом / mTLS (роль node). См. также §10.
| Метод | Путь | Описание |
|---|---|---|
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) — обязательно на ноде в production (§13).
7.12. Глобальные настройки (опционально)
| Метод | Путь | Описание |
|---|---|---|
GET |
/v1/settings |
KV вроде global_settings (лимиты CDN, feature flags). |
PATCH |
/v1/settings |
Частичное обновление (только роль operator). |
7.13. Матрица прав (роли)
| Ресурс | viewer |
editor |
operator |
node |
|---|---|---|---|---|
| GET модули, ревизии, peers | да | да | да | нет* |
| PATCH модули, peers | нет | да | да | нет |
| apply, rollback | нет | нет | да | нет |
| bundle / enroll | нет | нет | нет | да |
Нода не ходит в общий CRUD; только §7.11.
7.14. Следующие итерации API
- Полная OpenAPI 3.1 в
docs/openapi.yamlпо этому разделу. - Webhooks:
POSTна URL клиента по завершенииjob(опционально). - SSE/WebSocket для стрима статуса долгих jobs.
- Rate limits по ключу и по tenant в ответах (
RateLimit-*заголовки).
7.15. Связь API с разделами плана
| Тема плана | Подраздел §7 |
|---|---|
| REST, jobs, идемпотентность | 7.1, 7.10 |
refresh, apply, rollback, preview, IP_RANGES |
7.3, 7.8, 7.9 |
| peers, speakers, communities, DoH | 7.4–7.7 |
| bundle API, нода | 7.11 |
| Контрактные тесты HTTP | §14 + openapi.yaml |
Черновик в репозитории docs/evobgp-api-sketches.md держать синхронным с §7 при согласовании изменений (или пометить файл указателем на план как единый источник).
8. Генерация BIRD и ревизии
- Фрагменты
bird.d/*.conf,include, фильтры,peers.conf, community из справочника. - Ревизия: хэш набора префиксов, артефакты, откат = новая ревизия со старым содержимым.
9. Эксплуатация и масштаб
- До ~20+ клиентских пиров — строки
bgp_peer, не отдельные хосты EvoBGP. - Rate-limit CDN, per-module cooldown.
- Canary: несколько
bgp_speakerили подмножество пиров по фильтру. - Метрики: размер префикс-сета, ошибки DoH/CDN,
birdc show protocols. - Секреты BGP — Vault / K8s secrets, не plaintext в БД.
- Last-known-good конфиг на volume / bind-mount, общий для bird2 и evobgp-agent (или снимок на хосте при bind-mount).
10. Реплика evobgp-node
- Render на мастере упаковывает бандл (как для мастерского BIRD) + manifest (SHA-256) + подпись (например Ed25519).
- evobgp-node: fetch → проверка → распаковка →
birdc configure. - Общие фильтры/префиксы идентичны;
local.confна ноде (router id, source) — вне бандла. - Риски: дубли анонсов, отставание ревизий, компрометация без подписи.
11. Выбор СУБД
Решение по умолчанию: PostgreSQL в обоих профилях — один тип миграций, один SQL-диалект в коде (
pgx/database/sql), проще сопровождение и перенос с microVPS на reference без смены БД.
| Движок | Роль в плане |
|---|---|
| PostgreSQL | Основной для reference и microVPS (различаются только ресурсы и postgresql.conf). |
| SQLite | Опция microVPS_sqlite: один контейнер без PG — только при жёстком лимите «ровно один контейнер приложения+БД в одном процессе». |
| MySQL / MariaDB | Опционально по требованию заказчика/хостинга; тот же слой DAO через второй драйвер — вне дефолтного пути. |
| rqlite | HA без отдельного DBA Postgres; +контейнеры; на 1 ГиБ тесно. |
Почему PG «не много» и всё же два контейнера на microVPS
При узкой конфигурации (shared_buffers 64–128 МиБ, max_connections 15–30, один пул коннектов в evobgp-all, без сотен долгоживущих backend’ов) суммарный вклад PG сопоставим с практичным использованием SQLite в том же объёме RAM, зато:
- нет отличий DDL/типов между профилями;
- нормальные advisory locks /
SKIP LOCKEDдля очередиjob_audit; - проще подключить внешний managed Postgres при росте.
На microVPS отдельные контейнеры **postgres** и стек bird2 + evobgp-agent — осознанная плата за единообразие с reference (минимум: evobgp-all + postgres + bird2 + evobgp-agent).
PostgreSQL: память и CPU (ориентиры)
| Сценарий соединения | RAM на backend |
|---|---|
| Чистый idle | ~1.5 МиБ |
| После простых запросов | ~10–11 МиБ |
| После тяжёлых / temp | ~14.5 МиБ |
Плюс shared_buffers, relation cache при огромной схеме, autovacuum. reference: при многих процессах Go — PgBouncer (transaction pooling). microVPS: пулер часто не нужен, если суммарно ≤10 реальных коннектов к PG. Таймауты: idle_in_transaction_session_timeout, statement_timeout, параметры tcp_keepalives_*; мониторинг pg_stat_activity.
rqlite
Raft, HTTP/gorqlite; для HA control-plane; не замена дефолтного PG в плане без отдельного решения.
12. Профиль microVPS — детализация
Железо: 1 vCPU · ~1024 МиБ RAM · 7–10 ГиБ SSD под Docker + данные + логи · Ubuntu 24.04. Рекомендуется swap 512 МиБ–1 ГиБ, если его нет.
Контейнеры
| Вариант | Состав |
|---|---|
| A (целевой) | evobgp-all + postgres + bird2 + evobgp-agent (общий volume конфигов BIRD; см. §4.1) |
| B (опция) | Без отдельного PG — профиль microVPS_sqlite + тот же стек bird2 + evobgp-agent |
| C (legacy) | BIRD только на хосте ОС — не целевой путь, только для отладки или жёстких ограничений Docker |
Бюджет диска 7–10 ГиБ
| Статья | Ориентир |
|---|---|
| Образ evobgp-all | ~50–150 МиБ |
| Образ PostgreSQL | ~80–200 МиБ (слои образа) |
| Данные PG | ~200 МиБ – 2 ГиБ (политика ревизий) |
| Конфиги / бандлы | ~10–200 МиБ |
| Логи Docker | max-size / max-file в compose |
| Prune | docker system prune по расписанию |
| Резерв ОС/пики | ≥1–2 ГиБ |
CPU и RAM
- Worker pool ingest/render: 1–2; без агрессивного параллелизма на одном ядре.
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)
Пример направлений (не копировать слепо — проверить по мониторингу):
shared_buffers= 64–128 МиБ;max_connections= 20–40;work_memумеренно низкий.- Отключить или минимизировать
parallel_workersна 1 vCPU. effective_cache_sizeподсказка планировщику без выделения RAM.
Tuning PostgreSQL (reference)
Обычные практики под размер ВМ; PgBouncer при многих сервисах Go; резерв под autovacuum и пики ingest.
13. Снижение рисков (меры и процессы)
Дополняет §9 и §10 конкретными обязательными практиками.
Конфигурация BIRD: безопасное применение
- Двухфазный deploy: (1) запись новой ревизии во временный каталог на общем volume и проверка
**bird -c <path> -p** (парсинг без запуска демона; см.bird(8)); (2) только при нулевом коде выхода — атомарная подмена активных файлов (rename) и**birdc configure**. Опционально перед фазой (2) —preview/diff в control-plane (REST). - Last-known-good (LKG): хранить на volume предыдущую применённую ревизию; при неуспехе
configureили ненулевом exit автоматически восстановить файлы LKG, зафиксировать событие в логах/метриках и не оставлять BIRD в полусобранном состоянии. - Canary в production: перед полным apply — отдельный
bgp_speakerили подмножествоbgp_peer(см. §9); полный выкат только после проверки сессий/префиксов на канареечном спикере.
Данные, очередь, microVPS
- Миграции: в основной ветке — только вперёд; откат схемы — явные down-миграции (если приняты в процессе) или восстановление БД из бэкапа; политика фиксируется в операторской документации.
- Jobs: обязательные
**idempotency_key** и уникальность вjob_auditтам, где это предотвращает двойной apply/reload. - microVPS: пороги мониторинга на рост таблиц ревизий/артефактов, retention старых ревизий, лимиты ротации логов Docker (см. §12) — с алертами при приближении к лимиту диска и OOM.
Безопасность
- evobgp-node: в production обязательна проверка подписи бандла (отдельно от TLS транспорта); ключ подписи не смешивать с другими ролями.
- Секреты BGP (пароли, ключи) — только secret store / Docker secrets; не логировать полные конфиги с секретами.
Поставка и совместимость
- В Dockerfile / Compose зафиксировать версию образа BIRD 2 (тег minor или digest), совпадающую с образом, в котором выполняется
**bird -p** в CI (§15). - Статический каркас (router id, локальные интерфейсы, операторские правки) — в файлах вне автогенерируемых фрагментов; сгенерированное — только в согласованных путях
bird.d/(см. §8, §10).
Порядок внедрения (уточнение)
Перед полным набором микросервисов целесообразен параллельный этап: контракт OpenAPI + каркас internal/birdfmt + golden-тесты + проверка bird -p в CI (§14, §15), затем миграции PG и один вертикальный сценарий (например IP_RANGES).
14. Тестирование BIRD2 и матрица сценариев
Цель — покрыть поверхность генератора EvoBGP, а не весь язык BIRD. Комбинации фиксируются матрицей и каталогом сценариев в репозитории (internal/birdfmt/testdata/scenarios/).
Матрица покрытия (ориентир)
| Измерение | Варианты для покрытия |
|---|---|
| Роль спикера | master (полный набор фрагментов); реплика / бандл для evobgp-node (manifest + подмножество includes + локальный local.conf) |
| Типы модулей (выход render) | AS_PREFIXES, CDN_CIDRS, DOMAINS (материализованные префиксы), IP_RANGES — минимум по одному сценарию; комбинация 2+ типов в одной ревизии |
| Пиры | при поддержке каркасом — только static; 1× IPv4, 1× IPv6, несколько пиров, смешанный v4/v6 |
| Community | каждый поддерживаемый kind в справочнике + вариант без community (default) |
| Фильтры | экспорт «разрешить анонс»; при генерации — отрицательные кейсы (reject) |
| Граничные данные | пустой префикс-лист; один префикс; большой список (нагрузка на размер файла) |
| Шаблоны include | каждый именуемый фрагмент из internal/birdfmt участвует хотя бы в одном интеграционном сценарии |
По мере расширения генератора матрица дополняется; регрессия — новыми строками в таблице тестов и при необходимости новыми подкаталогами сценариев.
Виды тестов
- Unit / snapshot (Go): пакет
internal/birdfmt— вход из фикстур, выход сравнивается с*.goldenилиtxtar. - Синтаксис BIRD в CI: для каждого сценария с
bird.confвыполняется**bird -c … -p** в контейнере с той же major/minor версией BIRD 2, что в production (§13). - Позже: контрактные тесты HTTP по
docs/openapi.yamlи сценариям из §7 после реализацииinternal/httpapi.
15. CI/CD (Gitea Actions)
- Workflows: каталог
**.gitea/workflows/** в корне репозитория; синтаксис совместим с GitHub Actions (документация Gitea Actions). - Нужен зарегистрированный act runner с меткой
ubuntu-latest(или согласованной с инсталляцией) и при job с Docker — доступ Docker на runner. - Рекомендуемый pipeline: lint OpenAPI (
npx @redocly/cli lint docs/openapi.yaml),**go vet/go test/go build ./...**, проверка всехtestdata/scenarios/*/bird.confчерезbird -p(см. workflow в репозитории).
16. Риски и этапы внедрения
Риски
- Домены и устаревшие IP; DoH down; IRR/RIR vs локальные фильтры; community-ошибки; дубли при master+node; microVPS: переполнение диска логами/ревизиями, OOM без swap.
Этапы
- Monorepo Go, миграции PostgreSQL (основной путь), опционально SQLite для
microVPS_sqlite, ComposereferenceиmicroVPS. - Один тип модуля end-to-end; render + BIRD.
- Расписания CDN/модуля; deploy + agent.
- Ревизии, rollback, bundle API.
- evobgp-node на отдельной ВМ; observability.
- Hardening, документация операторская.
- Web UI в отдельном контейнере (§17): полный UX по спискам, расписанию и мониторингу.
17. Web UI (Svelte, shadcn-svelte)
Цель — единая операторская поверхность поверх уже описанного REST (§7) и observability (§4, этапы в §16), без дублирования бизнес-логики на фронтенде: UI только вызывает API и визуализирует состояние.
Стек и упаковка
- Svelte (актуальная ветка проекта, SvelteKit при необходимости SSR/роутинга) и shadcn-svelte — доступные компоненты (формы, таблицы, диалоги, навигация), единый визуальный язык.
- Отдельный сервис в Docker Compose (профиль reference): образ со статической сборкой или Node-сервером за reverse-proxy; не вшивать UI в
evobgp-api. Контейнер получает толькоVITE_*/ публичный base URL API и при необходимости URL метрик/health-прокси (см. ниже). - Сборка и публикация артефакта UI — отдельный job в CI (§15) по мере появления кода в репозитории (например
web/илиui/).
Покрытие user experience
- Списки и сущности — модули префиксов, ревизии, пиры, community, DoH-профили, спикеры: просмотр, фильтрация, создание/редактирование там, где это отражено в OpenAPI; связь с jobs и аудитом (§7.10).
- Расписание — триггеры и окна обновления модулей/ETL, ручной refresh, очередь задач и статусы без «чёрного ящика» (§7, scheduler в §1).
- Мониторинг системы — дашборд health API, агентов и нод; интеграция с метриками/алертами (Prometheus/Grafana или встроенные виджеты по публичным эндпоинтам); наглядное состояние BGP-сессий и последних deploy/revision там, где данные доступны через API или безопасный read-only прокси.
Безопасность и эксплуатация
- Аутентификация и роли — по §7.13; UI не хранит секреты вне согласованного потока (cookie/session или OIDC — на этапе проектирования конкретной инсталляции).
- Для microVPS полноценный отдельный контейнер UI опционален (можно тот же образ с
profilesили отключённый сервис), чтобы не раздувать single-node; приоритет — reference как эталон операторской панели.
Соответствие старым именам: full ≈ reference, target_vps ≈ microVPS.