Docker на роутере MikroTik: как развернуть и не утонуть в багах

8ks39w0gz0n-8or4mmdjvmvvkq0.png


Привет, Хабр! Меня зовут Ярослав, я стажер инженерно-технического отдела в Selectel. В своих пет-проектах уже давно использую роутеры MikroTik. Но я никогда думал, что на них станет возможным развернуть Docker. Релиз стабильной версии RouterOS 7.5 изменил мое мнение: теперь MikroTik поддерживает контейнеризацию.

На примере Nextcloud показываю, как установить и настроить приложение в контейнере, и рассказываю, с какими ограничениями можно столкнуться. Подробности под катом.

Начнем с ограничений


Не каждый MikroTik поддерживает контейнеры


К сожалению, функционал поддерживается не на всех роутерах. Контейнер можно запустить только на устройстве с архитектурой ARM, ARM64 или x86. Из беспроводных роутеров можно использовать MikroTik линейки Chateau и некоторые hAP-модели. Из проводных — RB1100AHx4 Dude Edition, RB3011 и RB5009. А также — новые роутеры линейки CCR (CCR2004–16G-2S+, CCR2116–12G-4S+, CCR2216–1G-12XS-2XQ).

С полным списком моделей и их архитектурами можно ознакомиться тут.


Архитектуру x86 поддерживают программные роутеры CHR, которые могут быть установлены на сервер или виртуальную машину с соответствующим процессором.

Если у вас есть сервер, можно установить на него любую систему виртуализации создать несколько виртуальных машин. На одной из них — развернуть образ программного роутера CHR Mikrotik, а на другой — серверную операционную систему с Docker или нужным ПО.

В этом случае нет необходимости ставить контейнеры внутрь RouterOS. На мой взгляд этот способ является более стабильным и функциональным решением. Но есть одна особенность: установить контейнер RouterOS может быть быстрее, чем разворачивать систему виртуализации. К тому же она может потребовать дополнительного лицензирования.

Если вы знаете, для чего может понадобиться контейнеризации на CHR, поделитесь опытом в комментариях.


Контейнер ограничен характеристиками роутера


У аппаратных роутеров достаточно жесткие ограничения по оперативной памяти. Объем ОЗУ на роутерах, за исключением линейки CCR, не превышает 1 ГБ. И если, например, половину объема оставить под нужды RouterOS, контейнер с приложением будут сильно ограничены в памяти.

С ресурсами процессора ситуация не лучше. Для примера: приложение Nextcloud, которое я развернул на роутере RB3011, загрузило оба ядра на 100% — и это без какой-либо нагрузки.

dzgf0canoc5qfbxzrlrzqilrmoi.png


Окно Resources, состояние процессорных ядер.

Также можно столкнуться с ограничениями по объему памяти флеш-накопителя. Его вместимость не превышает 128 МБ, за исключением накопителя в роутере RB5009. Поэтому память лучше оставить исключительно для хранения конфигураций. А для работы контейнера и хранения примонтированных каталогов использовать внешний накопитель.

Некоторые модели имеют SATA- и M.2-разъемы для подключения внешних накопителей. Если таких разъемов нет, можно воспользоваться USB и подключить флешку.

Риски использования


Немаловажна и безопасность: нужно понимать, что, если роутер будет скомпрометирован, злоумышленники могут загрузить любое вредоносное ПО в контейнере. Это может привести к чему угодно, если роутер включен в домашнюю или корпоративную сеть.

Подробнее со всеми рисками можно ознакомиться на официальном сайте.


MikroTik снимает с себя ответственность за безопасность RouterOS с установленными контейнерами. Поэтому нужно быть уверенным, что используемое ПО не содержит уязвимостей.

1k7bto4ll6kmlckzsvnaox4oupc.png


Подготовка роутера к установке контейнеров


Я уже говорил, что к аппаратному роутеру нужно подключить дополнительный накопитель. Кроме того, нужно обновить систему RouterOS до stable-версии 7.5 или выше, а потом — RouterBOARD. Но это не все, что понадобится.

Каждый из последующих этапов можно выполнить через графический интерфейс RouterOS или командную строку.


Форматирование диска


Предварительно нужно отформатировать накопитель для работы с файловой системой ext3/ext4: нужно выбрать новый накопитель и нажать Format Drive.

kwkh3hmbpjk8i40ukeu1relfrem.png


Окно Format Drive, настройка форматирования диска.

/disk/print 

Flags: M, r - RAID-MEMBER; p - PARTITION
Columns: SLOT, MODEL, SERIAL, INTERFACE, NAME
#    SLOT        MODEL                         SERIAL                INTERFACE         NAME 
0    usb1        JetFlash Mass Storage Device  CCYYMMDDHHmmSSECGXE8  USB 2.10 480Mbps       
1 Mp usb1-part1
     
/disk/format-drive usb1 file-system=ext4


Настройка форматирования диска.
usb1 — имя накопителя, полученное командой /disk/print

Установка дополнительного пакета для работы с контейнерами


На официальном сайте в разделе Software нужно найти блок с архитектурой процессора используемого роутера. А после — скачать архив Extra packages. В нем должен быть файл container, который нужно переместить в Winbox, в окно File.

wq7kjug0pgh6lvcmnbixbfjb-z0.png


Содержание архива Extra packages.

upxi_kw9u1qno0nfqzewnes1ezm.png


Файловая система Winbox.

Для установки пакета необходимо перезагрузить роутер.

Активация функционала контейнеров


Последний этап подготовки — активация функционала контейнеров. В терминале RouterOS нужно ввести специальную команду.

/system/device-mode/update container=yes
update: please activate by turning power off or pressing reset or mode button in 4m53s
-- [Q quit|D dump|C-z pause]


После сообщения нужно в течение 5 минут перезагрузить роутер, то есть выключить и включить его по питанию, либо нажать на кнопку reset или mode.

Установка образа контейнера с Docker Hub


Создание виртуального сетевого интерфейса


В разделе Interface → VETH нужно создать виртуальный сетевой интерфейс для будущего контейнера. Для этого нужно настроить несколько параметров:

  • Name — название сетевого интерфейса,
  • Address — IP-адрес и битовая маска подсети для контейнера. По данному адресу можно будет подключиться к контейнеру,
  • Gateway — IP-адрес, который контейнер будет использовать в качестве шлюза для работы с устройствами в других подсетях.
u8tmjumbuwlfdcd-jvelitfgwdi.png


Окно VETH, создание виртуального сетевого интерфейса.

/interface/veth/add name=veth3 address=10.10.4.4/24 gateway=10.10.4.1


Создание виртуального сетевого интерфейса VETH.

Для включения контейнера в сеть можно создать «виртуальный коммутатор» bridge, назначить ему IP-адрес и добавить в него виртуальный интерфейс.

/interface/bridge/add name=container-bridge
/ip/address/add address=10.10.4.1/24 interface=container-bridge
/interface/bridge/port/add bridge=container-bridge interface=veth3


Создание виртуального коммутатора для контейнеров и его настройка.

На самом деле, в bridge добавлять интерфейс не обязательно — его можно использовать отдельно, настроив, например, соединение point-to-point.

/interface/veth/add name=veth4 address=10.10.5.2/30 gateway=10.10.5.1
/ip/address/add address=10.10.5.1/30 interface=veth4


Назначение IP-адресов на PtP-интерфейс.

Я заметил особенность поведения RouterOS: при смене IP для виртуального сетевого интерфейса VETH, внутри самого контейнера адрес не обновляется. По поводу этой проблемы я создал тему на форуме MikroTik.


Конфигурирование контейнера


Далее нужно перейти в раздел Container → Config и настроить несколько параметров:

  • RAM Hight — опциональный параметр, ограничивает контейнеры в потреблении оперативной памяти,
  • Registry URL — адрес, с которого будет устанавливаться контейнер при запуске (для загрузки образа с Docker Hub нужно ввести registry-1.docker.io),
  • Tmp dir — путь до директории, куда будут перемещены временные файлы, необходимые для установки контейнера. Рекомендую располагать директорию на дополнительном накопителе (disk2).
jnvqrkjyl9jw4gsymj92imezipy.png


Окно Config, конфигурирование контейнера.

/container/config/set ram-high=768M registry-url=https://registry-1.docker.io tmpdir=disk2/tmp


Конфигурирование контейнера через консоль.

Особенности конфигурирования


Во время работы с Container → Config нужно учитывать ряд особенностей:

  1. При заполнении RAM High через Winbox неочевидно, в каких единицах нужно вводить значение. Нельзя использовать упрощенную модель — например, 768M, когда буква обозначает единицу измерения (килобайты, мегабайты, гигабайты). Объем необходимо указывать в байтах. Хотя в терминале подобная запись работает.
  2. При установке контейнера в RouterOS все приложения из каталога монтирования — например, Nextcloud (/var/www/html) — отображаются сплошным списком, без соблюдения иерархии директорий. Это сильно затормаживает загрузку раздела File и вызывает неудобства в использовании. Например, после установки контейнера с Nextcloud в разделе File появляется около 46 000 строк, которые загружаются больше минуты.
    g2aep8gebrq2ipc4a9psa0nxc0s.png

  3. Вторая особенность вызывает неудобства и в работе с терминалом. Когда в системе содержится большое количество файлов, при настройке конфигурации контейнеров RouterOS не дает ввести путь до директории для временных файлов (tmpdir). Возможно, это происходит из-за долгой индексации файлов во время проверки системой вводимых команд.
Возможно, эти тексты тоже вас заинтересуют:

→ Домашний дата-центр: ошибки, результаты и советы
→ ML в Managed Kubernetes: для каких задач нужен кластер с GPU
→ Docker Swarm VS Kubernetes — как бизнес выбирает оркестраторы


Настройка и запуск контейнера с Nextcloud


После подготовки роутера можно создать и настроить контейнер с приложением.

Создание переменных для управления контейнером


Для управления будущим контейнером нужно создать специальные переменные. Они будут «пробрасываться» внутрь него и подгружать значения, например, в конфигурационных файлах.

Таких переменных может быть очень много. Поэтому их принято группировать. Для этого нужно перейти во вкладку Evns и заполнить форму из нескольких полей:

  • Name — название группы переменных,
  • Key — ключ,
  • Value — значение ключа.
e8j9pcqgdff_43nmfb4iqscwq_8.png


Окно Env, добавление переменных.

/container/envs/add name=nextcloud_evns key=APACHE_LOG_DIR value=/var/log/httpd


Команда для добавления переменных

Группы переменных понадобятся во время создания контейнера.

Настройка каталога монтирования Nextcloud


В RouterOS есть вкладка Mounts — аналог атрибута --mount, который нужен для создания каталогов монтирования в традиционном Docker. С помощью Mounts можно сопоставить директории, находящиеся в файловой системе MikroTik, и директории, находящиеся внутри контейнера.

Это нужно сделать для тех директорий, которые важно не потерять в случае перезагрузки контейнера. В моем случае нужно было создать точку монтирования для директории Nextcloud (/var/www/html).

Чтобы это сделать, нужно указать специальные параметры:

  • Name — уникальное имя точки монтирования. Оно понадобится при создании контейнера,
  • Scr — путь к директории, находящейся на внешнем накопителе, которую необходимо смонтировать,
  • Dst — путь к директории назначения внутри контейнера.
ixei2va8ilidfbcwwa4grst691a.png


Окно Mount, добавление каталога монтирования.

/container/mounts/add name=nextcloud_html src=disk2/nextcloud_html dst=/var/www/html


Запуск контейнера


Наконец, можно создать и запустить контейнер. Для этого нужно перейти во вкладку Container и заполнить следующие поля:

  • Remote Image — название образа контейнера, который будет установлен (в моем случае с Docker Hub),
  • Interface — VETH-интерфейс для использования с контейнером,
  • Envlist — список переменных среды, настроенных в Container → Envs, которые будут использоваться контейнером,
  • Root Dir — директория, в которую будет установлен контейнер,
  • Mounts — точки монтирования, настроенные в Container → Mounts.
fy53mictwedpqaljegivcnbp96q.png


Окно Container, финальная настройка и запуск.

/container add remote-image=arm32v7/nextcloud:latest envlist=nextcloud_envs hostname=nextcloud interface=veth1 mounts=nextcloud_html root-dir=disk2/nextcloud


Команда для создания контейнера.

После можно запустить контейнер нажатием на кнопку Start. Или с помощью специальной команды.

/container/start number=1

/container/print


Запуск Nextcloud в Docker-контейнере.
1 — номер контейнера, который можно узнать командой /container/print

jlstdjzlbaaglkqem0ui_xchq8m.png


Стартовое окно Nextcloud.

Изначально в RouterOS 7.5 функция автозапуска контейнеров после перезагрузки роутера отсутствовала. В версии 7.6 такая возможность появилась, но она все еще недоступна для настройки через Winbox.

Если контейнер уже создан, добавить его в автозагрузку можно специальной командной через терминал.

/container/set 1 start-on-boot=yes

1 — номер контейнера

Если вы только создаете контейнер, то в команде нужно прописать специальный параметр.

start-on-boot=yes


Первые настройки всегда «комом»


В большинстве случаев контейнер запустить с первого раза не получится. Настройки, как блины, первый раз получаются «комом». Чтобы узнать, в каком месте допущена ошибка, вывод информации (исключений и ошибок) нужно транслировать из контейнера в log роутера.

Достаточно поставить галочку рядом с Logging.

aadhtnk9jmrg4x_prjy6_mwowha.png


Окно Container, включение логирования сообщений. В консоли для этого нужно выполнить команду /container/set 1 logging=yes

Или вручную подключиться к работающей оболочке контейнера. Для этого нужно ввести команду и номер контейнера.

[admin@R1] > /container/shell 1
root@wireguard:/# ls
bin   data  etc             home  media  opt   root  sbin  start.sh  tmp  var          web-vault
boot  dev   healthcheck.sh  lib   mnt    proc  run   srv   sys       usr  vaultwarden
root@wireguard:/# whoami
root
root@wireguard:/# exit
exit
done


Подключение к командной строке внутри контейнера, внутри которой можно выполнять любые команды (Is, whoami).

Оба способа помогут оперативно отловить «фичу» и прокричать «Ура, я запустил Docker на MikroTik!». Но оправдана ли радость?

Зачем вообще нужен контейнер на MikroTik?


Контейнеризация в MikroTik может быть полезна для решения нетребовательных задач, для которых не нужно поднимать отдельные серверы.

Вот несколько возможных сценариев использования «домашних контейнеров»:

  • Организация облачного файлового хранилища. Тут важно отметить, что лучше использовать приложения «попроще». Nextcloud слишком нагружает роутер.
  • Развертывание менеджера паролей. Повторюсь: лучше использовать менее нагрузочное ПО. Например, в качестве менеджера паролей вместо bitwarden можно установить его аналог — vaultwarden. Но помните: ответственность за безопасность паролей остается за вами.
  • Запуск полноценного DNS-сервера. Благодаря контейнерам на роутерах MikroTik стало возможным поднимать полноценные DNS-серверы и делегировать им управление доменами. Это можно сделать с помощью установки BIND 9. Именно этим я займусь во время апгрейда своего домашнего дата-центра, о котором можно почитать в блоге Selectel.


Область применения контейнеров на RouterOS ограничивается лишь вашей фантазией и… «железом» роутеров.

Из-за ресурсных ограничений контейнеры на MikroTik подходят не всегда. Для развертывания высоконагруженных сервисов лучше воспользоваться полноценным сервисом — например, Managed Kubernetes.

А какое приложение на MikroTik запустили бы вы? Поделитесь своим мнением в комментариях.

© Habrahabr.ru