Files
easyai-ai-gateway/docs/runbooks/production-ci-cd.md
T
wangbo 810dcfeee6 perf(storage): 极简化任务历史并增加保留治理
停止持久化 provider 原始响应、兼容响应快照、attempt/event/outbox 重复 JSON,并由标准任务结果动态生成 Kling/Keling/Volces 兼容响应。

增加事件去重与预算、极简 callback 投递、7/30 天分批清理、安全删除条件、并发迁移索引及可实际恢复的任务域排除备份。历史清理默认关闭,待兼容协议和异步恢复在线验证后单独启用。

验证:Go 全量测试与 go vet、PostgreSQL 18 集成与实际备份恢复、迁移安全测试、bash -n、ShellCheck、Compose 配置和人工发布脚本测试均通过。
2026-07-24 18:23:22 +08:00

171 lines
7.9 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.
# 人工生产发布运行手册
## 原则
生产发布没有自动触发器。允许 Agent 直接提交和推送 `main`,但 Git 操作不会授权 publish 或 deploy
1. 用户明确要求发布镜像后,Agent 执行本地 publish。
2. Agent 报告 manifest、digest、组件和冒烟结果并停止。
3. 用户再次明确确认上线后,Agent 执行 deploy。
不得把两步放进同一个命令、Git hook、Gitea Action、Webhook、服务、Timer 或轮询脚本。
## 一次性停用旧自动化
源码仓已经删除 `.gitea/workflows` 中的全部工作流,仓库级 Actions 开关必须为关闭;`main` 分支保护和 required status 也必须保持关闭。可用下列只读命令验收:
```bash
tea api /repos/BCAI/easyai-ai-gateway | node -e 'let s="";process.stdin.on("data",d=>s+=d);process.stdin.on("end",()=>console.log(JSON.parse(s).has_actions))'
tea branches list --repo BCAI/easyai-ai-gateway --output yaml | sed -n '/^- name: main$/,+3p'
```
第一条预期输出 `false`;分支状态预期 `protected: "false"``user-can-push: "true"`
确认没有运行中任务后,在旧 Runner 主机执行:
```bash
systemctl disable --now easyai-gateway-ci-v2-runner.service
systemctl is-active easyai-gateway-ci-v2-runner.service
```
预期第二条命令返回 `inactive`。保留 `easyai-gateway-ci-v2-data` volume 观察一段时间,不立即删除。
生产部署仓不得保留 Tag/Main dispatcher、Webhook receiver 或 Timer。先只读列出相关单元,确认精确名称后逐个 `disable --now`,不得用模糊匹配批量停止其他 EasyAI 服务:
```bash
systemctl list-unit-files --type=service --type=timer | grep -Ei 'easyai.*(release|dispatch|deploy)'
```
## 安装固定生产助手
生产助手只解析 manifest、拉取 digest、备份/迁移、更新 Compose、探活和回滚;它不是常驻服务,也不读取源码 checkout。
把以下三个已审查文件复制到生产服务器:
- `deploy/manual/easyai-ai-gateway-release`
- `deploy/manual/easyai-ai-gateway-release.conf.example`
- `scripts/release-manifest.mjs`
在可信 checkout 中可运行一次安装器:
```bash
sudo ./deploy/manual/install-release-helper.sh
sudoedit /etc/easyai-ai-gateway-release.conf
sudo /usr/local/sbin/easyai-ai-gateway-release status
```
配置文件必须为 root 所有、`0600`。助手安装后不会创建或启用 service、timer、webhook 或 watcher。
默认生产资源:
- 部署目录:`/root/easyai-ai-gateway-deploy`
- 发布清单:`/root/easyai-ai-gateway-deploy/.releases`
- 数据库备份:`/var/backups/easyai-ai-gateway`
- 公网入口:`https://ai.51easyai.com`
## 阶段一:本地 publish
前置条件:Docker Desktop/Engine、Buildx、Compose v2、Node、Go、可用 Registry 登录和生产只读 SSH。源码必须无 tracked/untracked 改动,HEAD 必须属于最新获取的 `origin/main` 历史。
```bash
docker login --username=<your-aliyun-account> registry.cn-shanghai.aliyuncs.com
./scripts/publish-release-images.sh --components auto
```
`auto` 读取线上当前 manifest,与 HEAD 比较后选择:
- `api`API、Go workspace 或迁移变化;
- `web`Web、contracts、pnpm 或 Nginx 容器配置变化;
- `all`Dockerfile/Compose 等共享运行时变化;
- `none`:无运行时变化,不产生发布物。
首次发布或线上状态不可验证时只能显式使用:
```bash
./scripts/publish-release-images.sh --components all
```
此路径保守地把迁移标记为变化:生产助手会先备份数据库,再运行新 API 镜像内的幂等 migrator。
publish 会执行快速 Go 测试、迁移安全校验、`linux/amd64` 构建、临时完整栈迁移和 API simulation 冒烟。全部通过后才推送完整 SHA Tag,并生成带 SHA-256 内容完整性字段的固定 schema manifest
```text
dist/releases/<40 位 Git SHA>.json
```
成功输出必须包含 `production_changed=false`。此时 Agent 应报告结果并停止,不得继续上线。
## 阶段二:人工 deploy
收到用户再次确认后执行:
```bash
./scripts/deploy-production-release.sh dist/releases/<40 位 Git SHA>.json
```
客户端和生产助手都会确认当前生产 SHA 仍等于 manifest 的 `baseReleaseSha`。不相等说明 publish 之后生产发生变化,必须重新 publish,不能覆盖或使用强制参数。
助手随后验证:
- API/Web 均为完整 Registry digest
- 镜像为 `linux/amd64`
- 本次变化组件的 OCI revision 等于 release SHA
- 迁移变化时生成排除任务历史数据的完整 schema/业务状态备份,并实际恢复到一次性数据库验证长期数据、外键和空任务历史表;
- 内部 API health/readiness/OpenAPI
- Web 页面和 Web API 反代;
- 公网 health/readiness/OpenAPI。
失败时自动恢复上一组应用 digest 并重复探活。已经执行的 expand-only 数据库迁移不会自动恢复。
## 任务历史治理
首次上线极简写入时保持 `AI_GATEWAY_TASK_CLEANUP_ENABLED=false`。先验证 Kling V1/V2、Volces 的提交、查询、失败响应和异步恢复均不依赖兼容快照或 provider 原始响应,再单独开启 cleanup。不要把首次清理和应用切换放在同一个维护动作中。
开启后每 5 分钟确认 7 天分析数据和 30 天主任务的过期积压;任一积压最长时间超过 24 小时、callback 待投递增长、结算待办增长或事件跳过指标异常时暂停治理并排查。以下查询只用于只读验收:
```sql
SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_catalog.pg_statio_user_tables
WHERE relname IN (
'gateway_tasks',
'gateway_task_attempts',
'gateway_task_events',
'gateway_task_callback_outbox',
'gateway_task_param_preprocessing_logs'
)
ORDER BY pg_total_relation_size(relid) DESC;
SELECT
(SELECT count(*) FROM gateway_task_attempts WHERE created_at < now() - interval '7 days') AS expired_attempts,
(SELECT count(*) FROM gateway_task_events WHERE created_at < now() - interval '7 days') AS expired_events,
(SELECT count(*) FROM gateway_task_param_preprocessing_logs WHERE created_at < now() - interval '7 days') AS expired_parameter_logs,
(SELECT count(*) FROM gateway_tasks WHERE finished_at < now() - interval '30 days') AS candidate_tasks;
```
逻辑删除稳定后执行 `VACUUM (ANALYZE)` 更新统计信息;它不会把空间归还给操作系统。物理回收只在独立维护窗口中逐表执行 `pg_repack`,执行前确认扩展、额外磁盘空间、主从延迟和锁等待均满足要求。优先处理 `gateway_task_events``gateway_task_attempts``gateway_tasks`,不得与 deploy、迁移或大批量清理并行。
治理控制目标:
- 新任务的兼容 body/Header、event/outbox payload、attempt 大 JSON 均为空;
- 普通成功任务不超过 4 条事件,每任务非终态事件不超过 16 条;
- 分析数据过期积压低于 24 小时,稳态分析表总量不超过主任务表的 20%;
- 首轮治理后任务域低于治理前 10.9GB 的 40%
- 发布备份不超过 1GB,备份和实际恢复各不超过 5 分钟。
## 状态与回滚
```bash
./scripts/deploy-production-release.sh --status
./scripts/deploy-production-release.sh --rollback <服务器已有的历史 SHA>
```
回滚也需要用户明确指令。服务器只接受 `.releases/<SHA>.json` 中已有版本,拒绝远端任意 Tag、`latest` 或临时镜像。
## 故障排查
- publish 前失败:没有推送镜像,也没有可部署 manifest;修复本地环境后重试。
- 镜像已经部分推送但 manifest 未生成:SHA Tag 被视为占用,先审查 Registry 中的 digest,不得覆盖重推。
- deploy 报基线过期:重新读取线上状态并重新 publish。
- 迁移备份失败:生产不切换。
- 生产探活和自动应用回滚都失败:停止发布,保留日志、当前数据库和 release manifest,人工恢复服务;不得自动执行 `pg_restore`