Apps

Apps 菜单提供可通过容器部署的预配置应用目录,支持自动配置 RouterOS 并兼容多个容器注册表,需要 Container 软件包。

Apps

摘要

子菜单: /app
所需软件包: container

App 菜单提供可通过几次点击部署的应用目录。每个应用可以由一个或多个预配置容器组成,并会自动应用必要的 RouterOS 配置,例如防火墙规则和地址转换。该目录由 MikroTik 准备和维护,但容器镜像来自多个注册表,例如 Docker Hub、GCR 和 Quay。

不过,配置参数可以在启用应用之前编辑,并且可以随时查看应用的 yaml 文件。

要求

App 系统继承与 Container 软件包相同的要求:

  • 架构支持: arm64 和 x86 架构。
  • Container 软件包: 必须已安装。
  • 设备模式: 必须启用容器模式(需要物理接触并重置设备)。
  • 外部存储: 强烈建议使用,以获得最佳性能。
  • 内存要求: 容器运行需要足够的 RAM(16MB SPI 闪存设备可能需要外部存储来存放镜像)。
  • 架构限制: 不支持采用 EN7562CT CPU 的设备(例如 hEX Refresh)。

安全注意事项

与底层 Container 系统一样,App 菜单也继承相关安全影响:

  • 首次启用容器支持需要物理接触。
  • 启用后,可以远程管理容器。
  • 设备被攻破后,可能利用容器安装恶意软件。
  • 设备安全性与运行容器的安全性等同。
  • 第三方容器镜像可能引入安全漏洞。

属性

属性类型默认值说明
auto-updateyes | nono在有新的容器镜像版本可用时启用或禁用自动更新。
check-certificateyes | noyes拉取容器镜像前,根据路由器的证书存储验证注册表证书。
container-command-linesstring(空)指定启动容器时传递给应用程序的命令行参数。
devicesstring(空)指定要透传给容器应用的附加硬件设备。
environmentstring(空)定义运行中应用可用的环境变量。以键值对列表形式指定。
extra-mountsstring(空)指定要附加到容器的其他挂载点。
firewall-redirectsstring(空)配置从主机设备到容器的端口重定向。
networkdefault | lan | internaldefault指定容器使用的网络:internal(NAT 之后)、lan(LAN 网络上)或 default(因应用而异;可以是 internal 或 lan)。
network-outgoing-accessyes | noyes允许特定容器应用访问外部网络;设置为 no 时会创建 mangle 丢弃规则。
pvidinteger1设置网桥中容器虚拟以太网接口的端口 VLAN ID(PVID)。
required-hw-devicesstring(空)容器启动时主机上必须存在的硬件设备。仅在添加 YAML 配置后才可以配置此属性。Compose 格式:[host-hw-device]:[device-in-app]
required-mountsstring(空)容器启动所需的挂载目录。仅在添加 YAML 配置后才可以配置此属性。Compose 格式:[dir-on-host]:[dir-in-app]
use-httpsyes | noyes为应用 URL 使用 HTTPS。此选项在不支持云服务的设备上不会生效。
yamlstring(空)提供应用的 YAML 组合。配置示例请参阅文档。

只读属性

属性类型默认值说明
app-size应用的总大小。
app-store-urlstring安装该应用的应用商店 URL。
cpu-usage应用当前占用的 CPU 百分比。
customyes | no指示该应用是否为用户创建的自定义应用。
data-size应用存储的数据大小。
default-credentialstring应用所需的默认凭据。
default-networklan | internal应用使用的默认网络。有效值为 lan 或 internal。
descriptionstringYAML 配置 descr 参数中定义的应用描述。
from-app-storeyes | no指示该应用是否从自定义应用商店安装。
interfacestring应用使用的 VETH 接口。
ip-addressIP分配给 VETH 接口的 IP 地址。
memory-current应用当前使用的内存量。
namestringYAML 配置 name 参数中定义的应用名称。
project-pagestringYAML 配置 page 参数中定义的应用项目页面 URL。
running指示应用当前是否正在运行。
statusacquire veth | configuring container(s) | downloading/extracting | starting应用的当前状态。可能的值表示应用正在获取 VETH 接口、配置容器、下载/解压或启动。
ui-urlstring为应用 Web 界面生成的 URL(如果可用)。
variables-to-be-used-in-environment应用环境中存在的所有变量列表。

设置向导

App 菜单包含设置向导(GUI 中的 "Setup" 按钮,或命令 /app/setup)。该向导会自动完成原本需要多个手动步骤的网络、存储和注册表设置。

步骤 1:选择存储

选择用于安装应用的存储磁盘。系统会自动检测可用的已格式化磁盘驱动器(例如 nvme1、usb1、disk1 及类似设备)。如果列表中没有合适的磁盘,必须先用 ext4 或 btrfs 文件系统格式化磁盘,然后通过 /disk 菜单挂载它。

要求:

  • 建议顺序读/写速度至少为 100 MB/s。
  • 建议随机 IOPS(每秒输入/输出操作数)至少为 10,000。
  • 继续操作前,使用 /disk/test 命令验证存储性能。
  • 强烈建议使用外部存储设备以获得最佳性能。
步骤 2:配置网桥

选择用于容器网络的 LAN 网桥接口。此配置可在本地网络上启用自动端口转发和应用自动发现。设置向导会自动配置以下内容:

  • 创建虚拟以太网(veth)接口
  • 将 veth 接口添加到已配置的网桥
  • 出站连接的 NAT 规则
步骤 3:配置 IP

定义路由器的 IP 地址以启用应用访问。系统会自动检测主 IP 地址;但复杂网络设置支持手动配置。指定的 IP 地址用于:

  • 生成应用 UI URL。
  • 创建自动端口转发规则。
  • 提供 WebFig 集成链接。
完成

完成设置向导后,App 系统即可立即使用。您可以直接通过界面启用应用。系统会自动处理所有底层容器配置。

配置

应用配置可通过 /app/settings 访问,与手动 Container 配置相比提供了更简化的设置。

属性

属性类型默认值说明
app-store-urlsstring(空)自定义应用商店 URL。该 URL 必须指向一个 YAML 数组,其中每个应用是数组中的一个元素。
auto-updateyes | nono为所有已安装应用包启用自动更新的全局设置。
diskstring(空)指定用于存储操作的磁盘的全局设置。
download-pathstring(空)手动指定存储所有下载内容的目录路径。
lan-bridgestring(空)手动指定代表局域网(LAN)的网桥接口。
media-pathstring(空)手动指定存储所有媒体文件的目录路径。
registry-mirrorsstring(空)指定一个或多个用于获取容器镜像的注册表镜像 URL 地址。
router-ipIP(空)手动指定可访问当前 RouterOS 设备的 IP 地址。
show-in-webfigyes | noyes控制是否在 WebFig 登录页面显示已启用应用的链接。

自动配置的设置

某些参数最初会根据网络检测自动配置。如有需要,这些值始终可以手动覆盖。

属性类型默认值说明
assumed-router-ipIP(检测值)自动检测到的 RouterOS 设备网络 IP 地址。
assumed-lan-bridgestring(检测值)自动检测到的用于 LAN 连接的网桥接口。
assumed-media-pathstringdisk/media默认媒体存储路径,通常位于系统磁盘上。
assumed-download-pathstringdisk/media/downloads默认下载目录路径,通常位于媒体存储区域内。

应用管理

应用通过 /app 接口管理,提供与底层 /container 系统类似的状态监控和生命周期控制:

/app> print 
Flags: X - DISABLED, R - RUNNING
Columns: NAME, UI-URL, MEMORY-CURRENT, APP-SIZE, DATA-SIZE, CATEGORY, DESCRIPTION
状态指示符和元数据
  • 标志:
    • X(DISABLED)- 可以表示两种状态:未下载/安装(APP-SIZE 和 DATA-SIZE 为空),或已下载但已禁用(APP-SIZE 和 DATA-SIZE 显示存储使用量)。
    • R(RUNNING)- 应用正在运行且可访问。
  • UI-URL: 应用运行时可直接访问的 Web 界面 URL。
  • MEMORY-CURRENT: 实时内存消耗,单位为 MiB(仅运行时显示)。
  • APP-SIZE: 容器镜像存储消耗,单位为 MiB(下载后显示已用空间)。
  • DATA-SIZE: 应用持久数据大小,单位为 KiB/MiB(显示配置和用户数据)。
  • CATEGORY: 应用功能分类。
  • DESCRIPTION: 应用功能描述。
应用生命周期管理

部署过程

手动部署 Container 需要多个配置步骤(veth 接口、网桥设置、环境变量、挂载和防火墙规则),而 App 部署会自动完成整个过程:

  1. 选择: 通过 CLI 或 WebFig 从目录中选择应用。
  2. 下载: 自动下载并解压容器镜像。
  3. 网络设置: 自动配置 veth 接口和网桥。
  4. 端口转发: 自动创建用于 Web 访问的防火墙规则。
  5. 启动: 使用预配置设置初始化容器。
  6. 访问: UI-URL 可用后即可立即访问 Web 界面。

清理命令

清理命令会彻底移除应用,包括所有关联数据。此操作具有破坏性且不可逆:

/app> cleanup pihole 
App data will be lost, continue? [y/N]:

清理过程:

  1. 停止正在运行的容器。
  2. 移除所有应用数据和配置文件。
  3. 从存储中删除容器镜像。
  4. 将应用重置为未安装状态(APP-SIZE 和 DATA-SIZE 为空)。
  5. 移除该应用专用的网络配置。

警告

所有用户数据、配置设置和应用状态都将永久丢失。应用将恢复到目录中的原始状态,清理后需要重新进行完整配置。

自定义应用

从 RouterOS v7.22 开始,您可以使用 'compose' YAML 文件创建自己的自定义应用。这让有经验的用户能够构建适合其特定网络需求的解决方案。

工作原理:

  • 使用 YAML 格式定义应用内部结构和有限的 RouterOS 配置
  • RouterOS 拉取指定的镜像并创建您的应用
  • 应用在 RouterOS 硬件上运行,无需额外成本即可提供新功能
  • 可选地,使其与我们的 API 交互

使用理由:

  • 精确构建网络所需的功能
  • 无需等待官方应用发布
  • 非常适合自动化、自定义路由或专用服务
  • 声明式设置使管理更容易

如何添加应用

有三种方式,但都依赖 YAML。

方式 1:创建空白应用并编辑 YAML

首先,创建应用并将其分配到 LAN 网络:

/app/add network=lan

默认情况下,应用将命名为 "app"。

接下来,添加 YAML 配置。在终端中运行:

/app/edit app yaml

这会打开一个文本编辑器,您可以在其中粘贴 YAML。粘贴后,按 <kbd>Control</kbd>+<kbd>O</kbd> 保存更改。最后,启用应用以启动它。

方式 2:从文件导入

或者,将 compose 文本保存到文件并上传到设备。然后,使用以下命令将该文件设置为应用的 YAML:

/app/add yaml=[/file/get alpine-iperf.yml contents]

当您有准备好导入的预配置 YAML 文件时,此方法很有用。

方式 3:添加自定义应用商店 URL

如果您或您认识的人在 Web 服务器上托管了自己的应用或应用列表,只需将 URL 添加到 APP 设置中即可。这样就可以拥有动态更新的自定义应用目录。

/app/settings set app-store-urls="<custom_url>"

要使其正常工作,该 URL 应直接返回 YAML 文件的文本内容,其中多个应用按照标准 YAML 语法列在一个简单列表中。

为自定义应用编写 YAML

此示例使用现有的 openEuler 基础镜像创建 iperf3 应用。

name: openeuler-iperf
descr: openEuler container running iperf3 server
page: https://iperf.fr/
category: networking
default-credentials: none
services:
  iperf:
    image: docker.io/openeuler/iperf:latest
    ports:
      - 5201:5201:tcp
      - 5201:5201/udp:udp
    command: /bin/sh -c "iperf3 -s"

关键区别:

  • 基础镜像已安装 iperf
  • 必要端口被转发/映射到路由器 IP
  • 'command' 在容器启动时执行并运行 iperf3

或者,您可以使用 Alpine Linux 等普通基础镜像,并通过 'command' 安装 iperf3。

name: alpine-iperf
descr: Alpine Linux container running iperf3 server
page: https://iperf.fr/
category: networking
default-credentials: none
services:
  iperf:
    image: docker.io/alpine:latest
    command: /bin/sh -c "apk add --no-cache iperf3 && iperf3 -s"
networks:
  default:
    name: lan
    external: true

关键区别:

  • 干净的基础镜像
  • 每次启动时安装并运行 iperf3
  • 应用网络设置为您的 LAN(端口转发的替代方案)

此外,如果希望确保 'command' 只执行一次某些操作,可以考虑使用如下条件单行命令:

command: /bin/sh -c "if ! command -v iperf3 >/dev/null 2>&1; then apk add --no-cache iperf3; fi; exec iperf3 -s"

端口映射

映射端口时,使用 X:Y 或 X:Y:Z 语法,其中 X 是路由器上的端口,Y 是容器上的端口,Z 是端口名称;不过某些名称具有特殊功能,例如 'web' 会使 RouterOS 设置反向代理并生成自动 URL。 以下是一些有效示例:

2211:21
888:80:web
9000:9000:api
9001:9001:api-secure

默认情况下,所有端口都设置为 TCP,除非将它们定义为 UDP,如下所示:

6000:6000/udp:udp
8000:8000/udp:custom_name

警告

默认情况下,端口 80 被视为 Web 端口,除非明确将其设置为其他类型。有一个健康检查会探测此端口 - 如果没有监听,应用会看起来卡在 starting 状态。当未映射端口 80 时,将使用第一个定义的端口。为避免歧义,请明确命名使用的端口。

YAML 字段参考

YAML 文档定义一个 App:包含 App 元数据的应用级部分,以及包含一个或多个容器定义的 services 部分。

应用级字段

字段类型说明
namestringApp 的唯一名称。
descrstring应用描述。
pagestring项目页面 URL,显示为 App 的 project-page 属性。
categorystringApp 列表中显示的分类组(例如 network、system、utilities)。
default-credentialsstring采用 username:password 格式的登录凭据。仅供参考;可以留空。
iconstring在 WebFig 登录页面显示的图标图像 URL。
url-pathstring附加到 App URL 的路径,例如 /login 或 /web。
auto-updateboolean当为 true 时,有新容器镜像可用时自动更新 App。
supported-archsstring 列表App 支持的 CPU 架构:arm、arm64、arm_v5 和 x86。不匹配指定架构的设备不会显示该应用。
compatible-boardsstring 列表App 支持的板卡名称,例如 RDS2216。接受 * 通配符。不匹配指定板卡名称的设备不会显示该应用。
servicesmap容器服务定义。至少需要一个服务。
volumesmap服务使用的命名卷声明。
secretsmapApp 的机密名称,在 environment 中通过 [secret:name] 引用。
configsmap挂载到服务中的配置文件声明。
networksmap服务使用的网络声明。

服务字段

字段类型说明
imagestring容器使用的 App 镜像。必需。
container_namestring与特定镜像一起使用的名称,如 /container 菜单中所示。
commandstring在容器内执行的启动命令。
entrypointstring用作容器入口点的可执行文件。
environment列表或 map传递给容器的环境变量。
volumes列表附加到容器的挂载点。
ports列表从路由器到容器的端口映射。
expose列表向其他容器暴露但不在路由器上发布的端口。
restartstring容器的重启策略。unless-stopped、always 和 on-failure。
depends_on列表必须在此服务之前启动的服务名称。
healthcheckmap容器启动时运行健康检查。参见下方示例。
shm_sizestring共享内存大小,例如 512mb 或 1gb。
stop_grace_periodstring 或 int优雅关闭的超时时间,例如 30s 或 0。默认 30 秒。
devices列表透传给容器的硬件设备,例如 - /dev/ttyACM0:/dev/ttyACM0。
userstring容器运行使用的 Linux 用户或 UID。
hostnamestring在容器中设置的主机名。
security_opt列表容器安全选项。
buildmap本地构建镜像的构建配置。
secrets列表此服务可用的机密名称,作为文件挂载到 /run/secrets/<name>。
configs列表挂载到此服务中的配置文件。

健康检查

健康检查会探测服务以验证应用是否正常运行。'test' 参数在容器内运行,当命令返回退出码 0 时,服务被视为健康:

healthcheck:
  test: ["CMD", "curl -f http://localhost:8080/ || exit 1"]
  interval: 30s
  retries: 3
  start_period: 30s
  timeout: 10s

运行时占位符

环境变量值和 default-credentials 字段可以包含占位符,RouterOS 会在 App 运行时替换它们。

占位符说明
[accessIP]用于从外部访问 App 的 IP 地址或主机名。
[accessPort]映射到 App Web 界面的路由器端口。
[accessProto]用于访问 App 的协议,http 或 https。
[containerIP]分配给容器的 IP 地址。
[containerInterface]为 App 创建的 VETH 接口名称。
[routerIP]路由器在 App 网络上的 IP 地址。
[env:variable]App 的环境变量值。
[env:service:variable]特定服务的环境变量值。
[secret:name]应用级 secrets 部分声明的机密值。

在环境值中使用占位符可自动配置服务:

environment:
  - NEXTCLOUD_TRUSTED_DOMAINS=[accessIP]
  - APP_URL=[accessProto]://[accessIP]:[accessPort]

卷

为服务添加持久数据:

services:
  app:
    image: docker.io/example/app:latest
    volumes:
      - data:/data              # persistent directory in the App storage
      - appdata/conf:/etc/app   # sub-directory, mounted at /etc/app
      - ./custom:/custom        # relative to the storage path

机密

机密将密码和密钥与环境分开存储。在应用级 secrets 部分声明机密,并在环境值和 default-credentials 中使用 [secret:name] 引用它们。RouterOS 会在 App 运行时生成机密值:

secrets:
  db_password:
  admin_password:
services:
  db:
    image: docker.io/postgres:17
    environment:
      POSTGRES_PASSWORD: "[secret:db_password]"
  server:
    image: docker.io/example/server:latest
    environment:
      ADMIN_PASSWORD: "[secret:admin_password]"

或者,在服务下列出机密,将其作为文件挂载到 /run/secrets/<name>:

services:
  server:
    image: docker.io/example/server:latest
    environment:
      DB_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

配置

配置以文本形式向容器提供配置文件。在应用级 configs 部分声明内容,并使用 source、target 和可选的 mode 将其挂载到服务中。

configs:
  mosquitto_conf:
    content: |
      listener 1883
      allow_anonymous true
services:
  mosquitto:
    image: docker.io/eclipse-mosquitto:latest
    configs:
      - source: mosquitto_conf
        target: /mosquitto/config/mosquitto.conf
        mode: 0644

source 是应用级配置声明的名称,target 是容器内的路径,mode 是文件权限。

网络

默认情况下,App 在 NAT 之后的内部网络上运行,服务通过映射端口访问。要将 App 直接放在某个网络上,请在应用级 networks 部分使用外部网络定义默认网络。

networks:
  default:
    name: lan
    external: true

自定义应用商店

App 系统支持以 YAML 数组形式提供的自定义应用商店,数组中的每个元素都是一个应用定义。该文件必须托管在设备可以通过网络访问的服务器上。

包含两个应用的 YAML 数组示例:

- name: code-server-xxx
  descr: Code-server is VS Code running on a remote server, accessible through the browser.
  page: https://coder.com
  category: development
  icon: https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/code-server-logo.png
  default-credentials: <no_username>:password
  services:
    code-server:
      image: lscr.io/linuxserver/code-server:latest
      container_name: code-server
      user: "0:0"
      environment:
        PUID: 0
        PGID: 0
        PASSWORD: password
        PWA_APPNAME: code-server
      volumes:
        - config:/config
        - media:/data/media
      ports:
        - 8443:8443:web
- name: code-server-yyy
  descr: Code-server is VS Code running on a remote server, accessible through the browser.
  page: https://coder.com
  category: development
  icon: https://raw.githubusercontent.com/linuxserver/docker-templates/master/linuxserver.io/img/code-server-logo.png
  default-credentials: <no_username>:password
  services:
    code-server:
      image: lscr.io/linuxserver/code-server:latest
      container_name: code-server
      user: "0:0"
      environment:
        PUID: 0
        PGID: 0
        PASSWORD: password
        PWA_APPNAME: code-server
      volumes:
        - config:/config
        - media:/data/media
      ports:
        - 8443:8443:web

提示和最佳实践

  • 存储: 为获得最佳性能和更大容量,请考虑使用外部存储设备,例如 USB 驱动器、SATA 驱动器或 NVMe SSD。

  • 内存: 在终端中运行 /app/print 命令,持续关注应用的内存消耗。

  • 更新: 仅在需要且认为必要时更新系统。自动更新可以提供安全补丁和新功能,但在启用或应用更新之前,请评估您的具体用例是否需要更新。

  • 网络: 应用会自动管理端口转发并生成用于外部访问的必要 URL。

  • 数据持久性: 应用数据存储在指定的存储路径中,即使应用重启或系统重启也会保持完整。