Generalize frr_anycast role, add site-cloud environment (4 nodes, prepend, sNAT)
По updated_dia.png: новое окружение "Облачная площадка" (vr01-vr04, AS 65200, anycast 172.31.255.10/32) с двумя внешними BGP-каналами — основным (ASN 65104, без as-path prepend) и резервным (ASN 65103, с prepend на всех узлах) — плюс sNAT (nftables masquerade) на внешнем интерфейсе. Роль frr_anycast обобщена под это: вместо двух жёстко именованных соседей — список bgp_neighbors произвольной длины с флагом prepend; sNAT/ip_forward — опциональный блок (enable_snat). Площадка A мигрирована на новый формат host_vars/group_vars без изменения site-a.env и без изменения рендера — render-check.sh (golden-diff) по-прежнему проходит 6/6. Для site-cloud (окружение новое, ВМ не подняты) добавлен render-check-cloud.sh с grep-инвариантами: 4 соседа на узел, prepend только на резервном канале, nftables masquerade на внешнем интерфейсе — 56/56 проверок пройдено. run.sh обобщён на несколько окружений: инвентарь по имени playbook'а, env-файл через SITE_ENV_FILE (алиас SITE_A_ENV_FILE сохранён). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bc3HkMiDwooSyLBLoMKNyF
This commit is contained in:
1 parent
98f9f502ce
commit
b2b7306a3c
24 files changed
+431
-32
No files matched your search
@@ -89,32 +89,38 @@ docker compose exec -T c1 curl -s http://10.200.200.1/
|
||||
|
||||
Все специфичные для площадки A значения (ASN, anycast-префикс, router-id и BGP-соседи каждой ноды, имена интерфейсов, SSH-доступ) вынесены в единый файл переменных окружения `ansible/site-a.env` — сама роль `frr_anycast` полностью параметризована и не содержит захардкоженных адресов/ASN. `frr.conf.j2` при рендере воспроизводит уже проверенную в Docker-лабе BGP-конфигурацию (`frr/a{1,2,3}/frr.conf`), за вычетом блока `interface dummy0` — в VM-варианте этот адрес назначается через netplan (`dummy0.netplan.yml.j2`), а не через frr.conf.
|
||||
|
||||
Детали: [docs/2026-09-03-ansible-site-a-plan.md](docs/2026-09-03-ansible-site-a-plan.md) / [docs/2026-09-03-ansible-site-a-summary.md](docs/2026-09-03-ansible-site-a-summary.md).
|
||||
Роль `frr_anycast` обобщена: список BGP-соседей узла — не 2 жёстко именованных (`neighbor_b1`/`neighbor_b2`), а `bgp_neighbors` произвольной длины, каждый с флагом `prepend` (as-path prepend на исходящих анонсах). Опционально (`enable_snat: true`) роль также поднимает sNAT через `nftables` (masquerade на внешнем интерфейсе) — оба узла ниже используют эту одну и ту же роль с разными `group_vars`.
|
||||
|
||||
Детали: [docs/2026-09-03-ansible-site-a-plan.md](docs/2026-09-03-ansible-site-a-plan.md) / [docs/2026-09-03-ansible-site-a-summary.md](docs/2026-09-03-ansible-site-a-summary.md) — исходная реализация; [docs/2026-09-09-ansible-site-cloud-plan.md](docs/2026-09-09-ansible-site-cloud-plan.md) / [docs/2026-09-09-ansible-site-cloud-summary.md](docs/2026-09-09-ansible-site-cloud-summary.md) — доработка под второе окружение (см. ниже).
|
||||
|
||||
### Структура
|
||||
|
||||
```
|
||||
ansible/
|
||||
├── site-a.env источник всех site-A-специфичных значений
|
||||
├── run.sh source site-a.env + ansible-playbook
|
||||
├── inventory/site-a.yml a1/a2/a3, ansible_host из lookup('env', 'A{N}_MGMT_IP')
|
||||
├── group_vars/site_a.yml site-wide переменные (ASN, anycast-префикс, интерфейсы)
|
||||
├── host_vars/{a1,a2,a3}.yml per-node переменные (router-id, BGP-соседи)
|
||||
├── site-a.yml playbook (role: frr_anycast)
|
||||
├── roles/frr_anycast/ задачи, handlers, шаблоны (daemons.j2, frr.conf.j2, dummy0.netplan.yml.j2)
|
||||
└── tests/render-check.sh офлайн-проверка шаблонов без реальных ВМ (см. ниже)
|
||||
├── site-a.env / site-cloud.env источники site-специфичных значений (2 окружения)
|
||||
├── run.sh общий для всех окружений (SITE_ENV_FILE + имя playbook'а)
|
||||
├── inventory/{site-a,site-cloud}.yml ansible_host из lookup('env', ...)
|
||||
├── group_vars/{site_a,site_cloud}.yml site-wide переменные (ASN, anycast, интерфейсы, bgp_neighbors)
|
||||
├── host_vars/{a1,a2,a3,vr01..vr04}.yml per-node переменные (router-id, [bgp_neighbors])
|
||||
├── site-a.yml / site-cloud.yml playbook'и (role: frr_anycast — общая для обоих)
|
||||
├── roles/frr_anycast/ задачи, handlers, шаблоны (daemons.j2, frr.conf.j2,
|
||||
│ dummy0.netplan.yml.j2, nftables.conf.j2)
|
||||
└── tests/ render-check.sh (площадка A, golden-diff),
|
||||
render-check-cloud.sh (cloud, grep-инварианты)
|
||||
```
|
||||
|
||||
### Запуск
|
||||
|
||||
```bash
|
||||
cd ansible
|
||||
./run.sh site-a.yml # применить конфигурацию к a1/a2/a3
|
||||
./run.sh site-a.yml # применить конфигурацию к a1/a2/a3 (env по умолчанию: site-a.env)
|
||||
./run.sh site-a.yml --check --diff # сухой прогон
|
||||
```
|
||||
|
||||
Если `ansible-playbook` не установлен в системе — поставить локально в venv, не трогая системный Python: `python3 -m venv venv && venv/bin/pip install ansible` (каталог `venv/` в `.gitignore`, не коммитится); `run.sh` сам подхватит `venv/bin/ansible-playbook`, если он есть.
|
||||
|
||||
`run.sh` универсален для всех окружений в этом репозитории: инвентарь берётся по имени playbook'а (`X.yml` → `inventory/X.yml`), env-файл — из `SITE_ENV_FILE` (по умолчанию `site-a.env`).
|
||||
|
||||
### Проверка без живых ВМ
|
||||
|
||||
На момент подготовки playbook ВМ площадки A ещё не подняты (Terraform-провижининг — отдельный шаг), поэтому функциональная проверка (`vtysh`, реальный apply) не выполнялась и не входит в текущую поставку. Доступна и выполнена офлайн-проверка:
|
||||
@@ -126,3 +132,33 @@ ansible/tests/render-check.sh # golden-diff: рендер frr.conf
|
||||
```
|
||||
|
||||
После того как Terraform поднимет ВМ — реальный прогон `./run.sh site-a.yml`, затем те же `vtysh`-команды, что и в разделе «[Проверка окружения](#проверка-окружения)» выше (заменить `docker compose exec -T <node> vtysh ...` на `ssh <node> vtysh ...` или `ansible site_a -m command -a "vtysh -c 'show bgp summary'"`).
|
||||
|
||||
## Второе окружение: «Облачная площадка» (anycast + sNAT, 2 канала)
|
||||
|
||||
Второе, независимое от площадки A окружение (та же роль `frr_anycast`, другие `group_vars`/`host_vars`): 4 узла `vr01`…`vr04`, один AS `65200`, общий anycast-адрес `172.31.255.10/32`. У каждого узла — 2 приватных интерфейса-сегмента (не point-to-point, а общий L2 с обоими пирами стороны):
|
||||
|
||||
- **Основной канал** — сегмент к «Основная площадка» (внешняя сторона, ASN `65104`, пиры M1/M2) — анонсы **без** as-path prepend.
|
||||
- **Резервный канал** — сегмент к «Резервная площадка» (внешняя сторона, ASN `65103`, пиры B1/B2) — анонсы **с** as-path prepend (на всех 4 узлах, `AS_PATH_PREPEND_COUNT` из env, по умолчанию 3), чтобы при исправном основном канале трафик шёл через него.
|
||||
- **sNAT** (nftables, masquerade) на внешнем интерфейсе — на всех 4 узлах: трафик на anycast-адрес транслируется для выхода в интернет.
|
||||
|
||||
Все значения — в `ansible/site-cloud.env` (ASN, anycast-префикс, IP всех 4 пиров, имена интерфейсов, per-node router-id). Т.к. пиры общие для всех 4 узлов, список `bgp_neighbors` задан один раз в `group_vars/site_cloud.yml`, а не per-node.
|
||||
|
||||
```bash
|
||||
cd ansible
|
||||
SITE_ENV_FILE=site-cloud.env ./run.sh site-cloud.yml # применить
|
||||
SITE_ENV_FILE=site-cloud.env ./run.sh site-cloud.yml --check --diff # сухой прогон
|
||||
```
|
||||
|
||||
### Проверка без живых ВМ
|
||||
|
||||
ВМ этого окружения тоже не подняты — golden-файла для сравнения тоже нет (окружение новое), поэтому проверка через grep-инварианты вместо byte-diff:
|
||||
|
||||
```bash
|
||||
SITE_ENV_FILE=site-cloud.env ansible/run.sh site-cloud.yml --syntax-check
|
||||
ansible/tests/render-check.sh # регресс: площадка A рендерится как прежде
|
||||
ansible/tests/render-check-cloud.sh # 4 соседа, prepend только на резервном канале, sNAT
|
||||
```
|
||||
|
||||
`render-check-cloud.sh` проверяет: у каждого из 4 узлов ровно 4 `neighbor ... remote-as` (2×65104 без route-map, 2×65103 с `route-map RM-PREPEND-OUT out`), `route-map` содержит `set as-path prepend 65200 65200 65200`, `nftables.conf` содержит `masquerade` на заданном внешнем интерфейсе.
|
||||
|
||||
Детали и разбор диаграммы: [docs/2026-09-09-ansible-site-cloud-plan.md](docs/2026-09-09-ansible-site-cloud-plan.md) / [docs/2026-09-09-ansible-site-cloud-summary.md](docs/2026-09-09-ansible-site-cloud-summary.md).
|
||||
Reference in new issue
Block a user