mikrotik-wiki.ru
Главная
Загрузка...

Docker-контейнеры на RouterOS 7 — запуск сервисов на роутере

RouterOS 7.xSystem8 мин530 мар. 2026 г.
TelegramVK

Начиная с RouterOS 7.4, MikroTik поддерживает запуск Docker-контейнеров непосредственно на маршрутизаторе. Это позволяет развернуть дополнительные сервисы — DNS-фильтрацию, мониторинг, reverse proxy — без отдельного сервера. В этом руководстве разберём требования, настройку контейнерного окружения, создание сетевых интерфейсов и запуск практических примеров.

Описание

Что такое контейнеры на RouterOS

Контейнеры на RouterOS — это полноценная поддержка OCI-совместимых (Docker) образов, интегрированная в систему. Маршрутизатор скачивает Docker-образ из Docker Hub или другого registry, создаёт контейнер и запускает его в изолированном окружении.

Требования

ТребованиеОписание
RouterOS версия7.4 и выше (рекомендуется 7.12+ для стабильности)
АрхитектураARM, ARM64 или x86. Образ контейнера должен соответствовать архитектуре маршрутизатора
Оперативная памятьМинимум 256 МБ свободной RAM (рекомендуется 1 ГБ+)
ХранилищеВнешний USB-накопитель или встроенный NAND достаточного объёма
УстройстваRB5009, CCR2004, CCR2116, CHR или другие устройства с достаточными ресурсами

Не рекомендуется запускать контейнеры на устройствах с 64-128 МБ RAM (hAP lite, hEX lite) — ресурсов недостаточно для стабильной работы.

Ограничения

  • Нет docker-compose — каждый контейнер настраивается отдельно
  • Нет GPU — невозможно использовать аппаратное ускорение
  • Ограниченные ресурсы — маршрутизатор не сервер, тяжёлые приложения работать не будут
  • Один registry за раз — по умолчанию Docker Hub, можно сменить
  • Нет автообновления — обновление образа выполняется вручную
  • Перезапуск — при перезагрузке маршрутизатора контейнеры запускаются заново (не возобновляются)

Настройка

Шаг 1: Включение режима контейнеров

Контейнеры отключены по умолчанию из соображений безопасности. Для включения необходимо активировать device-mode:

[admin@MikroTik] >
/system/device-mode/update container=yes

После выполнения этой команды маршрутизатор потребует физическое подтверждение — нажатие кнопки reset на устройстве или перезагрузку. Это защита от удалённого включения контейнеров злоумышленником.

[admin@MikroTik] >
# После нажатия reset или перезагрузки проверяем
/system/device-mode/print
# container: yes

Для CHR (Cloud Hosted Router) физическое подтверждение не требуется — контейнеры включаются сразу после перезагрузки.

Шаг 2: Настройка хранилища

Контейнеры и их данные занимают место. Рекомендуется использовать внешний USB-накопитель:

[admin@MikroTik] >
# Проверяем доступные диски
/disk print

# Форматируем USB-накопитель (если нужно)
/disk/format-drive usb1 file-system=ext4 label=containers

# Указываем директорию для контейнеров
/container/config set ram-high=512M tmpdir=usb1/tmp

Параметр ram-high ограничивает максимальное потребление RAM всеми контейнерами.

Если внешнего накопителя нет, контейнеры будут использовать встроенное хранилище. Убедитесь, что свободного места достаточно:

[admin@MikroTik] >
/system/resource print
# Смотрите поле free-hdd-space

Шаг 3: Настройка сети для контейнеров

Контейнеры подключаются к сети через виртуальные Ethernet-интерфейсы (veth). Каждый контейнер получает свой veth, который добавляется в bridge.

Создание veth-интерфейса:

[admin@MikroTik] >
/interface/veth add name=veth-pihole \
  address=172.17.0.2/24 \
  gateway=172.17.0.1 \
  comment="Pi-hole container"

Создание bridge для контейнеров:

[admin@MikroTik] >
/interface/bridge add name=bridge-containers \
  comment="Bridge for Docker containers"

/ip/address add address=172.17.0.1/24 interface=bridge-containers

Добавление veth в bridge:

[admin@MikroTik] >
/interface/bridge/port add bridge=bridge-containers interface=veth-pihole

NAT для выхода контейнеров в интернет:

[admin@MikroTik] >
/ip/firewall/nat add chain=srcnat \
  src-address=172.17.0.0/24 \
  action=masquerade \
  comment="NAT for containers"

Шаг 4: Настройка DNS для контейнеров

Контейнерам нужен DNS для загрузки обновлений и работы сервисов:

[admin@MikroTik] >
/container/config set registry-url=https://registry-1.docker.io \
  envdir=usb1/container-env \
  ram-high=512M

Шаг 5: Настройка переменных окружения

Переменные окружения передаются контейнеру через файлы в специальной директории. Каждый envdir содержит файл env, где переменные записаны в формате KEY=VALUE.

[admin@MikroTik] >
# Создание envdir для Pi-hole
/container/envs add name=pihole-envs key=TZ value="Europe/Moscow"
/container/envs add name=pihole-envs key=WEBPASSWORD value="PiholeAdmin2024"
/container/envs add name=pihole-envs key=DNSMASQ_LISTENING value="all"
/container/envs add name=pihole-envs key=PIHOLE_DNS_ value="8.8.8.8;1.1.1.1"

Пример 1: Pi-hole — блокировка рекламы

Pi-hole — DNS-сервер с фильтрацией рекламных и вредоносных доменов. Запуск на маршрутизаторе позволяет блокировать рекламу для всех устройств в сети без установки расширений в браузеры.

Создание veth (если не создан ранее):

[admin@MikroTik] >
/interface/veth add name=veth-pihole \
  address=172.17.0.2/24 \
  gateway=172.17.0.1

/interface/bridge/port add bridge=bridge-containers interface=veth-pihole

Создание mount для сохранения данных:

[admin@MikroTik] >
/container/mounts add name=pihole-data \
  src=usb1/pihole/etc-pihole \
  dst=/etc/pihole

/container/mounts add name=pihole-dnsmasq \
  src=usb1/pihole/etc-dnsmasq.d \
  dst=/etc/dnsmasq.d

Загрузка и создание контейнера:

[admin@MikroTik] >
/container add remote-image=pihole/pihole:latest \
  interface=veth-pihole \
  root-dir=usb1/pihole-root \
  envlist=pihole-envs \
  mounts=pihole-data,pihole-dnsmasq \
  hostname=pihole \
  start-on-boot=yes \
  logging=yes \
  comment="Pi-hole DNS ad blocker"

Загрузка образа займёт несколько минут в зависимости от скорости интернета. Следите за прогрессом:

[admin@MikroTik] >
/container print
# Статус изменится с "pulling" на "stopped", затем можно запустить

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

[admin@MikroTik] >
/container start [find comment="Pi-hole DNS ad blocker"]

Перенаправление DNS-запросов на Pi-hole:

[admin@MikroTik] >
# Все DNS-запросы из LAN перенаправляются на Pi-hole
/ip/firewall/nat add chain=dstnat \
  protocol=udp dst-port=53 \
  src-address=192.168.1.0/24 \
  action=dst-nat to-addresses=172.17.0.2 to-ports=53 \
  comment="Redirect DNS to Pi-hole"

/ip/firewall/nat add chain=dstnat \
  protocol=tcp dst-port=53 \
  src-address=192.168.1.0/24 \
  action=dst-nat to-addresses=172.17.0.2 to-ports=53 \
  comment="Redirect DNS TCP to Pi-hole"

Веб-интерфейс Pi-hole будет доступен по адресу http://172.17.0.2/admin. Для доступа из LAN добавьте DST-NAT или статический маршрут.

Пример 2: Nginx reverse proxy

Nginx может выступать как reverse proxy для доступа к внутренним сервисам через один внешний IP.

Создание veth:

[admin@MikroTik] >
/interface/veth add name=veth-nginx \
  address=172.17.0.3/24 \
  gateway=172.17.0.1

/interface/bridge/port add bridge=bridge-containers interface=veth-nginx

Подготовка конфигурации Nginx:

Создайте файл конфигурации на USB-накопителе. Загрузите его через FTP/SFTP или Winbox (Files):

Файл usb1/nginx/conf.d/default.conf:

code
server {
    listen 80;
    server_name service1.example.com;

    location / {
        proxy_pass http://192.168.1.100:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

server {
    listen 80;
    server_name service2.example.com;

    location / {
        proxy_pass http://192.168.1.101:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Создание mount и контейнера:

[admin@MikroTik] >
/container/mounts add name=nginx-conf \
  src=usb1/nginx/conf.d \
  dst=/etc/nginx/conf.d

/container add remote-image=nginx:alpine \
  interface=veth-nginx \
  root-dir=usb1/nginx-root \
  mounts=nginx-conf \
  hostname=nginx \
  start-on-boot=yes \
  logging=yes \
  comment="Nginx reverse proxy"

Port forwarding на Nginx:

[admin@MikroTik] >
/ip/firewall/nat add chain=dstnat \
  protocol=tcp dst-port=80 \
  in-interface-list=WAN \
  action=dst-nat to-addresses=172.17.0.3 to-ports=80 \
  comment="Forward HTTP to Nginx"

/ip/firewall/nat add chain=dstnat \
  protocol=tcp dst-port=443 \
  in-interface-list=WAN \
  action=dst-nat to-addresses=172.17.0.3 to-ports=443 \
  comment="Forward HTTPS to Nginx"

Управление контейнерами

Основные команды управления:

[admin@MikroTik] >
# Список контейнеров
/container print

# Запуск контейнера
/container start 0

# Остановка контейнера
/container stop 0

# Просмотр логов контейнера
/log print where topics~"container"

# Удаление контейнера
/container stop 0
/container remove 0

# Выполнение команды внутри контейнера (shell)
/container/shell 0

Проверка

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

[admin@MikroTik] >
/container print

Возможные статусы:

СтатусОписание
pullingЗагрузка образа из registry
extractingРаспаковка образа
stoppedКонтейнер остановлен
runningКонтейнер работает
errorОшибка при запуске

Проверка сетевой связности

[admin@MikroTik] >
# Ping контейнера с маршрутизатора
/ping 172.17.0.2 count=5

# Проверка порта
/tool/fetch url="http://172.17.0.2/admin" mode=http dst-path=test.html
/file/remove test.html

Проверка потребления ресурсов

[admin@MikroTik] >
# Общая информация о ресурсах
/system/resource print

# Использование диска
/disk print

# Информация о контейнере
/container print detail

Проверка логов контейнера

[admin@MikroTik] >
/log print where topics~"container"

Для подробного логирования:

[admin@MikroTik] >
/system/logging add topics=container action=memory

Проверка DNS-фильтрации Pi-hole

[admin@MikroTik] >
# Запрос к Pi-hole напрямую
/tool/dns-lookup name=ads.google.com server=172.17.0.2

# Если Pi-hole работает корректно, рекламные домены
# вернут 0.0.0.0

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

Типичные ошибки

1. Контейнер не запускается: «error — could not pull image»

Причина: нет доступа к Docker Hub, DNS не резолвит адрес registry, или архитектура образа не соответствует устройству.

Решение:

[admin@MikroTik] >
# Проверьте DNS
/ip/dns print
/tool/dns-lookup name=registry-1.docker.io

# Проверьте интернет-доступ
/ping 8.8.8.8 count=3

# Проверьте архитектуру
/system/resource print
# Поле architecture-name покажет: arm, arm64, x86 и т.д.

# Убедитесь, что образ поддерживает вашу архитектуру
# Например, pihole/pihole:latest поддерживает arm64 и amd64

2. Контейнер запускается, но нет сети

Причина: veth не добавлен в bridge, нет IP-адреса или нет NAT.

Решение:

[admin@MikroTik] >
# Проверьте veth
/interface/veth print

# Проверьте bridge port
/interface/bridge/port print where interface~"veth"

# Проверьте IP на bridge
/ip/address print where interface=bridge-containers

# Проверьте NAT
/ip/firewall/nat print where comment~"container"

# Проверьте, что bridge-containers имеет связность
/ping 172.17.0.2 count=3

3. Ошибка «not enough disk space»

Причина: Docker-образы занимают от 50 МБ до нескольких ГБ. Встроенного хранилища может не хватить.

Решение:

[admin@MikroTik] >
# Проверьте свободное место
/system/resource print

# Используйте внешний USB-накопитель
/disk print

# Выбирайте минимальные образы (alpine-варианты)
# Вместо nginx:latest используйте nginx:alpine
# Вместо pihole/pihole:latest можно использовать образы на Alpine

4. Контейнер «device-mode» не включается

Причина: не выполнено физическое подтверждение (нажатие reset).

Решение:

[admin@MikroTik] >
# Проверьте текущий статус
/system/device-mode/print

# Если container=no, выполните
/system/device-mode/update container=yes

# Затем в течение нескольких минут нажмите кнопку reset на устройстве
# ИЛИ перезагрузите маршрутизатор
/system/reboot

На устройствах с кнопкой reset достаточно кратковременного нажатия (не удержания, чтобы не сбросить конфигурацию).

5. Данные контейнера теряются после перезапуска

Причина: не настроены mounts. Без них данные хранятся в overlay-файловой системе контейнера и удаляются при пересоздании.

Решение: всегда используйте mounts для persistent data:

[admin@MikroTik] >
# Создайте mount для каждой директории с данными
/container/mounts add name=app-data \
  src=usb1/app/data \
  dst=/app/data

# Пересоздайте контейнер с mount
/container stop 0
/container remove 0
/container add remote-image=image:tag \
  interface=veth-app \
  root-dir=usb1/app-root \
  mounts=app-data \
  start-on-boot=yes

6. Высокое потребление CPU/RAM контейнером

Причина: контейнерное приложение потребляет больше ресурсов, чем маршрутизатор может предоставить.

Решение:

[admin@MikroTik] >
# Ограничьте RAM для контейнеров
/container/config set ram-high=256M

# Мониторьте ресурсы
/system/resource print

# Если CPU постоянно выше 80%, остановите контейнер
/container stop 0

Рассмотрите использование более лёгких альтернатив:

  • Вместо полноценного Pi-hole — AdGuard Home (меньше потребление)
  • Вместо nginx — caddy (проще конфигурация, меньше памяти)
  • Используйте образы на базе Alpine Linux

Рекомендации

  1. Используйте внешний USB для хранилища контейнеров — это продлит жизнь встроенного NAND
  2. Ограничивайте ram-high — контейнер не должен забирать RAM у основных функций маршрутизатора
  3. Выбирайте alpine-образы — они значительно меньше по размеру
  4. Настраивайте start-on-boot=yes для критических сервисов
  5. Регулярно обновляйте образы — удаляйте контейнер и создавайте заново с новым образом
  6. Мониторьте ресурсы — контейнеры не должны влиять на производительность маршрутизации

Контейнеры на RouterOS — мощная функция, которая превращает маршрутизатор в мини-сервер. Однако помните: основная задача маршрутизатора — маршрутизация. Не перегружайте его контейнерами. Для серьёзных сервисов используйте выделенный сервер, а на маршрутизаторе запускайте только лёгкие вспомогательные контейнеры.

[admin@MikroTik] >
/system/device-mode/update container=yes
# После нажатия reset или перезагрузки проверяем
/system/device-mode/print
# container: yes
# Проверяем доступные диски
/disk print

# Форматируем USB-накопитель (если нужно)
/disk/format-drive usb1 file-system=ext4 label=containers

# Указываем директорию для контейнеров
/container/config set ram-high=512M tmpdir=usb1/tmp
/system/resource print
# Смотрите поле free-hdd-space
/interface/veth add name=veth-pihole \
  address=172.17.0.2/24 \
  gateway=172.17.0.1 \
  comment="Pi-hole container"
/interface/bridge add name=bridge-containers \
  comment="Bridge for Docker containers"

/ip/address add address=172.17.0.1/24 interface=bridge-containers
/interface/bridge/port add bridge=bridge-containers interface=veth-pihole
/ip/firewall/nat add chain=srcnat \
  src-address=172.17.0.0/24 \
  action=masquerade \
  comment="NAT for containers"
/container/config set registry-url=https://registry-1.docker.io \
  envdir=usb1/container-env \
  ram-high=512M
# Создание envdir для Pi-hole
/container/envs add name=pihole-envs key=TZ value="Europe/Moscow"
/container/envs add name=pihole-envs key=WEBPASSWORD value="PiholeAdmin2024"
/container/envs add name=pihole-envs key=DNSMASQ_LISTENING value="all"
/container/envs add name=pihole-envs key=PIHOLE_DNS_ value="8.8.8.8;1.1.1.1"
/interface/veth add name=veth-pihole \
  address=172.17.0.2/24 \
  gateway=172.17.0.1

/interface/bridge/port add bridge=bridge-containers interface=veth-pihole
/container/mounts add name=pihole-data \
  src=usb1/pihole/etc-pihole \
  dst=/etc/pihole

/container/mounts add name=pihole-dnsmasq \
  src=usb1/pihole/etc-dnsmasq.d \
  dst=/etc/dnsmasq.d
/container add remote-image=pihole/pihole:latest \
  interface=veth-pihole \
  root-dir=usb1/pihole-root \
  envlist=pihole-envs \
  mounts=pihole-data,pihole-dnsmasq \
  hostname=pihole \
  start-on-boot=yes \
  logging=yes \
  comment="Pi-hole DNS ad blocker"
/container print
# Статус изменится с "pulling" на "stopped", затем можно запустить
/container start [find comment="Pi-hole DNS ad blocker"]
# Все DNS-запросы из LAN перенаправляются на Pi-hole
/ip/firewall/nat add chain=dstnat \
  protocol=udp dst-port=53 \
  src-address=192.168.1.0/24 \
  action=dst-nat to-addresses=172.17.0.2 to-ports=53 \
  comment="Redirect DNS to Pi-hole"

/ip/firewall/nat add chain=dstnat \
  protocol=tcp dst-port=53 \
  src-address=192.168.1.0/24 \
  action=dst-nat to-addresses=172.17.0.2 to-ports=53 \
  comment="Redirect DNS TCP to Pi-hole"
/interface/veth add name=veth-nginx \
  address=172.17.0.3/24 \
  gateway=172.17.0.1

/interface/bridge/port add bridge=bridge-containers interface=veth-nginx
server {
    listen 80;
    server_name service1.example.com;

    location / {
        proxy_pass http://192.168.1.100:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

server {
    listen 80;
    server_name service2.example.com;

    location / {
        proxy_pass http://192.168.1.101:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
/container/mounts add name=nginx-conf \
  src=usb1/nginx/conf.d \
  dst=/etc/nginx/conf.d

/container add remote-image=nginx:alpine \
  interface=veth-nginx \
  root-dir=usb1/nginx-root \
  mounts=nginx-conf \
  hostname=nginx \
  start-on-boot=yes \
  logging=yes \
  comment="Nginx reverse proxy"
/ip/firewall/nat add chain=dstnat \
  protocol=tcp dst-port=80 \
  in-interface-list=WAN \
  action=dst-nat to-addresses=172.17.0.3 to-ports=80 \
  comment="Forward HTTP to Nginx"

/ip/firewall/nat add chain=dstnat \
  protocol=tcp dst-port=443 \
  in-interface-list=WAN \
  action=dst-nat to-addresses=172.17.0.3 to-ports=443 \
  comment="Forward HTTPS to Nginx"
# Список контейнеров
/container print

# Запуск контейнера
/container start 0

# Остановка контейнера
/container stop 0

# Просмотр логов контейнера
/log print where topics~"container"

# Удаление контейнера
/container stop 0
/container remove 0

# Выполнение команды внутри контейнера (shell)
/container/shell 0
/container print
# Ping контейнера с маршрутизатора
/ping 172.17.0.2 count=5

# Проверка порта
/tool/fetch url="http://172.17.0.2/admin" mode=http dst-path=test.html
/file/remove test.html
# Общая информация о ресурсах
/system/resource print

# Использование диска
/disk print

# Информация о контейнере
/container print detail
/log print where topics~"container"
/system/logging add topics=container action=memory
# Запрос к Pi-hole напрямую
/tool/dns-lookup name=ads.google.com server=172.17.0.2

# Если Pi-hole работает корректно, рекламные домены
# вернут 0.0.0.0
# Проверьте DNS
/ip/dns print
/tool/dns-lookup name=registry-1.docker.io

# Проверьте интернет-доступ
/ping 8.8.8.8 count=3

# Проверьте архитектуру
/system/resource print
# Поле architecture-name покажет: arm, arm64, x86 и т.д.

# Убедитесь, что образ поддерживает вашу архитектуру
# Например, pihole/pihole:latest поддерживает arm64 и amd64
# Проверьте veth
/interface/veth print

# Проверьте bridge port
/interface/bridge/port print where interface~"veth"

# Проверьте IP на bridge
/ip/address print where interface=bridge-containers

# Проверьте NAT
/ip/firewall/nat print where comment~"container"

# Проверьте, что bridge-containers имеет связность
/ping 172.17.0.2 count=3
# Проверьте свободное место
/system/resource print

# Используйте внешний USB-накопитель
/disk print

# Выбирайте минимальные образы (alpine-варианты)
# Вместо nginx:latest используйте nginx:alpine
# Вместо pihole/pihole:latest можно использовать образы на Alpine
# Проверьте текущий статус
/system/device-mode/print

# Если container=no, выполните
/system/device-mode/update container=yes

# Затем в течение нескольких минут нажмите кнопку reset на устройстве
# ИЛИ перезагрузите маршрутизатор
/system/reboot
# Создайте mount для каждой директории с данными
/container/mounts add name=app-data \
  src=usb1/app/data \
  dst=/app/data

# Пересоздайте контейнер с mount
/container stop 0
/container remove 0
/container add remote-image=image:tag \
  interface=veth-app \
  root-dir=usb1/app-root \
  mounts=app-data \
  start-on-boot=yes
# Ограничьте RAM для контейнеров
/container/config set ram-high=256M

# Мониторьте ресурсы
/system/resource print

# Если CPU постоянно выше 80%, остановите контейнер
/container stop 0
System / Docker-контейнеры на RouterOS 7 — запуск сервисов на роутере