引言
产品版本
本文档对应的产品版本为 ZStack API Router preview。
读者对象
本文档介绍 ZStack API Router 的环境准备、安装部署和部署后验证方法,主要适用于以下读者:
- 部署运维工程师。
- 平台管理员。
- 技术支持工程师。
- 负责模型网关交付的实施人员。
部署概述
ZStack API Router 可部署为独立 API 网关,也可作为 ZStack AIOS 或 LobsterPool 推理链路的一部分。核心服务为 zr-server,数据库使用 PostgreSQL,启动前需执行数据库迁移,可选启动后台任务组件用于渠道健康探测和模型同步。
部署形态
| 部署形态 | 适用场景 | 说明 |
|---|---|---|
| 单节点部署 | 试用、演示、小规模环境 | PostgreSQL 和网关服务部署在同一节点或同一 Compose 环境。 |
| 生产部署 | 正式业务环境 | PostgreSQL 使用独立实例,入口由 Nginx、Ingress 或负载均衡代理。 |
| 离线部署 | 无公网或受控机房 | 使用离线镜像包、环境变量模板和启动脚本部署。 |
| 兼容链路部署 | LobsterPool 或旧网关灰度替换 | 将 /openai/v1/* 兼容入口接入现有调用链路。 |
部署组件
| 组件 | 是否必需 | 说明 |
|---|---|---|
zr-server | 是 | 主服务,提供控制面、数据面、健康检查和指标。 |
zr-migrate | 是 | 启动前执行 PostgreSQL 数据库迁移。 |
zr-worker | 否 | 渠道模型同步和健康探测。 |
| PostgreSQL | 是 | 保存配置、令牌、组织、日志、审计和配额数据。 |
| Nginx 或 Ingress | 生产建议 | 提供 HTTPS、域名入口、灰度和访问控制。 |
| Prometheus | 生产建议 | 采集 /metrics 指标。 |
环境准备
支持的操作系统
| 操作系统 | 说明 |
|---|---|
| Rocky Linux 8 或兼容发行版 | 推荐用于生产环境。 |
| CentOS 7 或兼容发行版 | 可用于存量环境,需确认 Docker 和系统库版本。 |
| Ubuntu Server 20.04 或以上 | 可用于开发、测试和生产环境。 |
| macOS | 仅建议用于本地开发和验证,不建议作为生产部署环境。 |
组件版本要求
| 组件 | 版本要求 | 说明 |
|---|---|---|
| PostgreSQL | 14 或以上,推荐 16 | 运行时数据库。 |
| Docker | 20.10 或以上 | Docker 部署需要。 |
| Docker Compose | v2.0 或以上 | Compose 部署需要。 |
| Nginx | 1.20 或以上 | 生产入口、HTTPS 和灰度可选。 |
| systemd | 主流 Linux 发行版内置版本 | 二进制进程托管需要。 |
| OpenSSL 或系统 TLS 组件 | 随操作系统提供 | HTTPS 入口需要。 |
硬件规格
| 环境 | CPU | 内存 | 磁盘 | 说明 |
|---|---|---|---|---|
| 单节点试用 | 2 核 | 4 GB | 50 GB | 支持基础验证和少量调用。 |
| 小规模生产 | 4 核 | 8 GB | 100 GB | 建议 PostgreSQL 独立数据盘。 |
| 中等规模生产 | 8 核 | 16 GB | 200 GB | 建议独立 PostgreSQL、日志目录和指标采集。 |
| 高并发流式场景 | 16 核或以上 | 32 GB 或以上 | 按日志保留周期规划 | 需重点规划文件句柄、连接池和入口代理。 |
网络和端口要求
| 端口或方向 | 要求 |
|---|---|
3080 | zr-server 默认监听端口,可通过 ZR_BIND_ADDR 调整。 |
| PostgreSQL 端口 | 网关节点必须能访问数据库。 |
| 上游模型服务 | 网关节点必须能访问供应商或内部推理服务地址。 |
80、443 | 使用 Nginx 或 Ingress 对外提供 HTTP/HTTPS 时开放。 |
| DNS | 需要解析上游模型服务、入口域名和数据库域名。 |
| NTP | 建议开启时间同步,避免日志和签名校验异常。 |
TLS 和域名要求
生产环境建议准备:
- 对外访问域名,例如
api-router.example.com。 - 有效 TLS 证书。
- 指向 Nginx、Ingress 或负载均衡的 DNS 记录。
- 如使用企业统一入口,确认路径转发规则覆盖
/api/zr/*、/v1/*、/openai/v1/*、/healthz、/readyz和/metrics。
权限和目录要求
| 项目 | 要求 |
|---|---|
| 运行用户 | 生产环境建议使用专用系统用户运行服务。 |
| 配置文件权限 | 环境变量文件包含数据库密码和访问令牌,建议权限为 600。 |
| 日志目录 | 运行用户应具备写入权限。 |
| 诊断文件目录 | 上游失败诊断文件目录需持久化并限制访问权限。 |
| systemd | 运维人员需具备启动、停止、查看服务日志的权限。 |
| Docker | 使用 Docker 部署时,执行用户需具备 Docker 操作权限。 |
生产部署前检查
安装前请完成以下检查:
| 检查项 | 检查方法 |
|---|---|
| 数据库连通性 | 使用 psql 连接目标 PostgreSQL。 |
| 端口占用 | 检查 3080 或计划监听端口是否已被占用。 |
| 磁盘空间 | 确认数据库、日志和诊断文件目录空间充足。 |
| 上游网络 | 从网关节点访问模型供应商地址。 |
| 入口代理 | 确认 Nginx 或 Ingress 能转发数据面和控制面路径。 |
| TLS 证书 | 确认证书有效期和域名匹配。 |
| 指标采集 | 确认 Prometheus 可访问 /metrics。 |
| 备份策略 | 确认 PostgreSQL 备份和恢复流程。 |
| 安全配置 | 确认真实密钥不写入文档、默认脚本或公开日志。 |
单节点 Docker Compose 部署
适用场景
适用于试用、演示、功能验证和小规模环境。
前提条件
- 已安装 Docker 和 Docker Compose。
- 当前用户具备 Docker 操作权限。
- 本地端口
3080和 Compose 中配置的 PostgreSQL 端口未被占用。
操作步骤
- 进入部署目录:
cd zstack-router
- 检查环境变量模板:
sed -n '1,120p' .env.example
- 启动服务:
docker compose up --build -d
- 查看服务状态:
docker compose ps
- 查看日志:
docker compose logs -f zr-server
docker compose logs -f zr-worker
验证方式
curl -fsS http://127.0.0.1:3080/healthz
curl -fsS http://127.0.0.1:3080/readyz
curl -fsS http://127.0.0.1:3080/api/zr/openapi.json
注意事项
- Compose 默认配置适合验证,不建议直接作为大规模生产配置。
- 生产环境应使用独立 PostgreSQL,并配置备份。
- 如只验证 API,可不启用控制台静态资源。
生产环境部署
适用场景
适用于正式业务环境,通常由独立 PostgreSQL、zr-server、可选 zr-worker 和入口代理组成。
前提条件
- 已准备生产 PostgreSQL。
- 已完成数据库备份策略设计。
- 已准备域名、TLS 证书和入口代理。
- 已创建专用运行用户和部署目录。
准备数据库
create user zstack_router with password 'CHANGE_ME';
create database zstack_router owner zstack_router;
验证连接:
psql 'postgres://zstack_router:CHANGE_ME@{DB_HOST}:5432/zstack_router' -c 'select now();'
配置环境变量
创建环境变量文件,例如 /etc/zstack-router/zstack-router.env:
ZR_DATABASE_URL=postgres://zstack_router:CHANGE_ME@{DB_HOST}:5432/zstack_router
ZR_BIND_ADDR=0.0.0.0:3080
ZR_PROVIDER_MODE=openai
ZR_CLOUD_TOKEN=Bearer {CLOUD_TOKEN}
ZR_DISCOVERY_TOKEN=Bearer {DISCOVERY_TOKEN}
ZR_CONSOLE_DIST_DIR=/usr/share/zstack-router-console
ZR_PROVIDER_FAILURE_DUMP_DIR=/var/lib/zstack-router/provider-failures
设置权限:
chmod 600 /etc/zstack-router/zstack-router.env
chown zstack-router:zstack-router /etc/zstack-router/zstack-router.env
执行数据库迁移
export $(grep -v '^#' /etc/zstack-router/zstack-router.env | xargs)
zr-migrate
启动服务
使用 systemd 或容器平台启动 zr-server。需要渠道同步和健康探测时,同时启动 zr-worker。
配置入口代理
Nginx 应转发以下路径:
| 路径 | 转发目标 |
|---|---|
/api/zr/ | zr-server |
/v1/ | zr-server |
/openai/v1/ | zr-server |
/feedback | zr-server |
/healthz、/readyz | zr-server |
/metrics | zr-server,建议限制来源。 |
/ai-gateway | zr-server,仅启用控制台时需要。 |
流式接口需要关闭响应缓冲,避免 SSE 卡顿。
验证方式
| 验证项 | 命令或方法 |
|---|---|
| 服务健康 | curl -fsS https://{DOMAIN}/healthz |
| 服务就绪 | curl -fsS https://{DOMAIN}/readyz |
| OpenAPI | curl -fsS https://{DOMAIN}/api/zr/openapi.json |
| 指标 | Prometheus target 状态为 UP。 |
| 数据面 | 使用 API Key 调用 /v1/chat/completions。 |
离线环境部署
适用场景
适用于无法访问公网镜像仓库或需要离线交付的环境。
前提条件
- 已获得离线部署包。
- 目标服务器已安装 Docker 和 Docker Compose,或部署包已包含前置依赖。
- 已准备 PostgreSQL 或确认部署包内置数据库配置。
操作步骤
- 上传离线包到目标服务器。
- 解压到部署目录。
- 检查
env.example、docker-compose.yml和load-and-run.sh。 - 按环境修改
.env。 - 加载镜像并启动:
bash load-and-run.sh
- 执行健康检查。
注意事项
- 确保部署文件来自同一版本包,不要混用旧版本
docker-compose.yml和新版本镜像。 - 离线环境也必须配置数据库备份。
- 如需要包含 Docker/Compose 前置依赖,打包时使用对应离线依赖选项。
部署后验证
部署完成后,请按以下清单验证:
| 检查项 | 预期结果 |
|---|---|
zr-migrate | 执行成功,无数据库迁移错误。 |
zr-server | 正常监听目标端口。 |
zr-worker | 如启用,日志中无持续失败。 |
/healthz | 返回成功。 |
/readyz | 返回 ready。 |
/metrics | 可被指标系统采集。 |
| 控制台 | 如启用,可访问并登录。 |
| 数据面 | API Key 可调用目标模型。 |
| 用量日志 | 调用后产生用量记录。 |
| 审计日志 | 管理操作产生审计记录。 |
常见问题
/readyz 返回异常
可能原因:
ZR_DATABASE_URL配置错误。- PostgreSQL 不可达。
zr-migrate未执行或执行失败。
处理方法:
- 使用
psql验证数据库连接。 - 查看
zr-server日志。 - 重新执行
zr-migrate。
数据面无法调用上游模型
可能原因:
- 上游地址不可达。
- 凭证错误。
- SSRF 策略阻止该地址。
- 渠道未同步模型。
处理方法:
- 从网关节点访问上游地址。
- 检查渠道配置。
- 运行
zr-worker同步模型。 - 查看用量日志和上游失败诊断文件。
流式响应不稳定
可能原因:
- Nginx 或 Ingress 开启了响应缓冲。
- 进程文件句柄不足。
- PostgreSQL 连接池不足。
处理方法:
- 关闭数据面路径的代理缓冲。
- 提高 systemd
LimitNOFILE或容器 nofile。 - 根据并发量调整数据库连接池。
附录:常用运维命令
以下命令用于部署验证和运维排障:
curl -fsS http://127.0.0.1:3080/healthz
curl -fsS http://127.0.0.1:3080/readyz
curl -fsS http://127.0.0.1:3080/metrics
查看近期用量:
select endpoint, status, upstream_status, count(*) as requests,
max(created_at) as last_seen
from zr_usage_logs
where created_at >= now() - interval '30 minutes'
group by endpoint, status, upstream_status
order by last_seen desc;
