Files
poc-frr-anycast/docs/2026-09-03-anycast-lab-summary.md
ayurishchevandClaude Sonnet 5 eaa577e6b7 Add FRR anycast lab: HLD, containerized topology, docs
Реализует HLD-дизайн (hld.md) в виде развёртываемого Docker Compose
окружения: 5 FRR-роутеров (A1-A3 anycast 10.200.200.1/32 на AS 65001,
B1/B2 на AS 65002/65003) + 6 клиентских контейнеров, ECMP-балансировка
трафика клиентов площадки B к anycast-адресу площадки A.

- docker-compose.yml, frr/*, entrypoints/* — топология и конфиги FRR
- scripts/verify.sh, scripts/traffic-test.sh — проверка BGP/ECMP и трафика
- hld.md — HLD-дизайн + Mermaid-диаграмма топологии
- README.md — запуск, структура, команды проверки на роутерах и клиентах
- docs/ — планы внедрения и summary по каждому изменению

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bc3HkMiDwooSyLBLoMKNyF
2026-09-03 12:52:44 +03:00

5.4 KiB
Raw Permalink Blame History

Summary: контейнерный POC anycast-топологии FRR

Дата: 2026-09-03 План: 2026-09-03-anycast-lab-plan.md

Что сделано

Топология из hld.md полностью развёрнута в Docker Compose (docker-compose.yml): 5 FRR-контейнеров (a1/a2/a3 — AS 65001, площадка A; b1/b2 — AS 65002/65003, площадка B) + 6 клиентских контейнеров (nicolaka/netshoot) на площадке B. 8 Docker-сетей воспроизводят все линки HLD (6 межплощадочных + 2 клиентских сегмента).

Созданные файлы: docker-compose.yml, frr/{a1,a2,a3,b1,b2}/{daemons,frr.conf,vtysh.conf}, entrypoints/{a-entrypoint.sh,b-entrypoint.sh,client-entrypoint.sh}, scripts/{verify.sh,traffic-test.sh}, README.md.

Отклонения от первоначального плана (обнаружены и устранены в процессе)

  1. /30 → /29 на межплощадочных линках. Docker всегда резервирует первый usable-адрес подсети под gateway моста, даже при internal: true. При буквальном /30 (только 2 usable-адреса) это конфликтовало с адресом .1, который нужен был роутеру A (Error: Address already in use). Решение — расширить линковые подсети до /29 и явно вынести gateway на неиспользуемый адрес (.6); адресация роутеров (.1/.2) осталась как в hld.md. Аналогично для клиентских /24-сетей gateway вынесен на .254, чтобы не конфликтовать с адресом B-роутера (.1).
  2. sysctl -w в entrypoint не работал (Read-only file system) — /proc/sys внутри контейнера доступен на запись только для sysctl'ов, заданных декларативно через Docker (sysctls: в compose), а не вызовом sysctl из процесса внутри контейнера. Перенесли net.ipv4.ip_forward=1 в docker-compose.yml.
  3. cap_sys_admin требуется FRR для namespace-операций — с cap_add: [NET_ADMIN, NET_RAW] zebra/bgpd не стартовали (privs_init: initial cap_set_proc failed). Добавили SYS_ADMIN в cap_add.
  4. ECMP не реагировал на src-port. С дефолтной политикой ядра net.ipv4.fib_multipath_hash_policy=0 next-hop хешируется только по src/dst IP — один клиент всегда получал один и тот же anycast-узел, что противоречило описанной в hld.md 5-tuple-логике. Установили net.ipv4.fib_multipath_hash_policy=1 на b1/b2.
  5. Убраны interface ethN из frr.conf. Раз Docker Compose уже назначает статические IP через ipv4_address, а zebra сам подхватывает существующие адреса интерфейсов, ручное дублирование адресов в frr.conf было источником риска (несовпадение имени интерфейса ethN с ожидаемым линком). Оставлен только dummy0 (единственный интерфейс, которого нет "из коробки" у Docker).

Результаты проверки

  • BGP: все 10 eBGP-сессий (a1/a2/a3 × b1/b2) в состоянии Established.
  • ECMP: у b1 и у b2 — по 3 равнозначных пути (weight 1) до 10.200.200.1/32, через a1/a2/a3 соответственно.
  • Связность клиент → anycast: ping/traceroute/curl с любого клиента (c1…c6) до 10.200.200.1 проходят.
  • Распределение трафика (scripts/traffic-test.sh): серии запросов с варьированием src-port показывают ответы от всех трёх anycast-узлов в примерно равной пропорции, например с c4 (30 запросов): a1: 13, a2: 2, a3: 15; с c2 (24 запроса): a1: 10, a2: 7, a3: 7. Ответ каждого узла содержит его hostname (мини HTTP-responder на dummy0), что визуально подтверждает, какой именно anycast-узел обслужил запрос.
  • Идемпотентность: docker compose down && docker compose up -d поднимает окружение с нуля без ручного вмешательства, BGP сходится за секунды.

Как повторить

docker compose up -d
./scripts/verify.sh
./scripts/traffic-test.sh c1 30
docker compose down

Дальнейшие возможные шаги (не выполнялись, вне рамок задачи)

  • Симуляция отказа одного из A-узлов (docker compose stop a2) для проверки конвергенции ECMP на оставшихся 2 путях.
  • Нагрузочный тест через iperf3 (уже есть в образе nicolaka/netshoot) вместо HTTP-responder.