关于 routeros-container
面向 RouterOS 管理者的容器子系统操作指南,涵盖 MikroTik 硬件上的 OCI 容器部署、网络与存储配置及生命周期管理。内容也说明版本差异和本地镜像导入限制。
主要功能
- 01启用并安装容器支持
- 02配置 VETH、桥接与 NAT
- 03设置环境变量和卷挂载
- 04从注册表拉取或导入镜像
- 05管理容器生命周期与 REST API
- 06说明版本属性及镜像限制
适用场景
- 01在 MikroTik 设备上部署容器
- 02为容器配置网络和端口转发
- 03自动化容器部署与管理
MCP 相关
文档提及可使用 rosetta MCP 服务查询 RouterOS 文档和属性;本身不是 MCP 服务。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tikoci/ routeros-skills --skill routeros-container安装后在 Claude Code 中输入/routeros-container确认已加载。
详细介绍
RouterOS 容器子系统
概述
RouterOS 7.x 包含一个容器子系统(/container),可直接在 MikroTik 硬件上运行兼容 OCI 的容器映像。它不是 Docker,而是 MikroTik 自行实现的功能,存在许多显著差异。
要求:
- 安装了
container额外软件包的 RouterOS 7.x - 必须启用设备模式(初次设置需要现场操作设备)
- 有足够的存储空间(建议使用外接 USB 磁盘,速度为 100+ MB/s、随机 IOPS 为 10K+)
- ARM、ARM64 或 x86 架构(容器不支持 MIPS)
设备模式——需要现场操作
容器支持受设备模式控制,需要通过物理确认(按下重置按钮或重启设备)才能启用:
# Enable container mode
/system/device-mode/update mode=advanced container=yes
# After executing: physically confirm within activation-timeout
# - Press reset button, OR
# - Power cycle the device
设备模式是 RouterOS 的通用安全功能,并非容器专属。它会在四种模式(home、basic、advanced、rose)下控制多项功能(调度程序、fetch、嗅探器等),各模式的出厂默认值因设备而异。
完整的功能矩阵、模式、更新属性和物理确认详情,请参阅 routeros-fundamentals 技能中的设备模式参考。
模式脚本绕过(7.22+): 在 netinstall 期间,模式脚本(-sm)可在首次启动时设置设备模式,并自动触发重启。请参阅 routeros-netinstall 技能。
安装容器软件包
# Check if container package is already installed
/system/package/print where name=container
方法 1:上传 .npk 文件 + apply-changes(离线)
# Upload via SCP (or Winbox drag-and-drop, or WebFig file upload)
scp container-7.22-arm64.npk admin@router:/
# Apply changes (triggers reboot AND activates — /system/reboot does NOT work!)
/system/package/apply-changes
⚠️ 重要:/system/package/apply-changes 是在 RouterOS 7.18 中新增的。 在 7.18+ 上,始终使用该命令——直接执行 /system/reboot 会丢弃已上传的软件包。在低于 7.18 的版本中,/system/reboot 是正确且唯一的方法。(经实验室验证:7.22.1 使用 apply-changes,7.10 需要重启。可通过 rosetta 命令树检查版本。)
方法 2:在线更新软件包(需要互联网连接)
/system/package/update check-for-updates
/system/package/update install
此操作会下载并安装所有可用更新,包括额外软件包。若要启用已上传但尚未激活的特定软件包,请使用 /system/package/enable container,然后执行 /system/package/apply-changes。
网络设置
VETH(虚拟以太网)
容器通过 VETH 接口连接到 RouterOS 网络:
# Create VETH pair
/interface/veth/add name=veth-myapp address=172.17.0.2/24 gateway=172.17.0.1
# The VETH name IS the container's interface name (RouterOS 7.21+)
网桥设置
# Create a bridge for containers
/interface/bridge/add name=containers
# Add VETH to the bridge
/interface/bridge/port/add bridge=containers interface=veth-myapp
# Assign IP to bridge (acts as gateway for containers)
/ip/address/add address=172.17.0.1/24 interface=containers
NAT / 防火墙
# Masquerade container traffic for internet access
/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.17.0.0/24
# Port forwarding from host to container
/ip/firewall/nat/add chain=dstnat action=dst-nat \
dst-port=8080 protocol=tcp to-addresses=172.17.0.2 to-ports=80
# Allow container bridge in interface list (if firewall restricts)
/interface/list/member/add list=LAN interface=containers
二层网络(网桥模式)
对于需要与物理接口处于同一 L2 网络的容器(例如 netinstall):
# Add both physical port and VETH to the same bridge
/interface/bridge/port/add bridge=mybridge interface=ether5
/interface/bridge/port/add bridge=mybridge interface=veth-netinstall
这样容器就可以直接访问 ether5 上的设备。
环境变量和挂载
从 7.21+ 开始,有两种方式可为容器附加环境变量和挂载:
内联方式(7.21+ 优先)
直接在 /container/add 上设置 env= 和 mount=,使容器配置自包含:
# Inline env vars and mount (7.21+)
/container/add remote-image=pihole/pihole:latest interface=veth1 \
env="TZ=Europe/Riga,WEBPASSWORD=secret" \
mount="src=disk1/pihole,dst=/etc/pihole" \
root-dir=disk1/images/pihole logging=yes
/app YAML 底层也是这种实现方式——内联是现代化的配置模式,更便于自动化(无需管理单独关联的对象)。
命名列表(适用于所有版本)
将环境变量和挂载创建为单独对象,然后通过名称引用:
# Create named env list (7.20+ — the 'list=' property groups envs together)
/container/envs/add list=MYAPP key=TZ value="Europe/Riga"
/container/envs/add list=MYAPP key=WEBPASSWORD value="secret"
# Create named mount
/container/mounts/add name=appdata src=disk1/appdata dst=/data
# Reference from container (7.20+ uses 'envlists=', pre-7.20 used 'envlist=')
/container/add file=myimage.tar interface=veth1 \
envlists=MYAPP mountlists=appdata root-dir=disk1/myapp
最佳实践: 始终将容器卷放在外接磁盘(disk1/)上,切勿放在内部闪存存储中。
属性名称历史
环境变量和挂载引用属性的名称在不同版本间有所变化:
| 版本 | 环境变量列表分组(/container/envs/add) | 容器环境变量引用(/container/add) | 容器挂载引用 |
|---|---|---|---|
| 7.20 之前 | 仅有 key=、value=(无分组属性) | (没有环境变量引用属性) | (不可用) |
| 7.20 | 新增 list= | 新增 envlists=(复数形式) | (不可用) |
| 7.21+ | list= | envlists= + 内联 env= | mountlists= + 内联 mount= |
版本说明: 7.20+ 的属性名称已通过
/console/inspect命令树数据确认。在 7.20 之前,/container/envs/add只有key和value,没有分组机制;/container/add没有环境变量引用属性。内联env=和mount=是在 7.21 中新增的。
容器镜像格式
RouterOS 接受以下格式的容器镜像:
选项 A:从注册表拉取
/container/config/set registry-url=https://registry-1.docker.io tmpdir=disk1/pull
/container/add remote-image=library/alpine:latest interface=veth-myapp
选项 B:导入本地 Tar 文件
将 Docker v1 tar 上传到路由器,然后:
/container/add file=myimage.tar interface=veth-myapp
本地导入的 OCI 镜像要求
RouterOS 的容器加载器对本地 tar 文件有特定要求:
- 仅限单层 — 不支持多层镜像
- 不支持 gzip 压缩 — 层必须是未压缩的 tar
- Docker v1 清单格式 —
manifest.json+config.json+layer.tar
myimage.tar
├── manifest.json # [{"Config":"config.json","RepoTags":["name:tag"],"Layers":["layer.tar"]}]
├── config.json # {"architecture":"arm64","os":"linux","config":{...},"rootfs":{...}}
└── layer.tar # Uncompressed tar of the full filesystem
这些限制是它与标准 OCI 镜像的主要区别——大多数来自公共注册表的基础镜像在通过注册表拉取时已满足要求 1 和 2;本地构建的 tar 必须满足全部三项要求。
容器生命周期
CLI
# Create container (7.21+ inline syntax)
/container/add file=myimage.tar interface=veth-myapp \
env="MY_VAR=hello" mount="src=disk1/appdata,dst=/data" \
root-dir=disk1/myapp logging=yes
# Start
/container/start [find tag~"myapp"]
# Stop
/container/stop [find tag~"myapp"]
# View status
/container/print
# View logs (if logging=yes)
/log/print where topics~"container"
# Remove (must be fully stopped first)
/container/remove [find tag~"myapp"]
REST API
const base = "http://192.168.1.1/rest";
const auth = { headers: { Authorization: `Basic ${btoa("admin:")}` } };
// List containers
const containers = await fetch(`${base}/container`, auth).then(r => r.json());
// Start container by ID
await fetch(`${base}/container/start`, {
method: "POST", ...auth,
headers: { ...auth.headers, "Content-Type": "application/json" },
body: JSON.stringify({ ".id": "*1" }),
});
// Check status — .running field is "true"/"false" (strings!)
const status = await fetch(`${base}/container/*1`, auth).then(r => r.json());
if (status.running === "true") { /* container is running */ }
// Stop container
await fetch(`${base}/container/stop`, {
method: "POST", ...auth,
body: JSON.stringify({ ".id": "*1" }),
});
// Delete — must be fully stopped. Poll .running and retry.
async function deleteContainer(id) {
for (let i = 0; i < 5; i++) {
const c = await fetch(`${base}/container/${id}`, auth).then(r => r.json());
if (c.running === "false") {
await fetch(`${base}/container/${id}`, { method: "DELETE", ...auth });
return;
}
await new Promise(r => setTimeout(r, 3000));
}
throw new Error("Container did not stop in time");
}
容器 REST API 注意事项
.running字段是状态指示器——其值是字符串"true"/"false",而不是布尔值- 不存在
.stopped字段——只需检查.running - 停止过程中删除 = HTTP 400——必须轮询
.running,直到值为"false"后再执行 DELETE - 本地 tar 使用
file=,从注册表拉取使用remote-image= - 容器的
envlists=(复数,7.20+)引用环境列表名称——注意这里是复数。7.20 之前使用envlist=(单数)。请参阅上文的环境变量/挂载版本历史。
容器属性(7.22 起)
/container/add 的部分属性。这并非完整列表——要查看特定版本的完整列表,请使用 rosetta MCP 工具(/container/add 处的 routeros_command_tree)。
| 属性 | 描述 |
|---|---|
interface | VETH 接口 |
env | 内联环境变量(7.21+)。以逗号分隔的 KEY=value 对 |
envlists | 命名环境列表引用(7.20+)。请参阅上文的环境变量/挂载部分 |
mount | 内联卷挂载(7.21+)。src=host/path,dst=/container/path |
mountlists | 命名挂载列表引用(7.21+)。请参阅上文的环境变量/挂载部分 |
root-dir | 容器文件系统的存储位置 |
file | 容器 tar 文件(本地导入) |
remote-image | 容器镜像名称(从注册表拉取) |
cmd | 覆盖容器 CMD |
entrypoint | 覆盖容器 ENTRYPOINT |
hostname | 容器主机名 |
dns | 容器的 DNS 服务器 |
logging | 是否将容器 stdout/stderr 写入 RouterOS 日志(yes/no) |
start-on-boot | 设备启动时自动启动容器(yes/no) |
workdir | 覆盖工作目录 |
name | 容器名称(用于 [find where name=...]) |
devices | 直通物理设备(7.20+) |
cpu-list | CPU 核心亲和性 |
memory-high | RAM 使用量上限,单位为字节 |
架构映射
从注册表拉取或构建镜像时,请将 RouterOS 架构映射到 Docker 平台:
RouterOS architecture-name | Docker 平台 |
|---|---|
arm | linux/arm/v7 |
arm64 | linux/arm64 |
x86 | linux/amd64 |
查询路由器的架构:
const resource = await fetch(`${base}/system/resource`, auth).then(r => r.json());
const arch = resource["architecture-name"]; // "arm64", "arm", "x86"
/app 系统(7.21+/7.22+)
RouterOS 7.21 引入了 /app 路径(内置应用列表)。完整的 YAML 应用创建(/app/add)于 7.22 加入。完整的 YAML 规范请参阅 routeros-app-yaml 技能。
/app 与手动容器设置
如果需要完整控制 VETH/bridge/L2(例如 netinstall、DHCP 中继或其他原始 L2 工作流),请使用手动 /container 设置。对于符合 RouterOS 应用联网和端口转发惯例的标准多容器应用,请使用 /app YAML。
其他资源
相关技能:
- 有关 netinstall 和设备模式自动化:请参阅
routeros-netinstall技能 - 有关 /app YAML 格式:请参阅
routeros-app-yaml技能 - 有关 RouterOS 基础知识(CLI、REST、脚本):请参阅
routeros-fundamentals技能
MCP 工具:
- 有关 RouterOS 文档和属性查询:请使用
rosettaMCP 服务工具(routeros_search、routeros_get_page、routeros_search_properties)
外部文档: