Files
ModelRouter/docs/deployment.md
JianFeeeee f7e926ccb7 docs: README 拆分为主题文档 + 中性化竞品表述
README 从 642 行降到 131 行,只保留简介、核心能力、最小快速开始、文档索引、
改名说明、目录结构与测试入口。其余内容迁到 docs/,中英文索引一一对应:

  docs/features.md       实现与完整特性清单(原 README 的"实现/特性")
  docs/configuration.md  配置文件、自动探测模型、多密钥与配额
  docs/routing.md        模型路由、AUTO 链、冷却与半冷却、源/适配器、源模板
  docs/performance.md    实测内存占用与调优、thinking 预算
  docs/webui.md          WebUI 使用
  docs/adapters.md       Lua 适配器协议与内置适配器清单
  docs/gui.md            桌面端 Headless/Desktop 两种产物与构建
  docs/development.md    目录职责、开发协作、测试
  docs/deployment.md     部署、发行包、目录权限、llmsproxy 迁移与验证清单

中性化:README / README_EN / GUI 注释里的 `Clash Verge` 类比全部改为
「桌面壳 / desktop shell」,仓库内(源码与文档)已无该表述。
2026-10-26 22:28:24 +08:00

5.2 KiB
Raw Blame History

部署与迁移

本文档面向运维:单机 systemd 部署、发行包安装、目录与权限、从 llmsproxy 改名后的迁移与回滚。 返回 README。

1. 单机部署(推荐)

仓库根目录的 deploy.sh 负责:构建 → 预检配置 → 备份 → 原子替换二进制 → 重启服务 → 后置校验。它不修改源码,也不假设全新机器。

sudo ./deploy.sh                      # 默认读取仓库内 config.yaml
sudo ./deploy.sh --config other.yaml  # 投放并部署另一份配置

部署目标(改名后):

项 路径
二进制 /usr/local/bin/modelrouter
配置 /etc/modelrouter/config.yaml
适配器 /etc/modelrouter/adapters/
插件(可选) /etc/modelrouter/plugins/(需在配置里设 plugin_dir)
主密钥 /etc/modelrouter/master.key(0600)
systemd unit /etc/systemd/system/modelrouter.service

deploy.sh 会在以下情况中止而不是"看起来成功":

  • 部署后二进制起不来、或新配置 -check 不通过;
  • 凭据无法解封(master.key 丢失 / 与配置不匹配);
  • 检测到改名前的 /etc/llmsproxy,但新配置尚未建立(否则会部署出一个 没有 key、没有源的空实例,所有请求都被拒)。

2. 发行包安装

三个产物由 packaging/core-dist.sh 生成到 cmd/build/dist/:

modelrouter_<ver>_amd64.deb
modelrouter-<ver>.x86_64.rpm
modelrouter-<ver>-linux-amd64.tar.gz

deb / rpm 安装后:

sudo systemctl enable --now modelrouter
sudo journalctl -u modelrouter -f

tar 包内只有:modelrouter、config.example.yaml、modelrouter.service、 migrate-to-modelrouter.sh、adapters/。

发行包不含业务插件(channels / billing / quota / usage 等)。 它们保留在仓库中作为可选扩展,需要时手工放入 plugin_dir,网关不会自动安装、 覆盖或删除。这是有意的:插件属于运维资产,生命周期不与内核绑定。

首次启动会在 /etc/modelrouter/config.yaml 生成一份随机 admin key 的配置, key 打印在启动日志里。发行包不预置任何可用 key(历史上曾因此泄露过一个真实的 sk-gw-local-0001)。

3. 目录与权限

  • /etc/modelrouter 是唯一的读写根(systemd unit 用 ProtectSystem=strict + ReadWritePaths=/etc/modelrouter 固化这一点)。
  • master.key 必须 0600。当前 unit 以 root 运行:降权到普通用户需要先把 master.key 交给该用户并统一目录属主,否则服务会"带着明文落盘继续跑", 失败只留一行日志——这是独立变更,不要和加固混在一起。
  • plugin_dir 由运维维护;插件自带的状态文件(如 .channels-store.json)也在其中。

4. 从 llmsproxy 迁移

二进制、配置目录、服务名、环境变量已统一为 modelrouter:

旧 新
/usr/local/bin/llmsproxy /usr/local/bin/modelrouter
/etc/llmsproxy/ /etc/modelrouter/
llmsproxy.service modelrouter.service
LLMSPROXY_PLUGIN_DIR MODELROUTER_PLUGIN_DIR
LLMSPROXY_XDISPLAY_BASE MODELROUTER_XDISPLAY_BASE
LLMS_PROXY_MASTER_KEY MODELROUTER_MASTER_KEY

迁移脚本默认 dry-run,复制而非移动,旧目录永不删除:

sudo ./packaging/migrate-to-modelrouter.sh          # 预演(逐条打印将做什么)
sudo ./packaging/migrate-to-modelrouter.sh --apply  # 执行

它做五件事:复制状态目录并改写配置里的旧绝对路径、复核 master.key 0600、 安装新二进制(旧文件保留)、由旧 unit 生成新 unit(改写 ExecStart / WorkingDirectory / ReadWritePaths)、复制 /usr/share 资源;最后跑 modelrouter -check 并 systemctl daemon-reload。

确认新服务可用后,再手工清理旧布局(脚本不会删):

sudo systemctl disable --now llmsproxy.service
sudo rm -f /etc/systemd/system/llmsproxy.service
sudo rm -rf /usr/local/bin/llmsproxy /etc/llmsproxy /usr/share/llmsproxy

回滚(不需要旧文件被删):

sudo ./packaging/migrate-to-modelrouter.sh --rollback --apply

读取侧兼容:旧配置路径与旧环境变量仍被接受,所以"先换二进制、后改 unit" 这种顺序不会立刻失效。但写入永远落在新路径,迁移完成后不要两台布局混用。

5. 部署后验证清单

# 1) 进程与监听
systemctl status modelrouter --no-pager
ss -ltnp | grep modelrouter

# 2) 鉴权生效(无 key 必须 401)
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/v1/models

# 3) 带 key 能列出模型
curl -s -H "Authorization: Bearer $KEY" http://127.0.0.1:8080/v1/models | head -c 400

# 4) 真实请求走通(证明 LuaJIT 适配器路径未被打断)
curl -s -H "Authorization: Bearer $KEY" \
  -d '{"model":"AUTO","messages":[{"role":"user","content":"hi"}]}' \
  http://127.0.0.1:8080/v1/chat/completions | head -c 400

# 5) 仓库文件与生产文件一致(部署脚本的收尾检查)
sha256sum /usr/local/bin/modelrouter build/modelrouter

第 4 步失败但第 3 步成功,通常是适配器或上游凭据问题,不是部署问题: 查看 journalctl -u modelrouter -n 100。