init
This commit is contained in:
@@ -0,0 +1,368 @@
|
||||
---
|
||||
name: EvoBGP архитектура
|
||||
overview: "Control-plane на Go в Docker: микросервисы (API, планировщик, ingest, генерация BIRD, доставка на узлы), MySQL, брокер очередей; префиксы из AS/CDN/доменов, расписания, DoH, community-справочник, REST, ревизии и откат; data-plane — BIRD и агент на узлах."
|
||||
todos:
|
||||
- id: schema-mysql
|
||||
content: "Схема MySQL: модули, расписания, CDN-источники, DoH-профили, справочник community, привязки, пиры, узлы, ревизии, jobs"
|
||||
status: pending
|
||||
- id: bird-generator
|
||||
content: Определить формат bird.conf фрагментов, фильтры и точки reload/configure
|
||||
status: pending
|
||||
- id: rest-jobs
|
||||
content: Спецификация REST (refresh модуля, apply, preview, rollback) и async jobs
|
||||
status: pending
|
||||
- id: node-agent
|
||||
content: Протокол доставки конфига на до 20 узлов (агент + версии + canary)
|
||||
status: pending
|
||||
- id: observability
|
||||
content: Метрики, алерты на дрейф префиксов, статус пиров
|
||||
status: pending
|
||||
- id: docker-ms
|
||||
content: Dockerfile сервисов, compose (dev), сети/volumes, healthchecks
|
||||
status: pending
|
||||
- id: go-modules
|
||||
content: Структура Go-модулей, общие пакеты (db, models, bird templating)
|
||||
status: pending
|
||||
isProject: false
|
||||
---
|
||||
|
||||
# EvoBGP: быстрый анонс префиксов через BIRD + MySQL + REST
|
||||
|
||||
Репозиторий сейчас без кода — план описывает целевую архитектуру «с нуля». **Backend — Go.** Развёртывание control-plane — **контейнеры Docker**; оркестрация: `docker compose` для разработки, в production — Kubernetes / Nomad / Swarm по выбору.
|
||||
|
||||
## Целевая картина (логическая)
|
||||
|
||||
- **BIRD** — источник истины на уровне маршрутизации; **MySQL** — для политики, ревизий и материализованных префиксов.
|
||||
- **Быстрота:** очередь задач, идempotent-воркеры, при необходимости `birdc configure` после атомарной подмены include-файлов.
|
||||
|
||||
### Диаграмма: микросервисы и Docker (control-plane + data-plane)
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph edge [Периметр]
|
||||
LB[Traefik или Nginx]
|
||||
end
|
||||
subgraph docker [Docker host или кластер]
|
||||
API[evobgp-api Go]
|
||||
SCH[evobgp-scheduler Go]
|
||||
ING[evobgp-ingest Go]
|
||||
REN[evobgp-render Go]
|
||||
DEP[evobgp-deploy Go]
|
||||
MQ[(NATS или Redis Streams)]
|
||||
DB[(MySQL)]
|
||||
end
|
||||
subgraph nodes [До 20 узлов]
|
||||
AG1[evobgp-agent Go]
|
||||
BR1[BIRD]
|
||||
AG1 --> BR1
|
||||
end
|
||||
LB --> API
|
||||
API --> DB
|
||||
API --> MQ
|
||||
SCH --> DB
|
||||
SCH --> MQ
|
||||
ING --> MQ
|
||||
ING --> DB
|
||||
REN --> MQ
|
||||
REN --> DB
|
||||
DEP --> MQ
|
||||
DEP --> DB
|
||||
DEP -->|mTLS pull или push| AG1
|
||||
```
|
||||
|
||||
|
||||
|
||||
Назначение сервисов (можно объединять на раннем MVP, границы — контракты между пакетами):
|
||||
|
||||
|
||||
| Сервис | Роль |
|
||||
| -------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| **evobgp-api** | REST, аутентификация, CRUD сущностей, постановка задач (`refresh`, `apply`, `rollback`), `GET /jobs`. |
|
||||
| **evobgp-scheduler** | Читает интервалы модулей и CDN-строк из MySQL, публикует события «пора обновить модуль/источник» в очередь. |
|
||||
| **evobgp-ingest** | Fetch CDN, DoH-резолв доменов, загрузка AS/префиксов; пишет материализованные строки и сырые метаданные в MySQL. |
|
||||
| **evobgp-render** | Собирает итоговый набор префиксов + community, создаёт ревизию, генерирует артефакты BIRD (текст конфигов). |
|
||||
| **evobgp-deploy** | Доставка артефактов на узлы, учёт `node_config_version`, canary. |
|
||||
| **evobgp-agent** | Отдельный образ для узла: получение конфига, запись в volume, вызов `birdc`, отчёт о версии. |
|
||||
|
||||
|
||||
Инфраструктурные контейнеры: **MySQL**, **брокер очередей** (NATS JetStream или Redis), опционально **Valkey/Redis** для кэша и rate-limit по модулям.
|
||||
|
||||
---
|
||||
|
||||
## 1. MySQL: сущности и версионирование
|
||||
|
||||
Рекомендуемые группы таблиц:
|
||||
|
||||
|
||||
| Область | Назначение |
|
||||
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Модули** | Тип: `AS_PREFIXES` / `CDN_CIDRS` / `DOMAINS`; включён/выключен; приоритет; ссылки на расписание и (для доменов) DoH-профиль. |
|
||||
| **Расписания обновления** | Базовый интервал на **модуль** (`refresh_interval_sec`, cron или interval); см. ниже про переопределение на CDN. |
|
||||
| **Источники CDN внутри модуля** | Для типа `CDN_CIDRS`: несколько записей «URL/статический список» на модуль; у **каждой** записи свой опциональный `refresh_interval_sec` (если NULL — брать интервал модуля). |
|
||||
| **Профили DoH** | URL HTTPS DoH (`https://…/dns-query`), опционально имя для SNI, таймауты, доверие к сертификату (политика); привязка к модулям `DOMAINS` или глобальный default. |
|
||||
| **Содержимое модуля** | AS и префиксы; CDN-строки; FQDN; у каждой сущности — **привязка к community** (FK). |
|
||||
| **Справочник BGP community** | Канонические записи: `standard` (65535:123), `large` (x:y:z) при необходимости, человекочитаемое имя, описание, `tenant_id`. |
|
||||
| **Привязки community** | Связь «сущность → community»: для **домена**, **ASN**, **префикса/CIDR** (в т.ч. из CDN-листа) — `community_id`; при генерации BIRD маршруты/фильтры получают соответствующий `bgp_community.add()`. |
|
||||
| **Пиры** | neighbor IP, ASN, пароли/ключи (лучше ссылка на секреты), BGP параметры, привязка к группе узлов. |
|
||||
| **Узлы** | Идентификатор узла (hostname), роль, теги для «каким пирам/политикам подчиняться». |
|
||||
| **История (append-only)** | Снимок состояния или дифф после каждого успешного применения; `revision_id`, автор (API key/user), timestamp. |
|
||||
| **Журнал заданий** | Очередь «пересобрать модуль X», «откатить на revision Y», статус, ошибки. |
|
||||
|
||||
|
||||
### Расписание: модуль и отдельно каждый CDN-источник
|
||||
|
||||
- **Уровень модуля:** поля вроде `refresh_interval_seconds` и/или `cron_expr` (если нужны окна по времени); воркер ставит следующий запуск по минимальному интервалу среди дочерних сущностей.
|
||||
- **Уровень CDN-строки** (таблица `module_cdn_sources` или аналог): для каждого URL/файла — **опционально** свой `refresh_interval_seconds`. Если задан — имеет приоритет над модулем для **fetch** этого списка; если NULL — используется интервал модуля.
|
||||
- **Домены и AS:** по умолчанию следуют расписанию модуля; при необходимости позже можно добавить переопределение на уровне отдельной записи FQDN (аналогично CDN).
|
||||
|
||||
### DoH для резолва доменов
|
||||
|
||||
- В БД хранится **профиль** (`doh_profiles`): базовый URL DoH, при необходимости заголовки/API-ключ (секрет — вне БД или зашифровано), таймаут, лимит параллельных запросов.
|
||||
- Модуль типа `DOMAINS` ссылается на `doh_profile_id` (или наследует default из глобальных настроек).
|
||||
- Воркер выполняет DNS-запросы **только через выбранный DoH** (RFC 8484 JSON или wire-format POST — зафиксировать один поддерживаемый режим в реализации), а не системный stub resolver, чтобы поведение было предсказуемым и привязанным к политике.
|
||||
|
||||
### Справочник community и привязки
|
||||
|
||||
- Таблица `bgp_community` (справочник): имя, тип (`standard` / `large` / `extended` — по потребности), значения полей, уникальность по `(tenant_id, representation)`.
|
||||
- Для **каждой** привязываемой сущности в контенте модулей — поле `community_id` (nullable: «наследовать от модуля» или «без community» по политике):
|
||||
- домен → community;
|
||||
- ASN (в AS-модуле) → community;
|
||||
- CIDR/префикс (в т.ч. строка из CDN-листа после парсинга) → community.
|
||||
- **Разрешение конфликтов:** если один префикс попал из двух источников с разными community — в плане заложить явное правило (приоритет модуля, приоритет специфичности CIDR, или запрет дубликата с алертом). Зафиксировать в конфиге по умолчанию: «более специфичный источник wins» + лог предупреждения.
|
||||
|
||||
**Генерация BIRD:** для каждого итогового префикса (или группы) в `filter` экспорта добавляется соответствующий `bgp_community.add(...)` из справочника; именованные community можно сгенерировать как `define` в отдельном include.
|
||||
|
||||
**Откат:** не переписывать текущее состояние «вручную», а хранить **ревизии** (например JSON-снимок или нормализованные строки в history-таблицах). Операция rollback = `INSERT` новой ревизии с содержимым выбранной старой + триггер перегенерации. Так история остаётся линейной и аудируемой.
|
||||
|
||||
**Дополнительно:** мягкие блокировки (`SELECT ... FOR UPDATE` на уровне модуля/узла при применении), чтобы два REST-вызова не портили друг друга.
|
||||
|
||||
### Диаграмма ETL (от источников до BIRD и ревизий)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph extract [Extract]
|
||||
CDN[CDN URL и HTTP fetch]
|
||||
DOH[DoH A или AAAA]
|
||||
AS[AS и префиксы из БД]
|
||||
end
|
||||
subgraph transform [Transform]
|
||||
NORM[Нормализация CIDR]
|
||||
DEDUP[Дедуп и конфликты]
|
||||
COMM[Подстановка community]
|
||||
end
|
||||
subgraph load [Load]
|
||||
MYSQL[(MySQL материализация)]
|
||||
REV[revision и snapshot]
|
||||
ART[Артефакты BIRD]
|
||||
end
|
||||
subgraph out [Выход]
|
||||
BIRD[BIRD на узлах]
|
||||
end
|
||||
CDN --> NORM
|
||||
DOH --> NORM
|
||||
AS --> NORM
|
||||
NORM --> DEDUP
|
||||
DEDUP --> COMM
|
||||
COMM --> MYSQL
|
||||
COMM --> REV
|
||||
REV --> ART
|
||||
ART --> BIRD
|
||||
```
|
||||
|
||||
|
||||
|
||||
Пояснение: **Extract** разнесён по сервису `evobgp-ingest`; **Transform** частично в ingest, частично в `evobgp-render` (финальное объединение модулей); **Load** — транзакции в MySQL + запись файлов/объектов для деплоя.
|
||||
|
||||
### Диаграмма схемы MySQL (сущности и зависимости FK)
|
||||
|
||||
Схема упрощена; имена таблиц — ориентир для миграций (`golang-migrate` / `goose`).
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
tenant ||--o{ module : owns
|
||||
tenant ||--o{ bgp_community : owns
|
||||
tenant ||--o{ bgp_peer : owns
|
||||
doh_profile ||--o{ module : uses
|
||||
module ||--o{ module_cdn_source : contains
|
||||
module ||--o{ module_domain_entry : contains
|
||||
module ||--o{ module_as_entry : contains
|
||||
bgp_community ||--o{ module_domain_entry : tags
|
||||
bgp_community ||--o{ module_as_entry : tags
|
||||
bgp_community ||--o{ module_cdn_source : tags
|
||||
bgp_node ||--o{ node_peer_binding : has
|
||||
bgp_peer ||--o{ node_peer_binding : has
|
||||
module ||--o{ config_revision : produces
|
||||
config_revision ||--o{ revision_materialized_prefix : snapshot
|
||||
module ||--o{ job_audit : async_tasks
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Пояснения к таблицам MySQL
|
||||
|
||||
Ниже — **назначение**, **основные поля (логически)** и **кто пишет/читает**. Точные типы и индексы задаются в миграциях.
|
||||
|
||||
|
||||
| Таблица | Назначение | Ключевые поля и смысл | Кто использует |
|
||||
| -------------------------------- | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
|
||||
| **tenant** | Изоляция клиентов/организаций (multi-tenant). | `id`, `name`, `slug`, статус; все сущности ниже с `tenant_id` при необходимости. | API, все сервисы при фильтрации. |
|
||||
| **module** | Логический блок политики: тип `AS_PREFIXES` / `CDN_CIDRS` / `DOMAINS`, включён ли, приоритет при конфликтах. | `tenant_id`, `type`, `enabled`, `priority`, `doh_profile_id` (для DOMAINS), `refresh_interval_sec` (и/или `cron_expr`), `default_community_id` (опционально для наследования). | API (CRUD), scheduler (интервалы), ingest/render (содержимое). |
|
||||
| **doh_profile** | Параметры DNS over HTTPS для резолва доменов. | `url` (HTTPS DoH), таймауты, ссылка на секрет (ID в Vault/K8s, не сам пароль в открытом виде), политика TLS. | Модули DOMAINS, ingest. |
|
||||
| **module_cdn_source** | Один источник CDN внутри модуля типа `CDN_CIDRS`: URL или встроенный список. | `module_id`, `source_kind` (url / inline), `url`, `etag`, `last_modified`, `refresh_interval_sec` (если NULL — брать из `module`), `community_id` (тег для префиксов из этого источника). | Ingest (fetch), render. |
|
||||
| **module_domain_entry** | Одна строка FQDN в модуле `DOMAINS`. | `module_id`, `fqdn`, `community_id`, опционально переопределение интервала; материализованные поля после резолва можно хранить в отдельной таблице или здесь (`last_resolved_at`, хэш ответа). | Ingest (DoH), render. |
|
||||
| **module_as_entry** | Одна строка в модуле `AS_PREFIXES`: ASN и/или явный префикс. | `module_id`, `asn`, `prefix` (nullable если задаётся только ASN), `community_id`. | API, render (если данные не из внешнего IRR — тогда расширить провайдером). |
|
||||
| **bgp_community** | Справочник BGP community для экспорта в BIRD. | `tenant_id`, `name`, `kind` (standard/large/extended), числовые поля значения, уникальность в рамках tenant. | API, render (генерация `filter` / `define`). |
|
||||
| **bgp_peer** | Описание BGP-соседа (логический пир). | `tenant_id`, neighbor IP, remote ASN, локальные политики, **ссылка на секрет** (MD5/TC), `group_name`/`tags` для выбора на узлах. | API, render (`peers.conf`), deploy. |
|
||||
| **bgp_node** | Узел сети, где крутится BIRD и агент. | `tenant_id`, `hostname`, `api_endpoint` или идентификатор для mTLS, `tags`, `last_applied_revision_id`. | deploy, API (статус), мониторинг. |
|
||||
| **node_peer_binding** | Какие пиры подняты на каком узле (many-to-many). | `bgp_node_id`, `bgp_peer_id`, возможно переопределение при необходимости. | API, render (генерация только релевантных сессий на узел). |
|
||||
| **config_revision** | Неизменяемая точка истории после успешного применения политики. | `id`, `module_id` или `NULL` (глобальная ревизия), `created_at`, `author`, `hash` префикс-сета, ссылка на артефакт (путь/URL в object storage), `parent_revision_id` (для отката как «новая ревизия со старым содержимым»). | render, deploy, API (rollback, audit). |
|
||||
| **revision_materialized_prefix** | Снимок итоговых префиксов для ревизии (для быстрого diff и отката без пересчёта из сырья). | `revision_id`, `prefix`, `cidr_len`, `community_id`, `source` (модуль/тип). | render (запись), API (preview, diff), откат. |
|
||||
| **job_audit** | Журнал асинхронных операций (дополняет брокер, не заменяет его). | `id`, `kind` (refresh / apply / rollback), `module_id`, `status`, `error`, `idempotency_key`, `created_at`. | API, операторы, ретраи. |
|
||||
|
||||
|
||||
**Дополнительно (по необходимости):**
|
||||
|
||||
- `**global_settings`** — ключ–значение для дефолтного DoH, лимитов, feature flags; одна строка на tenant или плоская таблица.
|
||||
- `**module_cdn_fetch_log`** (опционально) — сырые ответы HTTP, размер, время, для отладки CDN; с TTL очистки.
|
||||
|
||||
Очередь в **NATS/Redis** в MySQL не дублируется обязательно; `job_audit` нужен для **идемпотентности**, **аудита** и отображения статуса в UI.
|
||||
|
||||
### Диаграмма зависимостей сервисов и компонентов
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph clients [Клиенты]
|
||||
CLI[CLI или CI]
|
||||
UI[Опционально UI]
|
||||
end
|
||||
clients --> LB
|
||||
LB[Reverse proxy]
|
||||
LB --> API
|
||||
API --> MYSQL[(MySQL)]
|
||||
API --> MQ[Message broker]
|
||||
SCH[scheduler] --> MYSQL
|
||||
SCH --> MQ
|
||||
ING[ingest] --> MQ
|
||||
ING --> MYSQL
|
||||
ING --> EXT[Интернет CDN и DoH]
|
||||
REN[render] --> MQ
|
||||
REN --> MYSQL
|
||||
DEP[deploy] --> MQ
|
||||
DEP --> MYSQL
|
||||
DEP --> AG[evobgp-agent]
|
||||
AG --> BIRD[BIRD]
|
||||
PROM[Prometheus] --> API
|
||||
PROM --> ING
|
||||
PROM --> AG
|
||||
```
|
||||
|
||||
|
||||
|
||||
**Зависимости по данным:** все мутирующие сервисы согласуются через **MySQL** и **очередь**; агент не ходит в MySQL напрямую, только к API/deploy или к артефакт-хранилищу (S3/minio + подпись), в зависимости от выбранной реализации `evobgp-deploy`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Три типа include-модулей
|
||||
|
||||
|
||||
| Тип | Ввод | Поведение |
|
||||
| ----------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| **AS / префиксы** | Список AS или явные префиксы | Импорт из ваших таблиц или опционально **pdb/API RIR** (вне scope MVP — заложить интерфейс `PrefixProvider`). |
|
||||
| **CDN CIDR** | URL или статический список | Периодический fetch + парсинг (plain text, JSON); хранить `etag`/`last_modified` для условных запросов. |
|
||||
| **Домены** | FQDN | См. ниже: в BIRD **не** попадают строки доменов — только результат резолва. |
|
||||
|
||||
|
||||
### FQDN → что именно кладётся в `include` BIRD
|
||||
|
||||
**В конфигурацию BIRD доменные имена не записываются.** В языке BIRD нет встроенного «подставь IP по DNS при reload» для списков анонсируемых префиксов: политика и `filter` оперируют **префиксами** (и community и т.д.), а не FQDN.
|
||||
|
||||
Пайплайн для модуля `DOMAINS`:
|
||||
|
||||
1. **Воркер (control plane)** по расписанию модуля, по TTL или по `POST /modules/{id}/refresh` выполняет DNS lookup (A/AAAA) для каждого FQDN **через DoH-профиль** модуля (см. раздел про DoH в MySQL).
|
||||
2. Результат нормализуется в префиксы, обычно **хост-префиксы** `/32` (IPv4) и `/128` (IPv6) для каждого полученного адреса; при необходимости политика может задавать агрегацию (редко для «точечных» CDN/host записей).
|
||||
3. В MySQL хранятся и **исходные FQDN** (для аудита и повторного резолва), и **материализованный набор префиксов** с `resolved_at` / сроком жизни.
|
||||
4. **Генератор** собирает обычный статический фрагмент, например `include "/etc/bird.d/prefixes_from_domains.conf"`, внутри — объявления вида `route` / набор в `define` / список в `filter` (конкретный синтаксис зависит от выбранной схемы BIRD 2.x), но **только из IP-префиксов**, уже полученных на шаге 2.
|
||||
|
||||
Итог: **include в BIRD — это всегда уже готовые префиксы**; смена IP у DNS обновляет анонс только после следующего успешного резолва и перегенерации конфига + `birdc configure` (или эквивалент). Это совпадает с ограничением из раздела «Риски»: без частого refresh доменный модуль может отставать от реальности.
|
||||
|
||||
Общий пайплайн: модуль → нормализованный список **префиксов + community из справочника по привязкам** → объединение с дедупликацией и политикой конфликтов (более специфичный wins или явный приоритет модулей).
|
||||
|
||||
---
|
||||
|
||||
## 3. REST API: обновление «отдельного модуля»
|
||||
|
||||
Минимальный набор эндпоинтов:
|
||||
|
||||
- `POST /modules/{id}/refresh` — пересобрать только этот модуль (CDN fetch / DNS refresh / перечитать AS-данные).
|
||||
- `POST /apply` или `POST /nodes/{id}/apply` — сгенерировать конфиг и применить (см. раздел про узлы).
|
||||
- `GET /revisions`, `POST /revisions/{id}/rollback`.
|
||||
- `POST /peers` / `PATCH /peers/{id}` — добавление/изменение пира; опционально `POST /peers/{id}/apply`.
|
||||
- CRUD для **профилей DoH**, **справочника community**, **расписаний** (если вынесены из PATCH модуля) — по необходимости UI/автоматизации.
|
||||
|
||||
Ответы — **202 Accepted** + `job_id`, если работа асинхронная; **GET /jobs/{id}** для статуса.
|
||||
|
||||
Аутентификация: API keys или mTLS для production.
|
||||
|
||||
---
|
||||
|
||||
## 4. Генерация BIRD и «на лету»
|
||||
|
||||
- Генерировать **фрагменты** (`/etc/bird.d/*.conf`) и один `bird.conf` с `include`.
|
||||
- Статические фильтры: префиксы из БД; для экспорта — **community** из справочника по привязкам (отдельный include с `define` или динамика в `filter` по классам префиксов).
|
||||
- **RPKI** (опционально позже) — отдельный блок.
|
||||
- **Пиры:** отдельный include `peers.conf`; при изменении — перезапись файла и `birdc configure` (или полный reload по политике безопасности).
|
||||
|
||||
Где возможно, использовать **runtime** команды BIRD для соседей; если версия/политика требует только файл — документировать один поддерживаемый путь (проще сопровождать).
|
||||
|
||||
---
|
||||
|
||||
## 5. История и быстрый откат
|
||||
|
||||
- Каждое успешное применение создаёт **revision** с хэшем содержимого анонсируемого набора и ссылкой на сгенерированные артефакты (опционально хранить сам `bird` snippet в BLOB для форензики).
|
||||
- Откат = создание новой ревизии с данными из выбранной + тот же pipeline генерации.
|
||||
- Индексы по `(module_id, created_at)` и `(revision_id)` для быстрых запросов.
|
||||
|
||||
---
|
||||
|
||||
## 6. Масштаб до ~20 узлов: предложения по улучшению
|
||||
|
||||
1. **Единый control-plane, много data-plane:** один API+воркер (или небольшой кластер API за балансировщиком), на каждом узле — **агент** (лёгкий daemon), который тянет готовый конфиг/дифф по **mTLS** или получает push через message queue. Так не нужен SSH с центра на 20 хостов.
|
||||
2. **Идентичность конфигурации:** таблица `node_config_version`; после деплоя агент репортит `applied_revision`. Дашборд «какой узел отстаёт».
|
||||
3. **Canary / поэтапный rollout:** сначала 1–2 узла, затем остальные — снижает риск массового bad announce.
|
||||
4. **Очередь и rate-limit:** массовый refresh всех CDN-модулей не должен DDOSить внешние списки; **per-module cooldown** в воркере.
|
||||
5. **Наблюдаемость:** метрики (Prometheus): время генерации, размер префикс-сета, ошибки DNS/CDN, статус BIRD-сессий (через экспортер или scrape `birdc`). Алерты на **аномальный рост/падение** числа префиксов.
|
||||
6. **Консистентность БД:** транзакции при записи ревизии + смене «текущего» указателя; миграции через Flyway/Liquibase или аналог.
|
||||
7. **Секреты:** пароли BGP не в открытом виде в MySQL — **Vault**, Kubernetes secrets, или зашифрованные поля с KMS.
|
||||
8. **Multi-tenant (если нужно):** `tenant_id` на модулях и пирах с самого начала — дешевле, чем латеральный рефакторинг.
|
||||
9. **Dry-run:** `POST .../preview` возвращает diff префиксов и фрагмент BIRD без применения — обязателен для операций с 20 узлами.
|
||||
10. **Резервный путь:** локальный last-known-good конфиг на узле, если центр недоступен (только чтение, без изменения политики до восстановления связи).
|
||||
|
||||
---
|
||||
|
||||
## Технологический стек
|
||||
|
||||
- **Backend:** **Go** (1.22+): REST на `chi` / `echo` / `fiber`; драйвер MySQL — `database/sql` + `sqlc` или GORM по согласованию команды; DNS DoH — HTTP-клиент с проверкой TLS.
|
||||
- **Миграции:** `golang-migrate` или `goose`, SQL в репозитории.
|
||||
- **Контейнеры:** отдельный **multi-stage Dockerfile** на сервис (минимальный образ `distroless` или `alpine`); `docker compose.yaml` для локальной среды: `mysql`, `nats` или `redis`, сервисы `api`, `scheduler`, `ingest`, `render`, `deploy`, опционально `minio` для артефактов.
|
||||
- **BIRD и агент:** BIRD обычно на хосте или в **privileged** контейнере с `CAP_NET_ADMIN` и доступом к сетевому стеку; образ `evobgp-agent` монтирует volume с конфигом и взаимодействует с сокетом `birdc` (монтирование `bird.ctl`).
|
||||
- **Наблюдаемость:** OpenTelemetry / Prometheus metrics в каждом Go-сервисе; единый `health` endpoint для оркестратора.
|
||||
|
||||
---
|
||||
|
||||
## Риски и границы
|
||||
|
||||
- **Домены в BGP:** IP меняются; без короткого TTL и мониторинга возможны утечки/дыры. Заложить политику «максимальный срок жизни записи».
|
||||
- **DoH:** недоступность выбранного резолвера блокирует обновление доменного модуля; иметь **fallback** (второй профиль или кратковременный отказ в смене префиксов с алертом) — по политике эксплуатации.
|
||||
- **Согласование «что анонсировать»** с регистрацией в RIR/IRR — отдельная дисциплина; система может лишь **не выходить за заданные в БД границы** (prefix filters).
|
||||
- **Community:** ошибка в справочнике или привязке ведёт к неверной маркировке трафика у апстримов; обязательны preview/diff перед apply и аудит изменений справочника.
|
||||
|
||||
---
|
||||
|
||||
## Предлагаемые этапы внедрения
|
||||
|
||||
1. Репозиторий Go (monorepo `cmd/<service>` + `internal/`), MySQL-миграции, `docker compose` с MySQL и брокером.
|
||||
2. Сервис `evobgp-api` + `evobgp-ingest` (один тип модуля) + очередь; затем `evobgp-render` и генерация BIRD.
|
||||
3. `evobgp-scheduler` и политики интервалов (модуль + CDN-строка).
|
||||
4. `evobgp-deploy` + `evobgp-agent`, ревизии и rollback в БД.
|
||||
5. Наблюдаемость, hardening контейнеров (non-root где возможно, read-only root), пилот на 2–3 узлах, затем шаблон для остальных.
|
||||
|
||||
Reference in New Issue
Block a user