Docker-контейнеры на MikroTik RouterOS 7 — продвинутые сценарии
Базовый запуск контейнера на MikroTik — лишь начало. В реальных проектах нужны изолированные сети, проброс портов, монтирование томов, переменные окружения и грамотное управление ресурсами. В этом руководстве разберём продвинутые сценарии использования контейнеров на RouterOS 7.20+: от тонкой настройки networking до мониторинга потребления CPU и RAM, работы с NFS-хранилищами и обновления образов без потери данных.
Описание
Зачем продвинутые сценарии
Контейнеры на маршрутизаторе решают конкретные задачи: DNS-фильтрация, reverse proxy, мониторинг, лёгкие веб-сервисы. Однако стандартная настройка «один контейнер — один veth — один bridge» быстро упирается в ограничения:
- несколько контейнеров конкурируют за ресурсы — нужен контроль RAM и CPU;
- контейнер теряет данные при перезагрузке — нужны persistent-тома;
- сервис должен быть доступен из WAN — нужен NAT и firewall;
- образ устарел — нужна процедура обновления без даунтайма;
- логи и метрики — нужен мониторинг состояния.
Требования
| Требование | Минимум | Рекомендуется |
|---|---|---|
| RouterOS | 7.4+ | 7.20+ |
| Архитектура | ARM64 или x86 | ARM64 (RB5009, CCR2004) или x86 (CHR) |
| Оперативная память | 256 МБ свободной | 1 ГБ+ свободной |
| Хранилище | 512 МБ на USB или встроенный NAND | 4 ГБ+ USB/NVMe |
| Устройства | RB5009, CCR2004, CCR2116, CHR | RB5009UPr+S+, CCR2116-12G-4S+ |
Внимание: устройства с 64–128 МБ RAM (hAP lite, hEX lite, mAP lite) не подходят для контейнеров. Даже если RouterOS позволит включить container mode, стабильная работа невозможна.
Архитектурные ограничения
Контейнеры на RouterOS — это не полноценный Docker Engine. Важно понимать границы:
| Функция | Docker Engine | RouterOS Containers |
|---|---|---|
| docker-compose | Да | Нет |
| Multi-container networking | Да | Ограниченно (вручную через bridge) |
| GPU | Да | Нет |
| Volumes | Полная поддержка | Bind mounts через /container/mounts |
| Health checks | Да | Нет (скрипты вручную) |
| Auto-restart | Да (restart policies) | start-on-boot=yes |
| Registry | Несколько одновременно | Один активный |
| Image layers cache | Да | Ограниченно |
Когда использовать контейнеры на роутере, а когда — отдельный сервер
Контейнер на роутере подходит, если:
- сервис лёгкий (DNS-фильтр, DDNS-клиент, простой веб-сервер);
- нет отдельного сервера или Mini-PC;
- нужен сервис, тесно связанный с сетью (Proxy, DoH resolver);
- один-два контейнера с суммарным потреблением до 512 МБ RAM.
Отдельный сервер предпочтительнее, если:
- нужна база данных, Nextcloud, Plex, Home Assistant;
- нужно больше 2–3 контейнеров;
- сервис потребляет более 512 МБ RAM;
- нужны docker-compose, оркестрация, CI/CD.
Настройка
Шаг 1: Включение container mode
Если container mode ещё не активирован:
[admin@MikroTik] >/system/device-mode/update container=yes
Маршрутизатор потребует физическое подтверждение — нажмите кнопку reset на устройстве или выполните перезагрузку. Для CHR физическое подтверждение не требуется.
[admin@MikroTik] ># Проверяем после перезагрузки /system/device-mode/print
В выводе должно быть container: yes.
Шаг 2: Подготовка хранилища
USB-накопитель
Рекомендуемый вариант — внешний USB-накопитель с файловой системой ext4:
[admin@MikroTik] ># Просмотр доступных дисков /disk/print # Форматирование USB (уничтожит все данные!) /disk/format-drive usb1 file-system=ext4 label=containers # Настройка директории для контейнеров /container/config/set ram-high=768M tmpdir=usb1/tmp
Параметр ram-high задаёт мягкий лимит RAM для всех контейнеров. При превышении система начинает агрессивно освобождать память. Жёсткого лимита (OOM kill) по умолчанию нет — его можно задать через ram-high на уровне отдельного контейнера.
NFS-хранилище
Для более серьёзных сценариев можно подключить NFS-шару с NAS:
[admin@MikroTik] ># Создание точки монтирования для NFS /container/mounts/add name=nfs-data src=/mnt/nfs/containers dst=/data
При этом NFS-шара должна быть предварительно смонтирована на уровне системы (через SMB/CIFS или NFS — зависит от модели и прошивки). На практике проще использовать локальный USB-накопитель, а NFS — для бэкапа данных контейнеров.
Шаг 3: Создание сетевой инфраструктуры для контейнеров
Правильная сетевая архитектура — ключ к стабильной работе нескольких контейнеров. Создадим выделенную подсеть.
Создание bridge для контейнеров
[admin@MikroTik] ># Отдельный bridge для контейнерной подсети /interface/bridge/add name=bridge-containers comment="Container network" # IP-адрес на bridge — шлюз для контейнеров /ip/address/add address=172.17.0.1/24 interface=bridge-containers comment="Container gateway"
Создание veth-интерфейсов
Каждый контейнер получает свой виртуальный Ethernet-интерфейс (veth). Один конец veth подключается к контейнеру, другой — к bridge:
[admin@MikroTik] ># veth для первого контейнера (например, Nginx) /interface/veth/add name=veth-nginx address=172.17.0.10/24 gateway=172.17.0.1 comment="Nginx container" # veth для второго контейнера (например, скрипт) /interface/veth/add name=veth-script address=172.17.0.11/24 gateway=172.17.0.1 comment="Custom script" # veth для третьего контейнера /interface/veth/add name=veth-monitor address=172.17.0.12/24 gateway=172.17.0.1 comment="Monitoring"
Добавление veth в bridge
[admin@MikroTik] >/interface/bridge/port/add bridge=bridge-containers interface=veth-nginx /interface/bridge/port/add bridge=bridge-containers interface=veth-script /interface/bridge/port/add bridge=bridge-containers interface=veth-monitor
NAT для доступа контейнеров в интернет
Контейнерам нужен доступ наружу — для скачивания обновлений, списков фильтров и т.д.:
[admin@MikroTik] ># Masquerade для контейнерной подсети /ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.17.0.0/24 out-interface-list=WAN comment="Container NAT"
Проброс портов из WAN в контейнер
Если контейнер должен быть доступен извне (например, веб-сервер):
[admin@MikroTik] ># Проброс порта 8080 из WAN в Nginx-контейнер /ip/firewall/nat/add chain=dstnat action=dst-nat to-addresses=172.17.0.10 to-ports=80 protocol=tcp dst-port=8080 in-interface-list=WAN comment="Forward 8080 to Nginx"
DNS для контейнеров
Контейнерам нужен DNS. Можно указать DNS-серверы в переменных окружения контейнера или настроить MikroTik как DNS-resolver для контейнерной подсети:
[admin@MikroTik] ># Разрешаем DNS-запросы из контейнерной подсети /ip/dns/set allow-remote-requests=yes
Шаг 4: Переменные окружения
Многие контейнеры настраиваются через environment variables. В RouterOS для этого есть отдельная сущность:
[admin@MikroTik] ># Создание набора переменных для Nginx /container/envs/add name=nginx-env key=TZ value="Europe/Moscow" /container/envs/add name=nginx-env key=NGINX_HOST value="router.local" /container/envs/add name=nginx-env key=NGINX_PORT value="80"
Все переменные с одинаковым name объединяются в один набор и передаются контейнеру при создании.
Шаг 5: Точки монтирования (mounts)
Bind mounts позволяют контейнеру читать и писать файлы на хост-системе:
[admin@MikroTik] ># Монтирование директории для конфигурации Nginx /container/mounts/add name=nginx-config src=usb1/nginx/conf dst=/etc/nginx/conf.d # Монтирование директории для статических файлов /container/mounts/add name=nginx-html src=usb1/nginx/html dst=/usr/share/nginx/html # Монтирование для логов /container/mounts/add name=nginx-logs src=usb1/nginx/logs dst=/var/log/nginx
Параметры:
src— путь на маршрутизаторе (относительно корня файловой системы);dst— путь внутри контейнера.
Создайте директории на USB заранее:
[admin@MikroTik] >/file/mkdir usb1/nginx /file/mkdir usb1/nginx/conf /file/mkdir usb1/nginx/html /file/mkdir usb1/nginx/logs
Шаг 6: Создание и запуск контейнеров
Пример 1: Nginx веб-сервер
[admin@MikroTik] ># Настройка registry (Docker Hub по умолчанию) /container/config/set registry-url=https://registry-1.docker.io tmpdir=usb1/tmp # Создание контейнера Nginx /container/add remote-image=library/nginx:alpine interface=veth-nginx root-dir=usb1/nginx-root envlist=nginx-env mounts=nginx-config,nginx-html,nginx-logs start-on-boot=yes hostname=nginx logging=yes comment="Nginx web server"
Параметры команды /container/add:
| Параметр | Описание |
|---|---|
remote-image | Образ из Docker Hub (формат: library/имя:тег) |
interface | veth-интерфейс для контейнера |
root-dir | Директория для корневой ФС контейнера |
envlist | Набор переменных окружения |
mounts | Список точек монтирования через запятую |
start-on-boot | Автозапуск при загрузке маршрутизатора |
hostname | Имя хоста внутри контейнера |
logging | Запись логов контейнера в лог RouterOS |
Скачивание образа может занять несколько минут в зависимости от скорости интернета. Следите за статусом:
[admin@MikroTik] >/container/print
Статусы контейнера:
extracting— распаковка образа;stopped— готов к запуску;running— работает;error— ошибка (смотрите лог).
[admin@MikroTik] ># Запуск контейнера (после скачивания) /container/start 0
Пример 2: Пользовательский скрипт на Python
Создадим контейнер для запуска собственного Python-скрипта, который, например, отправляет уведомления в Telegram:
[admin@MikroTik] ># Переменные окружения /container/envs/add name=script-env key=TZ value="Europe/Moscow" /container/envs/add name=script-env key=BOT_TOKEN value="123456:ABC-DEF" /container/envs/add name=script-env key=CHAT_ID value="-100123456789" # Монтирование директории со скриптами /container/mounts/add name=script-data src=usb1/scripts dst=/app/data # Создание контейнера /container/add remote-image=library/python:3.12-alpine interface=veth-script root-dir=usb1/python-root envlist=script-env mounts=script-data start-on-boot=yes hostname=script cmd="python /app/data/main.py" logging=yes comment="Custom Python script"
Параметр cmd переопределяет команду запуска контейнера. Скрипт main.py должен лежать в usb1/scripts/ на маршрутизаторе.
Шаг 7: Управление контейнерами
Полный набор команд управления:
[admin@MikroTik] ># Список всех контейнеров /container/print # Подробная информация о контейнере /container/print detail where name~"nginx" # Запуск контейнера по номеру /container/start 0 # Остановка контейнера /container/stop 0 # Удаление контейнера (должен быть остановлен) /container/remove 0 # Просмотр логов контейнера /log/print where topics~"container" # Выполнение команды внутри контейнера (shell) /container/shell 0
При использовании /container/shell вы попадаете внутрь контейнера. Для выхода нажмите Ctrl+D или введите exit.
Шаг 8: Мониторинг ресурсов
Общие ресурсы системы
[admin@MikroTik] ># Текущая загрузка CPU и RAM /system/resource/print # Мониторинг в реальном времени (обновление каждую секунду) /system/resource/monitor
Ресурсы контейнеров
[admin@MikroTik] ># Просмотр потребления RAM контейнерами /container/print detail
В выводе обратите внимание на поля:
status— текущий статус;arch— архитектура образа.
Скрипт для мониторинга
Создадим скрипт, который проверяет доступность контейнера и перезапускает его при падении:
[admin@MikroTik] >/system/script/add name=container-watchdog source={ :local containerName "nginx" :local containerID 0 :local status [/container/get $containerID status] :if ($status != "running") do={ :log warning ("Container $containerName is $status, restarting...") /container/start $containerID :delay 5s :local newStatus [/container/get $containerID status] :if ($newStatus = "running") do={ :log info ("Container $containerName restarted successfully") } else={ :log error ("Container $containerName failed to restart: $newStatus") } } } # Запуск скрипта по расписанию каждые 5 минут /system/scheduler/add name=container-watchdog interval=5m on-event="/system/script/run container-watchdog"
Шаг 9: Обновление образов
RouterOS не поддерживает автоматическое обновление контейнеров. Процедура обновления вручную:
[admin@MikroTik] ># 1. Остановка контейнера /container/stop 0 # 2. Удаление контейнера (данные в mounts сохранятся!) /container/remove 0 # 3. Создание контейнера с тем же образом (скачается latest) /container/add remote-image=library/nginx:alpine interface=veth-nginx root-dir=usb1/nginx-root envlist=nginx-env mounts=nginx-config,nginx-html,nginx-logs start-on-boot=yes hostname=nginx logging=yes # 4. Ожидание скачивания и запуск # Проверяем статус /container/print # 5. Запуск /container/start 0
Ключевой момент: данные в точках монтирования (mounts) сохраняются при удалении контейнера. Удаляется только корневая ФС контейнера (root-dir). Поэтому конфигурации и данные нужно хранить именно в mounts.
Шаг 10: Несколько контейнеров — лучшие практики
При запуске 2–3 контейнеров одновременно:
[admin@MikroTik] ># Ограничение RAM для каждого контейнера /container/config/set ram-high=1024M # Убедитесь, что каждый контейнер использует свой: # - veth-интерфейс с уникальным IP # - root-dir (отдельная директория) # - набор mounts (не пересекаются) # Проверка всей контейнерной инфраструктуры /interface/veth/print /interface/bridge/port/print where bridge=bridge-containers /container/envs/print /container/mounts/print /container/print
Проверка
Проверка сетевой связности
[admin@MikroTik] ># Ping контейнера с маршрутизатора /ping 172.17.0.10 count=4 # Ping интернета из контейнера (через shell) /container/shell 0 # Внутри контейнера: # ping 8.8.8.8 # exit # Проверка NAT-правил /ip/firewall/nat/print where comment~"Container" # Проверка проброса портов /ip/firewall/nat/print where comment~"Nginx"
Проверка работы контейнера
[admin@MikroTik] ># Статус всех контейнеров /container/print # Логи контейнера /log/print where topics~"container" # Проверка veth-интерфейсов /interface/veth/print /interface/print where type=veth # Проверка bridge-портов /interface/bridge/port/print where bridge=bridge-containers
Проверка веб-сервера (Nginx)
[admin@MikroTik] ># HTTP-запрос к контейнеру с маршрутизатора /tool/fetch url="http://172.17.0.10" mode=http dst-path=test.html # Просмотр результата /file/print where name=test.html
Проверка потребления ресурсов
[admin@MikroTik] ># Общие ресурсы /system/resource/print # Свободное место на USB /disk/print # Список файлов контейнера /file/print where name~"usb1/nginx"
Типичные ошибки
Ошибка 1: «container: no» после перезагрузки
Симптом: после перезагрузки container mode не активирован.
Причина: не было физического подтверждения (нажатие кнопки reset).
Решение:
[admin@MikroTik] ># Повторно активируем /system/device-mode/update container=yes # Нажмите кнопку reset на устройстве в течение 60 секунд
На CHR физическое подтверждение не требуется — достаточно перезагрузки.
Ошибка 2: Контейнер не скачивается — «error» в статусе
Симптом: после /container/add статус навсегда extracting или сразу error.
Причина: нет доступа к Docker Hub, неправильный registry URL, нет DNS.
Решение:
[admin@MikroTik] ># Проверяем DNS /ip/dns/print /ping registry-1.docker.io count=4 # Проверяем registry URL /container/config/print # registry-url должен быть https://registry-1.docker.io # Исправляем при необходимости /container/config/set registry-url=https://registry-1.docker.io # Проверяем NAT (маршрутизатор сам должен иметь доступ в интернет) /ping 8.8.8.8 count=4
Ошибка 3: Несовпадение архитектуры образа
Симптом: контейнер скачивается, но не запускается — error в статусе.
Причина: образ собран для другой архитектуры (например, amd64 на ARM-устройстве).
Решение:
[admin@MikroTik] ># Проверяем архитектуру устройства /system/resource/print # Ищем поле architecture-name: arm64 / x86 / arm # Используйте образ, соответствующий архитектуре # Для ARM64 устройств: образ должен поддерживать arm64/aarch64 # Многие популярные образы (nginx:alpine, pihole) — мультиархитектурные
Ошибка 4: «not enough disk space»
Симптом: ошибка при скачивании образа.
Причина: недостаточно места на диске (встроенный NAND или USB).
Решение:
[admin@MikroTik] ># Проверяем место /system/resource/print /disk/print # Очищаем старые контейнеры /container/stop 0 /container/remove 0 # Удаляем директорию старого контейнера /file/remove usb1/old-container-root
Ошибка 5: Контейнер не получает сетевой доступ
Симптом: контейнер запущен, но не может выйти в интернет и не пингуется.
Причина: veth не добавлен в bridge, отсутствует NAT-правило, неправильная адресация.
Решение:
[admin@MikroTik] ># Проверяем veth /interface/veth/print # Убедитесь, что address и gateway заданы корректно # Проверяем bridge /interface/bridge/port/print where bridge=bridge-containers # veth должен быть в списке портов # Проверяем IP на bridge /ip/address/print where interface=bridge-containers # Должен быть 172.17.0.1/24 # Проверяем NAT /ip/firewall/nat/print where comment~"Container" # Должно быть правило masquerade для 172.17.0.0/24
Ошибка 6: Контейнер не стартует после перезагрузки
Симптом: при start-on-boot=yes контейнер не запускается автоматически.
Причина: USB-накопитель монтируется позже, чем стартуют контейнеры.
Решение:
[admin@MikroTik] ># Добавьте задержку запуска через scheduler /system/scheduler/add name=delayed-container-start on-event="/container/start 0" start-time=startup interval=0 comment="Start container after boot"
Альтернативный вариант — использовать скрипт с проверкой доступности диска:
[admin@MikroTik] >/system/script/add name=start-containers-delayed source={ :delay 30s :if ([/disk/find where label="containers"] != "") do={ :foreach id in=[/container/find where status!=running] do={ /container/start $id :delay 5s } :log info "All containers started" } else={ :log error "USB disk not ready, containers not started" } } /system/scheduler/add name=start-containers on-event="/system/script/run start-containers-delayed" start-time=startup interval=0
Ошибка 7: Конфликт портов между контейнерами
Симптом: два контейнера пытаются слушать один и тот же порт.
Причина: контейнеры используют разные IP (veth), поэтому конфликта внутри нет. Но если два dst-nat правила пробрасывают один и тот же внешний порт — будет конфликт.
Решение:
[admin@MikroTik] ># Проверяем NAT-правила /ip/firewall/nat/print where chain=dstnat # Используйте разные внешние порты: # Nginx: WAN:8080 -> 172.17.0.10:80 # Другой сервис: WAN:8081 -> 172.17.0.11:80
Рекомендации по безопасности
Контейнеры на маршрутизаторе представляют дополнительный вектор атаки. Соблюдайте правила:
[admin@MikroTik] ># 1. Ограничьте доступ к контейнерам из WAN — только нужные порты /ip/firewall/filter/add chain=forward action=drop in-interface-list=WAN dst-address=172.17.0.0/24 comment="Block direct WAN access to containers" # Разрешите только конкретные порты ДО этого правила: /ip/firewall/filter/add chain=forward action=accept in-interface-list=WAN dst-address=172.17.0.10 dst-port=80 protocol=tcp comment="Allow HTTP to Nginx container" # 2. Ограничьте доступ контейнеров к управлению маршрутизатором /ip/firewall/filter/add chain=input action=drop src-address=172.17.0.0/24 dst-port=80,443,8291,22,23,8728,8729 protocol=tcp comment="Block container access to management" # 3. Регулярно обновляйте образы контейнеров # Используйте процедуру из Шага 9
Всегда используйте конкретные теги образов (например, nginx:1.27-alpine) вместо latest, чтобы контролировать версии и избежать неожиданных обновлений при пересоздании контейнера.
/system/device-mode/update container=yes
# Проверяем после перезагрузки
/system/device-mode/print
# Просмотр доступных дисков
/disk/print
# Форматирование USB (уничтожит все данные!)
/disk/format-drive usb1 file-system=ext4 label=containers
# Настройка директории для контейнеров
/container/config/set ram-high=768M tmpdir=usb1/tmp
# Создание точки монтирования для NFS
/container/mounts/add name=nfs-data src=/mnt/nfs/containers dst=/data
# Отдельный bridge для контейнерной подсети
/interface/bridge/add name=bridge-containers comment="Container network"
# IP-адрес на bridge — шлюз для контейнеров
/ip/address/add address=172.17.0.1/24 interface=bridge-containers comment="Container gateway"
# veth для первого контейнера (например, Nginx)
/interface/veth/add name=veth-nginx address=172.17.0.10/24 gateway=172.17.0.1 comment="Nginx container"
# veth для второго контейнера (например, скрипт)
/interface/veth/add name=veth-script address=172.17.0.11/24 gateway=172.17.0.1 comment="Custom script"
# veth для третьего контейнера
/interface/veth/add name=veth-monitor address=172.17.0.12/24 gateway=172.17.0.1 comment="Monitoring"
/interface/bridge/port/add bridge=bridge-containers interface=veth-nginx
/interface/bridge/port/add bridge=bridge-containers interface=veth-script
/interface/bridge/port/add bridge=bridge-containers interface=veth-monitor
# Masquerade для контейнерной подсети
/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.17.0.0/24 out-interface-list=WAN comment="Container NAT"
# Проброс порта 8080 из WAN в Nginx-контейнер
/ip/firewall/nat/add chain=dstnat action=dst-nat to-addresses=172.17.0.10 to-ports=80 protocol=tcp dst-port=8080 in-interface-list=WAN comment="Forward 8080 to Nginx"
# Разрешаем DNS-запросы из контейнерной подсети
/ip/dns/set allow-remote-requests=yes
# Создание набора переменных для Nginx
/container/envs/add name=nginx-env key=TZ value="Europe/Moscow"
/container/envs/add name=nginx-env key=NGINX_HOST value="router.local"
/container/envs/add name=nginx-env key=NGINX_PORT value="80"
# Монтирование директории для конфигурации Nginx
/container/mounts/add name=nginx-config src=usb1/nginx/conf dst=/etc/nginx/conf.d
# Монтирование директории для статических файлов
/container/mounts/add name=nginx-html src=usb1/nginx/html dst=/usr/share/nginx/html
# Монтирование для логов
/container/mounts/add name=nginx-logs src=usb1/nginx/logs dst=/var/log/nginx
/file/mkdir usb1/nginx
/file/mkdir usb1/nginx/conf
/file/mkdir usb1/nginx/html
/file/mkdir usb1/nginx/logs
# Настройка registry (Docker Hub по умолчанию)
/container/config/set registry-url=https://registry-1.docker.io tmpdir=usb1/tmp
# Создание контейнера Nginx
/container/add remote-image=library/nginx:alpine interface=veth-nginx root-dir=usb1/nginx-root envlist=nginx-env mounts=nginx-config,nginx-html,nginx-logs start-on-boot=yes hostname=nginx logging=yes comment="Nginx web server"
/container/print
# Запуск контейнера (после скачивания)
/container/start 0
# Переменные окружения
/container/envs/add name=script-env key=TZ value="Europe/Moscow"
/container/envs/add name=script-env key=BOT_TOKEN value="123456:ABC-DEF"
/container/envs/add name=script-env key=CHAT_ID value="-100123456789"
# Монтирование директории со скриптами
/container/mounts/add name=script-data src=usb1/scripts dst=/app/data
# Создание контейнера
/container/add remote-image=library/python:3.12-alpine interface=veth-script root-dir=usb1/python-root envlist=script-env mounts=script-data start-on-boot=yes hostname=script cmd="python /app/data/main.py" logging=yes comment="Custom Python script"
# Список всех контейнеров
/container/print
# Подробная информация о контейнере
/container/print detail where name~"nginx"
# Запуск контейнера по номеру
/container/start 0
# Остановка контейнера
/container/stop 0
# Удаление контейнера (должен быть остановлен)
/container/remove 0
# Просмотр логов контейнера
/log/print where topics~"container"
# Выполнение команды внутри контейнера (shell)
/container/shell 0
# Текущая загрузка CPU и RAM
/system/resource/print
# Мониторинг в реальном времени (обновление каждую секунду)
/system/resource/monitor
# Просмотр потребления RAM контейнерами
/container/print detail
/system/script/add name=container-watchdog source={
:local containerName "nginx"
:local containerID 0
:local status [/container/get $containerID status]
:if ($status != "running") do={
:log warning ("Container $containerName is $status, restarting...")
/container/start $containerID
:delay 5s
:local newStatus [/container/get $containerID status]
:if ($newStatus = "running") do={
:log info ("Container $containerName restarted successfully")
} else={
:log error ("Container $containerName failed to restart: $newStatus")
}
}
}
# Запуск скрипта по расписанию каждые 5 минут
/system/scheduler/add name=container-watchdog interval=5m on-event="/system/script/run container-watchdog"
# 1. Остановка контейнера
/container/stop 0
# 2. Удаление контейнера (данные в mounts сохранятся!)
/container/remove 0
# 3. Создание контейнера с тем же образом (скачается latest)
/container/add remote-image=library/nginx:alpine interface=veth-nginx root-dir=usb1/nginx-root envlist=nginx-env mounts=nginx-config,nginx-html,nginx-logs start-on-boot=yes hostname=nginx logging=yes
# 4. Ожидание скачивания и запуск
# Проверяем статус
/container/print
# 5. Запуск
/container/start 0
# Ограничение RAM для каждого контейнера
/container/config/set ram-high=1024M
# Убедитесь, что каждый контейнер использует свой:
# - veth-интерфейс с уникальным IP
# - root-dir (отдельная директория)
# - набор mounts (не пересекаются)
# Проверка всей контейнерной инфраструктуры
/interface/veth/print
/interface/bridge/port/print where bridge=bridge-containers
/container/envs/print
/container/mounts/print
/container/print
# Ping контейнера с маршрутизатора
/ping 172.17.0.10 count=4
# Ping интернета из контейнера (через shell)
/container/shell 0
# Внутри контейнера:
# ping 8.8.8.8
# exit
# Проверка NAT-правил
/ip/firewall/nat/print where comment~"Container"
# Проверка проброса портов
/ip/firewall/nat/print where comment~"Nginx"
# Статус всех контейнеров
/container/print
# Логи контейнера
/log/print where topics~"container"
# Проверка veth-интерфейсов
/interface/veth/print
/interface/print where type=veth
# Проверка bridge-портов
/interface/bridge/port/print where bridge=bridge-containers
# HTTP-запрос к контейнеру с маршрутизатора
/tool/fetch url="http://172.17.0.10" mode=http dst-path=test.html
# Просмотр результата
/file/print where name=test.html
# Общие ресурсы
/system/resource/print
# Свободное место на USB
/disk/print
# Список файлов контейнера
/file/print where name~"usb1/nginx"
# Повторно активируем
/system/device-mode/update container=yes
# Нажмите кнопку reset на устройстве в течение 60 секунд
# Проверяем DNS
/ip/dns/print
/ping registry-1.docker.io count=4
# Проверяем registry URL
/container/config/print
# registry-url должен быть https://registry-1.docker.io
# Исправляем при необходимости
/container/config/set registry-url=https://registry-1.docker.io
# Проверяем NAT (маршрутизатор сам должен иметь доступ в интернет)
/ping 8.8.8.8 count=4
# Проверяем архитектуру устройства
/system/resource/print
# Ищем поле architecture-name: arm64 / x86 / arm
# Используйте образ, соответствующий архитектуре
# Для ARM64 устройств: образ должен поддерживать arm64/aarch64
# Многие популярные образы (nginx:alpine, pihole) — мультиархитектурные
# Проверяем место
/system/resource/print
/disk/print
# Очищаем старые контейнеры
/container/stop 0
/container/remove 0
# Удаляем директорию старого контейнера
/file/remove usb1/old-container-root
# Проверяем veth
/interface/veth/print
# Убедитесь, что address и gateway заданы корректно
# Проверяем bridge
/interface/bridge/port/print where bridge=bridge-containers
# veth должен быть в списке портов
# Проверяем IP на bridge
/ip/address/print where interface=bridge-containers
# Должен быть 172.17.0.1/24
# Проверяем NAT
/ip/firewall/nat/print where comment~"Container"
# Должно быть правило masquerade для 172.17.0.0/24
# Добавьте задержку запуска через scheduler
/system/scheduler/add name=delayed-container-start on-event="/container/start 0" start-time=startup interval=0 comment="Start container after boot"
/system/script/add name=start-containers-delayed source={
:delay 30s
:if ([/disk/find where label="containers"] != "") do={
:foreach id in=[/container/find where status!=running] do={
/container/start $id
:delay 5s
}
:log info "All containers started"
} else={
:log error "USB disk not ready, containers not started"
}
}
/system/scheduler/add name=start-containers on-event="/system/script/run start-containers-delayed" start-time=startup interval=0
# Проверяем NAT-правила
/ip/firewall/nat/print where chain=dstnat
# Используйте разные внешние порты:
# Nginx: WAN:8080 -> 172.17.0.10:80
# Другой сервис: WAN:8081 -> 172.17.0.11:80
# 1. Ограничьте доступ к контейнерам из WAN — только нужные порты
/ip/firewall/filter/add chain=forward action=drop in-interface-list=WAN dst-address=172.17.0.0/24 comment="Block direct WAN access to containers"
# Разрешите только конкретные порты ДО этого правила:
/ip/firewall/filter/add chain=forward action=accept in-interface-list=WAN dst-address=172.17.0.10 dst-port=80 protocol=tcp comment="Allow HTTP to Nginx container"
# 2. Ограничьте доступ контейнеров к управлению маршрутизатором
/ip/firewall/filter/add chain=input action=drop src-address=172.17.0.0/24 dst-port=80,443,8291,22,23,8728,8729 protocol=tcp comment="Block container access to management"
# 3. Регулярно обновляйте образы контейнеров
# Используйте процедуру из Шага 9