Наша почта:
В Москве:
РФ (звонок бесплатный):
Как RouterOS в annet тащили
{ Сетевой инженер }
Владимир Кузнецов

Видео доклада

Презентация спикера

Как RouterOS в annet тащили
Annet (внутри Яндекса — «Аннушка») — это инструмент управления конфигурациями сетевого оборудования, разработанный командой инфраструктуры офисных сетей (Enterprise Network) и выложенный в open source. Продукт изначально создавался для сетевого инженера: генераторы конфигурации пишутся так, что инженер видит привычный синтаксис CLI и понимает, что именно произойдёт с конкретной железкой при применении настроек.
Вторая ставка — мультивендорность. При замене сетевой коробки одного вендора на другую все данные подтягиваются из кода и источника истины: неважно, меняется Cisco на Huawei или наоборот. Достаточно налить конфигурацию — и сеть работает так же, как прежде.
Доклад посвящён тому, как Annet работает с одним из самых специфичных CLI — MikroTik RouterOS.

Проблема: конфигурация, которая расходится с ожидаемой

Типичный цикл эксплуатации выглядит так: конфигурация наливается на устройство, сеть запускается и работает — до первого обращения. Дальше инженер подключается к железке, ищет проблему, быстро её фиксит. Так накапливаются legacy-настройки и выключенные правила (в случае MikroTik — особенно заметно). Чем дольше устройство работает, тем сложнее его диагностировать: конфигурация всё дальше уходит от ожидаемой.

Для большой и долго живущей инфраструктуры решением становится подход «инфраструктура как код». Прежде чем применять настройки на оборудовании, их можно протестировать локально и раскатать на канареечной группе. Когда группа расширяется, изменения фиксируются коммитом в систему контроля версий и раскатываются дальше. Если что-то пошло не так — коммит откатывается, и раскатывается предыдущая версия конфигов.

Что умеет Annet

  • Ядро.
    Генерирует конфигурацию, забирая данные из источника истины, который одновременно является документацией на всю сеть, — например, NetBox. Для него есть встроенный адаптер, тоже выложенный в репозитории.
  • Патч.
    На внутреннем сленге это называется «сварить конфиг» или «сварить патч». Патч — это уже вендор-читаемые команды, правильно отсортированные: одни настройки откатить, другие применить, всё в нужном синтаксисе. После применения патча diff должен стать пустым — это значит, что настройки приведены к ожидаемым и лишних висящих правил не осталось.
  • gnetcli.
    Сервис на Go, который умеет подключаться к разным вендорам разными протоколами. Чаще всего это три протокола: SSH; Telnet (для legacy-оборудования или оборудования в защищённом контуре); консоль — у серьёзных сетевых железок есть обязательное подключение через консольный сервер, по нему тоже можно применять конфигурацию, например при первоначальной настройке коробки.
  • Адаптер gnetcli.
    Набор правил о том, что именно нужно читать на железке. Читается прежде всего конфиг: на Cisco это show running-config, а на MikroTik нужны три команды — помимо самого экспорта, требуется прочитать файлы и пользователей, так как в базовый экспорт они не попадают.
  • annetbox.
    Клиент для NetBox как наиболее популярной системы для ведения инвентаря. При наличии другого инвентаря Annet можно научить ходить и в его API, но у NetBox API развит хорошо.

Почему CLI, а не API

Логичный вопрос: почему для настройки железок используется CLI, а не API? API — это интерфейс для взаимодействия одной системы с другой, а CLI — интерфейс для человека. Раскаткой конфигурации занимается человек: он пишет генератор на понятном ему синтаксисе и сразу видит, что делает. Разбирать JSON — задача для роботов. С таким выбором можно спорить, но на практике он показывает себя хорошо.

Как начать

Порог входа невысокий. Есть подробный туториал; при наличии NetBox всё дальнейшее упрощается, а сам NetBox при необходимости разворачивается по инструкции, в том числе из Docker. Annet — набор Python-пакетов, устанавливается просто. Сервис gnetcli на Go также ставится без сложностей.
Самые востребованные команды:
  • 1.
    annet gen — сгенерировать конфигурацию и посмотреть её в текстовом виде;
  • 2.
    annet diff — увидеть расхождение с ожидаемым;
  • 3.
    annet patch — получить набор команд для приведения к ожидаемому;
  • 4.
    annet deploy — применить конфигурацию.
Есть и другие команды — например, генерация конфигурации с комментариями о том, в каком именно генераторе появилась та или иная настройка. Это позволяет быстро понять, в какой файл нужно вносить правку — скажем, при замене SNMP-хоста.

Специфика RouterOS

Вендоры сетевого оборудования — тоже по-своему художники и видят мир в своём свете. В RouterOS есть стандартная обёртка find, и, казалось бы, чтобы отменить команду, достаточно заменить add на remove, подставить find со скобками — и надеяться, что применится. На практике этот приём работает не всегда.

Отдельный случай: если на железку заходили руками и удалили интерфейсы, IP-адреса остаются висеть на интерфейсе *, и при чтении конфига это тоже приходится обрабатывать.
Для таких ситуаций в Annet есть rulebook и механизм logic — набор правил, позволяющих кастомно обработать конкретные строки конфигурации. Всё это, как и генераторы, пишется на
Python — языке, на котором можно почти тезисно записать желаемое и получить рабочий код. Правило описывается через logic, а сама «магия» выносится в функцию.

Примеры не оставлены за кадром: в репозитории Annet лежит развесистая конфигурация для RouterOS — с туннелями, IPsec, GRE поверх IPsec и резервированием провайдеров. Под такую инфраструктуру написан работающий набор правил. Например, функция обработки IP-адресов выцепляет адрес и интерфейс, при отсутствии маски подставляет дефолтную (/32 или /64 для IPv6), добавляет кавычки и формирует команду удаления либо по адресу, либо по паре «адрес + интерфейс», включая случай интерфейса *.
  • Склейка блочных команд.
    Синтаксис RouterOS блочный: diff разбит по блокам, как при обычном экспорте. Но в патче команды приходится склеивать, потому что у блоков ip и ipv6 отличается только «макушка». Ядро Annet при виде двух одинаковых строк вырезало дубликат — а в firewall правило вида «разрешить established/related на forward и input» вполне закономерно встречается и для IPv4, и для IPv6. Решение: в diff блоковая структура сохраняется для удобства чтения человеком, а в патче строки склеиваются, как в export verbose.
  • Firewall.
    Firewall — последовательный набор правил, аналог классического ACL, и порядок правил важен. Вырезать правило из середины и вставить в нужную позицию дорого: вычисление позиции — сложная задача. Поэтому подход простой: при появлении diff в firewall ruleset удаляется целиком и накатывается заново. Процедура выглядит опасной, но она безопасна при правильной архитектуре: если основное описано в фильтре, а специфика вынесена в address-list и interface-list, сам ruleset меняется редко. На практике при смене провайдера (а на роутере их два-три) меняются адреса, маршрутизация, route rules, IPsec — но не ruleset firewall, который остаётся близким к дефолтному MikroTik с небольшой спецификой. Связанность при этом не теряется: IPsec продолжает работать через второго оператора, и конфигурацию можно применить.
  • diff_logic.
    Ещё более неочевидный, но полезный инструмент. Пример: провайдер подключён по DHCP, настройки приходят от оператора, а в DHCP-клиенте отрабатывает скрипт, динамически создающий правила. Все такие правила помечаются комментарием, а простая функция для diff_logic вырезает их из diff. Настройки самого скрипта при этом контролируются: изменения в скрипте применятся. Без этого Annet сравнил бы динамические адреса и шлюзы с источником истины, не нашёл бы их там и решил, что настройки нужно поменять, — заруинив связность.
  • order.
    Порядок применения команд задаётся отдельным файлом сортировки. Инженер указывает, в какой последовательности безопасно применять команды на конкретном вендоре: например, из MikroTik-бриджа сначала удалить компоненты (VLAN'ы и порты), затем сам бридж, а затем собрать обратно. То же касается развесистой конфигурации IPsec с множеством компонентов. Патч не обязан повторять структуру экспорта — этим можно управлять.

Практика эксплуатации

Разграничение прав. Разные команды отвечают за разные домены: сети дата-центров, офисные сети, Wi-Fi. Разграничение переложено на политики системы контроля версий — раз инфраструктура описана кодом, всё лежит в VCS (git или, как в Яндексе, Arc). Отдельный файл политик описывает, какая команда отвечает за какой генератор. Роли прорастают из общей IDM-системы, а коммиты проходят через ревью. Есть и общие файлы — например, для свитча в дата-центре без динамической маршрутизации: изменения в такой файл уходят на ревью команде DC. Раскатка возможна только после коммита.

Безопасность раскатки. Тестирование идёт на проде, но на канареечных группах: сначала одно устройство, затем пара, затем десяток. При проблеме — откат на предыдущий коммит и раскатка предыдущей версии, так же по канареечным группам. Это возможно потому, что инфраструктура зарезервирована на других уровнях и падение одного устройства не ломает ничего глобально.

Как не потерять железку.

Команды сгруппированы в отдельные генераторы: один для маршрутизации, другой для IP-адресов, третий для правил firewall. Их можно применять по отдельности и в нужной последовательности — например, сначала раскатать IP-адреса, а затем менять шлюз. Дополнительно можно подложить соломки в самом инвентаре, заведя запасные адреса для возврата на устройство. Это зона ответственности инженера: думать о том, как не потерять железку, нужно и при ручном применении конфигурации.

Safe mode RouterOS сознательно не используется: он может навредить сильнее, чем помочь.

Порог внедрения. Ориентировочная оценка: примерно от сотни роутеров вложение в такую систему уже окупается — особенно если за ними стоят точки доступа. При этом сам Annet спокойно живёт на одной виртуалке. К этому моменту в компании обычно уже есть отдельный инвентарь и система мониторинга — одного inventory-файла из Ansible недостаточно.
Финал
Annet — это робот с человеческим лицом, точнее, с человеческими способностями. Работа идёт через CLI, а значит, нужно понять специфику CLI конкретного вендора и подстроиться под неё — инструменты для этого есть.
Killer feature: конфигурация остаётся в порядке даже после того, как в неё залезали руками и что-то чинили. А если diff показывает, что что-то не так, это повод задуматься — возможно, стоит модифицировать генератор и привести систему к консистентному состоянию.
logic и diff_logic — довольно мощные инструменты, а Annet можно научить работать с самыми разными интерфейсами, включая такой специфичный, как у RouterOS. Наработки по RouterOS перенесены из внутренних репозиториев в open source, и ставка на open-source-версию продукта усиливается: всё больше кастомизаций будет видно наружу, при этом останется механизм переопределения логики под собственные задачи.

Роботы выполняют рутину лучше, чем люди. Но их надо этому научить.
В Москве:
РФ (звонок бесплатный):
Наша почта:
GetNet
Остались вопросы?
Группа компаний VoxLink © 2011-2026