Массовое управление устройствами MikroTik через RouterOS API: заметки об архитектуре с реальных проектов
Архитектура централизованного и автономного управления сотнями и тысячами устройств MikroTik через RouterOS API: бинарный API librouteros, мост asyncio, очередь задач Redis, идемпотентный push конфигурации, circuit breaker и различия v6/v7. С уроками, извлечёнными при создании собственной платформы автоматизации.
Архитектура централизованного и автономного управления сотнями и тысячами устройств MikroTik через RouterOS API: бинарный API librouteros, мост asyncio, очередь задач Redis, идемпотентный push конфигурации, circuit breaker и различия v6/v7. С уроками, извлечёнными при создании собственной платформы автоматизации.
İçindekiler▾
- Способы программного управления RouterOS: API, SSH и REST
- Отправка команды сотням устройств одновременно: архитектура очереди задач
- Как затащить синхронную библиотеку в асинхронный мир: мост asyncio.to_thread
- Самая коварная ловушка API: разница между «print» и «action»
- Почему /export отсутствует в API и почему приходится падать на SSH
- Безопасное массовое изменение: desired state → diff → идемпотентная команда → проверка
- Различия RouterOS v6 и v7: место, где автоматизация расходует больше всего кода
- Учётные данные и аудит: безопасность на масштабе
- А насколько велик этот масштаб на самом деле?
- Строить самому или отдать на управление?
Короткий ответ: десятки устройств можно вести вручную по одному; на сотнях или тысячах устройств это становится невозможным. Правильный путь на масштабе состоит в том, чтобы построить автоматизацию на базе RouterOS API, работающую со структурированными данными, опирающуюся на очередь задач и идемпотентную. Эта статья рассказывает об архитектурных решениях и подводных камнях, которые мы усвоили на практике, разрабатывая собственную платформу централизованного управления MikroTik именно под эту задачу: почему бинарный API, почему очередь задач, как безопасно выполнять push конфигурации и каковы реальные краевые случаи RouterOS, усложняющие автоматизацию.
Это не рекламный материал о продукте; это дорожная карта для инженеров, которые будут строить похожую систему, и ответ на вопрос «что стоит за этим» для организаций, задумывающихся о передаче управления инфраструктурой MikroTik на аутсорс. Если вы только начинаете знакомство с MikroTik, рекомендуем сначала прочитать руководство «Что такое MikroTik».
Способы программного управления RouterOS: API, SSH и REST
Автоматизировать RouterOS извне можно тремя путями; на масштабе выбор очевиден:
- Бинарный API (8728 / api-ssl 8729): собственный двоичный протокол RouterOS. Команды и возвращаемые записи структурированы: то есть вы получаете данные из меню вроде
interface,ip address,firewall filterв виде пар «поле-значение», не парся текст. Это и есть правильный уровень для массового управления. - REST API (v7, HTTP/HTTPS): появился в RouterOS 7, возвращает JSON. Практичен для простых интеграций; мы выбрали бинарный API, потому что нам нужно было поддерживать и устройства v6, и оставаться в рамках единой абстракции клиента (REST есть только в v7).
- SSH: самый гибкий, но и самый хрупкий путь: вывод представляет собой свободный текст, меняется от версии к версии, парсить его хлопотно. SSH мы держим только для узких задач, которые API не покрывает (см. раздел про
/exportниже).
Наше решение: основным методом мы выбрали бинарный API, а SSH оставили как вторичный и узкоспециальный. На стороне Python мы делаем это через библиотеку librouteros; это зрелый клиент, корректно реализующий протокол и берущий на себя процедуру логина бинарного API.
Отправка команды сотням устройств одновременно: архитектура очереди задач
Самая частая ошибка это рефлекс «если тысяча устройств, открою тысячу соединений разом». Это быстро кладёт на лопатки один сервер и сетевой стек; к тому же одно медленное устройство задерживает весь процесс. Работающий на масштабе паттерн иной:
- Fan-out: когда запускается массовая операция (например, «сделать резервную копию всех устройств»), для каждого устройства создаётся отдельная задача.
- Приоритетная очередь: эти задачи пишутся в очередь Redis. Разные типы задач держатся с разными приоритетами: срочный reconcile обгоняет рутинное сканирование мониторинга.
- Горизонтальное масштабирование worker’ов: очередь параллельно разбирают множество независимых друг от друга worker-процессов. Повышение степени параллелизма достигается не ускорением одного огромного цикла, а увеличением числа реплик worker’ов. Это делает систему естественно горизонтально масштабируемой в Docker/Kubernetes.
У этой архитектуры три критических гарантии:
- Надёжная очередь (ACK/NACK): взятая задача помечается как «в обработке». Если worker падает, задача через определённое время автоматически возвращается в очередь, и ни одно устройство не пропускается молча.
- Распределённая блокировка на каждое устройство: для каждого устройства в Redis берётся блокировка (
lock:device:<id>). Так два worker’а не смогут одновременно писать конфигурацию на один и тот же MikroTik. Если блокировку взять не удалось, задача повторяется с коротким экспоненциальным backoff (5 → 10 → 20 → 40 с). - Circuit breaker: каждый раз впустую пытаться подключиться к выключенному или недоступному устройству это расточительство и времени, и очереди. После определённого числа (у нас 3) подряд идущих ошибок соединения «цепь размыкается» для этого устройства, и в течение периода остывания (5 мин) попытки не предпринимаются. Когда устройство возвращается, цепь автоматически замыкается.
Честная оговорка: не всякая массовая задача является «настоящим fan-out». Например, health-check тысяч устройств можно поместить в очередь как одну задачу и последовательно перебрать внутри worker’а; это просто, но серийно. Настоящий параллелизм возникает, когда вы дробите работу на каждое устройство. Что будет fan-out, а что серийным, это осознанное проектное решение.
Такое централизованное управление обретает смысл вместе со слоем мониторинга; инвентарь мы также подключаем к стороне мониторинга сети через Zabbix. Для многофилиальных структур и структур ISP-типа руководство по управлению сетью ISP служит дополняющим чтением.
Как затащить синхронную библиотеку в асинхронный мир: мост asyncio.to_thread
librouteros это синхронная библиотека: когда вы отправляете команду, она блокируется до прихода ответа. Наши же worker’ы построены на asyncio. Смешать эти две вещи в чистом виде означает, что одно медленное устройство заблокирует весь event loop, а значит, и все устройства, которые обрабатывает этот worker.
Решение состоит в том, чтобы вынести каждый вызов I/O к устройству в отдельный поток:
# Выполнить синхронный вызов librouteros, не блокируя event loop
api = await asyncio.to_thread(librouteros.connect, host=ip, username=user,
password=pw, port=8728, timeout=10)
data = await asyncio.to_thread(lambda: tuple(api.path("interface")))
Этот с виду небольшой мост критичен на масштабе: соединение, чтение, команда. Каждый шаг общения с устройством находится внутри to_thread. Иначе система выглядит «асинхронной», но на практике течёт со скоростью одного устройства.
Примечание: в языках вроде Go одновременный доступ к тысячам устройств естественнее строить на горутинах. Мы остались на Python, потому что остальная часть платформы (FastAPI, модель данных, привычность команды) на Python, и компенсировали это данным мостом. Выбор языка это не вопрос «правильно-неправильно», а решение в контексте.
Самая коварная ловушка API: разница между «print» и «action»
В RouterOS API прочитать меню и отправить в него действие это разные вызовы, и именно это чаще всего ловит новичка в автоматизации.
- Итерация по
api.path("interface")под капотом выполняет/interface/print, то есть читает. - Но команды вроде
reboot,upgrade,backup saveтак отправить нельзя; для них нужен отдельный вызов, выполняющий команду напрямую (вродеapi(cmd="/system/reboot")).
Не зная этой разницы, часами гадаешь «почему reboot не работает». В нашем коде это различие помечено комментарием в начале каждой функции-действия, чтобы через полгода не попасться в ту же ловушку.
Связанный факт: разрыв соединения после reboot это нормально. Пока устройство перезагружается, сессия API естественным образом обрывается; это исключение нужно не считать ошибкой, а проглатывать (и записывать как «устройство перезагружено»).
Почему /export отсутствует в API и почему приходится падать на SSH
Классический способ получить полный и читаемый дамп конфигурации MikroTik это команда /export. Но бинарный API не возвращает /export. Это была одна из самых осязаемых стен, о которые мы бились при построении автоматизации.
Есть два решения, и мы используем оба:
- SSH для настоящего
/export: когда нужен дословный дамп конфигурации (например, для аудита или архива), мы открываем SSH через paramiko и получаем вывод/export. Это точный пример принципа «держи SSH только для узких задач». - «Псевдо-export» из API: читать меню раздел за разделом и генерировать RSC-подобный текст. Не требует SSH, но не так полон, как
/export.
Урок: бинарный API мощен, но покрывает не всё; зрелая автоматизация должна уметь чисто переключаться на SSH там, где заканчивается API.
Безопасное массовое изменение: desired state → diff → идемпотентная команда → проверка
Массовое изменение конфигурации не обязано быть пугающим; пугает слепое изменение. Наш цикл reconcile (согласования) проходит через следующие шаги:
- Desired state: должное состояние устройства генерируется из YAML-шаблона (NTP, SNMP, базовый firewall, пользователи управления и т. д.).
- Actual state: текущая конфигурация считывается с устройства через API.
- Diff: два состояния сравниваются раздел за разделом; вычисляется только разница (drift).
- Предварительная резервная копия: перед применением изменения делается резервная копия конфигурации устройства как гарантия отката.
- Идемпотентное применение: команды генерируются по логике «если есть, не трогать; если нет, добавить» (
add-if-missing), «найти и обновить» (set-by-find). Даже если один и тот же reconcile выполнится дважды, результат не изменится. - Проверка: устройство считывается заново, подтверждается, что drift обнулился.
Практическая ценность идемпотентности такова: если reconcile прервался из-за сбоя сети, паники нет: повторный запуск задачи, не повторяя уже применённых шагов, довершит недостающее. Частичный успех также явно помечается как partial; даже если одна команда упадёт, остальные продолжают пробоваться, а результат честно рапортуется.
Эта дисциплина является единственным устойчивым способом держать правила firewall (межсетевого экрана), конфигурацию VLAN или настройки централизованного беспроводного доступа (CAPsMAN) согласованными на сотнях устройств.
Различия RouterOS v6 и v7: место, где автоматизация расходует больше всего кода
Управлять устройствами и RouterOS 6, и 7 одним шаблоном команд невозможно; различия версий вынуждены быть встроены внутрь автоматизации. С чем мы сталкивались на практике чаще всего:
| Тема | RouterOS v6 | RouterOS v7 |
|---|---|---|
| BGP | /routing/bgp/peer |
/routing/bgp/connection |
| NTP | primary-ntp / secondary-ntp (отдельные поля) |
servers= (список через запятую) |
| Фильтрация bridge VLAN | Ограниченная / незрелая | Полностью поддерживается |
| WireGuard | Нет | Есть (появился в v7) |
Практический подход: подключившись к устройству, сначала прочитайте версию RouterOS, определите мажорную версию и разветвляйте генерацию команд соответственно. Fallback’и типа «попробуй путь v7, не вышло, падай на путь v6» неизбежны. Это слой, раздувающий код, но незаменимый на практике. Если вы рассматриваете переход между версиями как услугу, на странице MikroTik Support мы отдельно касаемся перехода RouterOS 6→7.
Учётные данные и аудит: безопасность на масштабе
Система, держащая доступ не к одному, а к сотням устройств, при утечке становится куда более ценной целью. Минимальные линии, которых мы держимся:
- Пароли хранятся зашифрованными: пароли устройств лежат в базе данных не в открытом виде, а как ciphertext с симметричным шифрованием (Fernet); ключ хранится в переменной окружения и никогда не попадает в репозиторий. Пароль расшифровывается в памяти только в момент, когда worker собирается подключиться к устройству. (Честная оговорка: это не HashiCorp Vault / KMS, а решение на базе env: безопасность держится на одном ключе, и это зона для дозревания.)
- Аудит-лог: каждая задача записывается с информацией «кто запустил» (
created_by: пользователь / scheduler / автоматически). Каждое действие над устройством (сделана резервная копия, reconcile применён/провалился, обнаружен reboot) пишется в отдельную таблицу событий с детализацией «кто-что-когда». - Наименьшие привилегии: на стороне приложения есть ролевой доступ (viewer по умолчанию, операции управления требуют admin) и мультиарендность на основе групп. На стороне устройства SNMP community, добавляемое автоматизацией, делается только для чтения (
read-access=yes, write-access=no). (Сужение же привилегий пользователей управления на стороне устройства остаётся областью, которую мы постоянно улучшаем; честно говоря, здесь идеал «наименьших привилегий» даётся непросто.)
А насколько велик этот масштаб на самом деле?
Мы проектировали платформу с прицелом на 50 000+ устройств; архитектуру (очередь, горизонтальные worker’ы, распределённая блокировка, circuit breaker) выстраивали так, чтобы она выдержала эту величину. Здесь важно быть честными: 50 000 это не доказанная в бою цифра, а проектная цель. То, что архитектура размерена под этот масштаб, и то, что она фактически эксплуатировалась на нём, не одно и то же; второе подтверждается лишь реальной нагрузкой.
Практический вывод для вас таков: на 10-20 устройствах достаточно ручного управления или простых скриптов. Когда вы переходите к 100+ устройствам, к множеству филиалов или в позицию сервис-провайдера, управляющего MikroTik для своих клиентов, вышеописанная архитектура (структурированный API + очередь задач + идемпотентный reconcile + аудит) становится не «роскошью», а предпосылкой устойчивости.
Строить самому или отдать на управление?
Всё в этой статье реализуемо и может быть построено на инструментах с открытым исходным кодом (Python, librouteros, Redis, PostgreSQL). Но нужно видеть честную картину: различия v6/v7, идемпотентность, надёжная очередь, circuit breaker и безопасное управление учётными данными складываются в серьёзную инженерную инвестицию, и её сопровождение непрерывно.
Если вы будете строить со своей командой, эта статья даст вам реалистичную дорожную карту и список ловушек. Если же вы не хотите нести эту нагрузку, централизованное и поддающееся аудиту управление множеством MikroTik можно получить как услугу от команд вроде нашей: на это смотрят наши страницы Сетевая инфраструктура и MikroTik Support. В обоих случаях ключевой принцип один: управляйте своими устройствами не вручную, а воспроизводимой и проверяемой системой.
Kaynaklar
- librouteros: Python-клиент для RouterOS API — PyPI / librouteros (2026)
- Официальная документация RouterOS API — MikroTik (2026)
- Официальная документация MikroTik RouterOS — MikroTik (2026)
Sıkça Sorulan Sorular
RouterOS API или SSH: что использовать?+
Для массового и программного управления бинарный API RouterOS (8728/8729) гораздо удобнее SSH: он возвращает структурированные данные, вам не нужно парсить вывод команд как текст, а идемпотентные операции 'add/set/find' поддерживаются напрямую. SSH мы держим только для узких задач, которые API не покрывает; самый типичный пример это получение вывода `/export`, у которого нет эквивалента в API.
Какой порт использует RouterOS API?+
Незашифрованный API работает на порту 8728, а API с TLS (api-ssl) на порту 8729. При управлении из интернета следует использовать только 8729 (api-ssl) и ограничивать доступ доверенными источниками; обычный 8728 разумен только в защищённой/внутренней сети управления. Сервис API включается в разделе `/ip service` и ограничивается фильтром по адресу.
Как отправить команду на сотни MikroTik одновременно?+
Правильный подход на масштабе состоит в следующем: не открывать тысячи одновременных соединений в одном процессе, а создавать для каждого устройства отдельную 'задачу', помещать их в очередь (мы используем Redis) и позволять множеству worker'ов параллельно разбирать очередь. Так параллелизм горизонтально масштабируется числом worker'ов, одно медленное устройство не блокирует систему, а благодаря отдельной блокировке на каждое устройство два изменения на одном устройстве не конфликтуют.
Безопасно ли массовое изменение конфигурации?+
При правильной организации ответ положительный. Наш процесс таков: сгенерировать желаемое состояние (desired state) из шаблона, сравнить его с фактическим состоянием (actual state), считанным с устройства (diff), перед применением изменений сделать резервную копию конфигурации, применить команды идемпотентно (если есть, не трогать; если нет, добавить), затем считать заново и убедиться, что drift обнулился. Благодаря идемпотентности прерванную на середине операцию можно безопасно запустить повторно.
Одинаков ли API RouterOS v6 и v7?+
Нет, есть важные различия, и именно здесь автоматизация расходует больше всего кода. Например, BGP в v7 находится под `/routing/bgp/connection`, а в v6 под `/routing/bgp/peer`; настройка NTP в v7 задаётся через `servers=` списком через запятую, а в v6 используются отдельные поля `primary-ntp`/`secondary-ntp`; фильтрация bridge VLAN стала зрелой в v7. Автоматизация должна считывать версию RouterOS устройства и генерировать команду соответственно.
Profesyonel Destek mi Lazım?
Bu konuda yardıma ihtiyacın varsa yanındayız. Kurulum, konfigürasyon ve sorun giderme için ulaş.
