Files
sub2api-cn-relay-manager/docs/REAL_HOST_ACCEPTANCE_RUNBOOK.md
2026-05-19 22:24:32 +08:00

184 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Real Host Acceptance Runbook
日期2026-05-16
## 目标
把当前 `CONDITIONAL_APPROVED` 的剩余外部门禁收敛为一套可直接执行的真实宿主验收流程,覆盖:
1. 真实 sub2api 宿主接入探测
2. pack 安装
3. preview/import 验证
4. access preview / access status 验证
5. reconcile 验证
6. rollback smoke
## 前置条件
### 控制面
- `sub2api-cn-relay-manager` 已启动
- `CRM_BASE_URL` 可访问,例如 `http://127.0.0.1:8080`
- 已设置 `CRM_ADMIN_TOKEN`
### 真实宿主
- 已知真实宿主 `HOST_BASE_URL`
- 已知宿主管理认证:
- `HOST_API_KEY`
- `HOST_BEARER_TOKEN`
- 至少一个真实 provider key
- 已知 pack 路径,例如 `/app/packs/openai-cn-pack`
## 推荐执行方式
### 1. 构建本地容器镜像(适用于代理/离线开发机)
```bash
cd /path/to/sub2api-cn-relay-manager
scripts/build_local_image.sh
```
默认输出:
- 二进制:`bin/sub2api-cn-relay-manager`
- 镜像:`sub2api-cn-relay-manager:local`
### 2. 先 dry-run 检查真实验收参数
```bash
CRM_BASE_URL=http://127.0.0.1:8080 \
CRM_ADMIN_TOKEN=replace-me \
HOST_NAME=prod-sub2api \
HOST_BASE_URL=https://sub2api.example.com \
HOST_API_KEY=host-admin-key \
PACK_PATH=/app/packs/openai-cn-pack \
PROVIDER_ID=deepseek \
KEYS=sk-live-1,sk-live-2 \
ACCESS_MODE=self_service \
ACCESS_API_KEY=user-gateway-key \
DRY_RUN=1 \
scripts/real_host_acceptance.sh
```
### 3. 执行真实验收
```bash
CRM_BASE_URL=http://127.0.0.1:8080 \
CRM_ADMIN_TOKEN=replace-me \
HOST_NAME=prod-sub2api \
HOST_BASE_URL=https://sub2api.example.com \
HOST_API_KEY=host-admin-key \
PACK_PATH=/app/packs/openai-cn-pack \
PROVIDER_ID=deepseek \
KEYS=sk-live-1,sk-live-2 \
ACCESS_MODE=self_service \
ACCESS_API_KEY=user-gateway-key \
scripts/real_host_acceptance.sh
```
### 4. 订阅模式示例
```bash
CRM_BASE_URL=http://127.0.0.1:8080 \
CRM_ADMIN_TOKEN=replace-me \
HOST_NAME=prod-sub2api \
HOST_BASE_URL=https://sub2api.example.com \
HOST_BEARER_TOKEN=host-bearer-token \
PACK_PATH=/app/packs/openai-cn-pack \
PROVIDER_ID=deepseek \
KEYS=sk-live-1 \
ACCESS_MODE=subscription \
SUBSCRIPTION_USERS=user-a,user-b \
SUBSCRIPTION_DAYS=30 \
scripts/real_host_acceptance.sh
```
### 5. 导入后自动补 access 前置(可选)
当真实宿主需要额外完成“普通用户余额 / key-group 绑定 / 订阅写入 / 缓存失效”等宿主侧动作时,可在 import 完成后插入自定义 hook
```bash
AFTER_IMPORT_HOOK_COMMAND='bash /path/to/host-access-hook.sh' \
... \
scripts/real_host_acceptance.sh
```
hook 执行时会额外导出:
- `BATCH_ID`
- `BATCH_DETAIL_FILE`(若非 dry-run会指向 `05a-batch-detail-pre-access.json`
- `PROVIDER_ID`
- `HOST_BASE_URL`
- `CRM_BASE_URL`
- `ACCESS_MODE`
- `MODE`
- `ARTIFACT_DIR`
标准产物会新增:
- `05a-batch-detail-pre-access.json`
- `05b-after-import-hook.stdout.txt`
- `05b-after-import-hook.stderr.txt`
## 产物
脚本会把每一步 JSON 响应落到:
```text
artifacts/real-host-acceptance/<timestamp>/
```
默认文件顺序:
- `01-create-host.json`
- `02-probe-host.json`
- `03-install-pack.json`
- `04-preview-import.json`
- `05-import.json`
- `05a-batch-detail-pre-access.json`(若拿到了 `batch_id` 且非 dry-run
- `05b-after-import-hook.stdout.txt` / `05b-after-import-hook.stderr.txt`(若配置了 hook
- `06-access-preview.json`
- `07-access-status.json`
- `08-provider-status.json`
- `09-reconcile.json`
- `10-batch-detail.json`
- `11-rollback.json`(若未跳过)
## 通过标准
至少同时满足:
1. `probe-host` 返回宿主版本与 capability 快照
2. `install-pack` 成功
3. `import` 返回 `batch_id`,且 batch/provider 状态不为 `failed`
4. `access-preview` 返回 `available=true` 或 access status 进入:
- `subscription_ready`
- `self_service_ready`
- `fully_ready`
5. `reconcile` 不返回关键失败
6. `rollback smoke` 成功(若本次需要验证回滚链路)
## 当前门禁解释
- 若以上脚本在真实宿主环境全部通过:
- 可以把当前项目从 **代码层 `CONDITIONAL_APPROVED`** 推进到 **真实环境放行**
- 若脚本未执行:
- 仍然只能维持 `CONDITIONAL_APPROVED`
- 若脚本执行但失败:
- 失败应被归类为真实宿主兼容性 / 凭据 / 网络 / pack 内容问题,而不是再泛化成“代码是否已完成”
## 注意事项
1. 默认会执行 rollback smoke若当前环境不允许回滚设置
```bash
SKIP_ROLLBACK=1 scripts/real_host_acceptance.sh
```
2. `PACK_PATH` 必须是控制面进程可读路径,不是用户本地概念路径。
3. 如果控制面部署在容器中,确保 pack 目录已经挂载进去。
4. `HOST_API_KEY``HOST_BEARER_TOKEN` 二选一即可;脚本会自动推导 `auth.type=apikey|bearer`
5. `ACCESS_API_KEY` 必须使用真实未脱敏的普通用户 gateway key不能直接复用数据库/列表接口中的展示值。
6. 真实宿主初始化只会准备管理员账号;普通用户账号/密码不会自动生成,验收前必须显式创建并留存可复用凭据。
7. `self_service` 验证除普通用户 key 外,还需要该 key 绑定目标 group若目标 group 是标准计费组,还需要用户侧具备可用余额,否则 `/v1/models` 可能从“未授权”转为 `INSUFFICIENT_BALANCE`
8. `subscription` 验证需要目标 group 本身是 `subscription` 类型,并且完成“普通用户订阅分配 + 普通用户 key 绑定该 group”仅有管理员主体或未绑定 key 不足以通过 `/v1/models`
9. 若需要验证 `reconcile` 收敛,优先在干净宿主场景或隔离 group 下执行,避免历史残留资源把结果污染成 `status=drifted` / `extra_count>0`
10. `scripts/import_remote43_provider.sh` 现已内置 remote43 的 subscription 验收补全动作:会根据 import batch 自动解析目标 group执行“普通用户最低余额补齐 + key/group 绑定 + user_subscriptions upsert + 定向 Redis 缓存失效auth / balance / subscription并把 SQL / host state 证据写入 artifact 目录。
11. 当 CRM 进程与 operator 到 host 的访问地址不一致时,优先显式设置 `CRM_HOST_BASE`,避免把 CRM 侧探测地址和本地运维隧道地址混用。
12.`Upstream service temporarily unavailable` 一类 502不要先认定是上游聊天链路故障先看脚本落盘的 `09-models.headers.txt` / `10-models.body.json`。若 `/v1/models` 已返回了别的 provider 模型集(例如 GPT 系列而不是预期的 DeepSeek/Minimax 模型),先检查普通用户 key/group 绑定,也要检查 CRM 导入时是否把 provider 的 `channel_template.model_mapping``restrict_models``billing_model_source` 一并下发到宿主 channel。