Files
chorus/docs/10-deployment-and-operations.md
T

176 lines
10 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.
<!-- gitea-wiki-mirror:start -->
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
wiki_page: Deployment-and-Operations
wiki_url: https://git.ilapage.cn/OPC/chorus/wiki/Deployment-and-Operations.-
wiki_revision: 80dac27043770615620a5d346e5b0e6f72451ab4
synchronized_at: 2026-08-21T04:34:00Z
<!-- gitea-wiki-mirror:end -->
# 部署与运维
## 本页用途
本页定义 chorus 常驻服务的生产部署基线。当前尚无产品代码和真实生产环境,命令是后续实现必须满足的运维契约;域名、容量、保留期和阈值在首发工单确认后补充,不能由 Agent 猜测。
## 安全边界
- 生产只部署已审核制品和 `migrations/`;不从 `D:\github\goadmin` 构建,不运行 AutoMigrate。
- dev-tools 生成路由、`/gen/todb` 和写源码能力不得注册或被 nginx 代理;仅隐藏菜单不合格。
- DSN、会话密钥、Provider 主密钥/key ring、TLS 私钥只来自受控环境文件或密钥管理系统,权限最小化,不写入 Git/Wiki/日志。
- 原图、结果和缩略图保存在受保护目录,通过 portal 鉴权读取,不由 nginx 直接暴露。
- 数据迁移、回退、删除、清理和密钥轮换均是高风险操作,必须有工单、备份和人工确认。
## 服务概览
```text
Internet
→ nginx/TLS
→ chorus-portal 127.0.0.1:8080(页面、HTMX、JSON、MVP 内嵌 worker)
→ chorus-admin 127.0.0.1:8081(MVP-1)
→ /admin-ui 静态构建产物(MVP-1)
portal/admin → MySQL 8.0
portal worker → Provider(安全 DialContext)
portal → /var/lib/chorus/storage(或后续对象存储适配)
```
| 项目 | 基线 |
|---|---|
| 运行账号 | 独立无登录 `chorus` 用户 |
| 制品目录 | `/opt/chorus/releases/<commit>/`,`/opt/chorus/current` 指向当前版本 |
| 配置 | `/etc/chorus/chorus.env`,仅运行账号可读 |
| 持久数据 | `/var/lib/chorus/storage`,不随版本目录切换 |
| 日志 | journald 或平台日志;结构化且脱敏 |
| 进程托管 | systemd:`chorus-portal.service`、`chorus-admin.service` |
| 数据库 | MySQL 8.0,独立最小权限账号 |
| 构建 | CI 使用 Go 1.26.5;portal/web 与 admin-ui 使用 Node >=22 + pnpm 9.15.1 |
## 配置与凭据
| 配置 | 用途 | 敏感 |
|---|---|---|
| `CHORUS_ENV=production` | 启用生产安全门禁 | 否 |
| `CHORUS_DSN` | MySQL | 是 |
| `CHORUS_MASTER_KEY` / key ring | Provider Key 加解密与轮换 | 是 |
| `CHORUS_SESSION_KEY` | portal 会话 | 是 |
| `CHORUS_STORAGE_ROOT` | 生成物目录 | 否 |
| 上游/存储超时、lease、worker 数 | 执行与优雅退出 | 否 |
| `CHORUS_SESSION_TTL_MINUTES` | 服务端内存会话有效期 | 否 |
| `CHORUS_LOGIN_ATTEMPTS` / `CHORUS_LOGIN_WINDOW_SECONDS` | 登录节流窗口 | 否 |
| `CHORUS_MAX_PROMPT_BYTES` | prompt 字节上限 | 否 |
| `CHORUS_MAX_IMAGES` / `CHORUS_MAX_IMAGE_BYTES` / `CHORUS_MAX_UPLOAD_BYTES` / `CHORUS_MAX_IMAGE_PIXELS` | 上传边界 | 否 |
| `CHORUS_HISTORY_LIMIT` | 历史查询上限 | 否 |
| 保留期与磁盘告警 | 清理和容量保护 | 否 |
生产启动必须校验必需配置、密钥长度/key_id、目录权限、超时与 lease 关系;缺失或不安全时 fail closed。`CHORUS_ENV=production` 下若检测到 AutoMigrate 或 dev-tools 注册必须拒绝启动。
## 制品构建
在干净 CI 环境按固定提交来源导入后的 chorus 代码构建:
```bash
go version
corepack pnpm --dir portal/web install --frozen-lockfile
corepack pnpm --dir portal/web build
go test ./...
go vet ./...
go build -trimpath -o dist/chorus-portal ./portal
go build -trimpath -o dist/chorus-admin ./admin
corepack pnpm --dir admin-ui install --frozen-lockfile
corepack pnpm --dir admin-ui build:prod
```
portal 的模板和静态资源嵌入 `chorus-portal` 二进制,运行环境不需要 Node,也不从 CDN 加载资源;CI 必须先按 `portal/web/pnpm-lock.yaml` 重建并确认工作区无差异。MVP-0 没有 admin/admin-ui 时跳过对应命令并在发布记录说明。制品记录 chorus commit、Go module 校验、portal/web 与 admin-ui lockfile 和固定 go-admin 来源提交。
## 首次部署与升级顺序
1. 记录当前/目标 commit、迁移版本、制品校验值和回退条件。
2. 备份 MySQL,并验证备份可读取;确认持久存储快照/备份策略。
3. 把制品解压到新的 release 目录,不原位覆盖当前版本。
4. 用相同 MySQL 8 版本的隔离库执行全部 migration up/down/up 验证。
5. 停止取新任务并等待在途 worker 到优雅退出期限;旧 worker 未结束时不得启动会竞争同一租约的错误版本。
6. 在生产执行 `migrate ... up`;检查版本,禁止任何 AutoMigrate。
7. 原子切换 `current`,启动/重启 portal 和 admin。
8. 执行健康、就绪、登录、提交 mock/受控测试和权限检查。
9. 验证生产访问 dev-tools 路径为 404/未注册,并核对路由清单。
10. 观察错误率、租约过期、磁盘和数据库连接;满足观察窗口后完成发布记录。
## 健康与就绪
应用必须提供:
- `/healthz`:进程存活,不依赖上游;
- `/readyz`:必需配置有效、MySQL 可用、迁移版本匹配、存储可写、生产 dev-tools 未注册;
- admin 健康路径不得泄露版本、DSN、路由或密钥。
```bash
systemctl status chorus-portal
curl --fail http://127.0.0.1:8080/healthz
curl --fail http://127.0.0.1:8080/readyz
journalctl -u chorus-portal -n 100 --no-pager
```
MVP-1 同样检查 admin 8081。外部检查经 TLS/nginx 访问,不把内部端口暴露公网。
## portal 会话与请求边界
MVP-0 的终端用户会话保存在单个 portal 进程内存中,Cookie 只携带签名后的不透明 session ID。部署必须保持单实例;portal 重启或切换版本会让全部终端用户重新登录。不要在负载均衡后启动多个 portal 实例,除非先建立新的共享会话设计和工单。
生产 Cookie 必须为 Secure/HttpOnly/SameSite=Lax。反向代理不得记录 Cookie 或 CSRF header;请求日志和 GORM SQL 使用参数化输出。JSON 正文、multipart 总量、单图字节/像素/数量和历史查询都有显式生产配置,缺少任一阈值时启动失败。
上传先在应用层校验,再在 generation 事务回调中保存带 owner/generation metadata 的文件。事务失败只清理本请求保存的 key;存储根目录不能作为 nginx/static 目录暴露。
## MVP-0 worker 已实现配置与退出行为
portal 单二进制会同时启动 HTTP server 和内嵌 worker。生产除现有 portal 限制外,还必须显式提供:
| 变量 | 约束 |
|---|---|
| `CHORUS_WORKER_LEASE_SECONDS` | 正整数;必须大于 `CHORUS_PROVIDER_HTTP_TIMEOUT_SECONDS + 5` |
| `CHORUS_WORKER_POLL_MILLISECONDS` | 正整数;控制空队列轮询间隔 |
| `CHORUS_PROVIDER_HTTP_TIMEOUT_SECONDS` | 正整数;安全 HTTP client 总超时和响应头超时 |
| `CHORUS_PROVIDER_MAX_RESPONSE_BYTES` | 正整数;Provider JSON/Base64/下载响应读取上限 |
`CHORUS_MASTER_KEY` 的原始字节长度必须是 AES 支持的 16、24 或 32 字节;MVP-0 写入信封使用 `key_id=primary`。生产缺失或长度无效时 portal 启动失败且不输出密钥。开发环境未配置主密钥时只生成进程内临时密钥,适用于默认 `auth_type=none` mock;要测试持久化 Bearer 凭据必须显式提供稳定的仓库外密钥。
`CHORUS_TEST_DISABLE_WORKER` 是测试专用开关,只在 `CHORUS_ENV=test` 接受;开发和生产设置为 true 会启动失败。部署制品和服务配置不得设置该变量,`portal/web/e2e/fixture` 也不得进入生产运行命令。
#13 已在 Windows 前台进程两次用 `Ctrl+C` 验证停止认领、关闭 HTTP 并等待 worker 返回。真实 Linux/systemd 的 TERM、超时和重启恢复仍属于首次发布前门禁,不能把本机验证写成已上线。
## worker 优雅退出
- 收到 TERM 后先停止认领新任务;
- 在途任务只在 lease_token 仍有效时提交;
- systemd 的停止等待时间大于应用优雅退出期限;
- 到期未完成时退出,让租约自然过期,新 worker 原子重领;
- 不把 running 改回 pending,不无条件标 failed,不删除其他 worker 文件。
- 每种 generation kind 必须恰好一个启用的 ProviderModel;0 个或多个都应 fail closed,不随机选取。
- Provider 请求和结果 URL 只走安全 Client;带 Authorization 的跨 origin 重定向必须拒绝。
- 上游超时后用独立短超时尝试最终 CAS;token 已陈旧时只清理本 attempt 生成的临时结果。
- 自动健康/发布验证使用 mock,不把真实 Provider 请求作为启动探针。
## 存储、备份与监控
必须备份 MySQL 和仍在保留期内的生成物元数据/文件,并定期做恢复演练。至少监控:
- MySQL 连接、慢查询、迁移版本;
- pending 数/最老等待时间、running 租约过期数、失败率;
- Provider 429/5xx/超时和熔断状态;
- 存储总量、可用空间、临时文件增长、缩略图失败;
- 登录失败/节流、SSRF 拦截和越权拒绝;
- portal/admin 健康与重启次数。
保留期、备份频率、RPO/RTO、磁盘阈值尚未确认,是生产上线门禁。清理任务不得在确认前启用。
## 回滚
- 优先使用向后兼容迁移并回滚二进制;先停止新任务,再切回上一 release,重启并执行健康检查。
- 不能仅通过切回代码撤销数据库变更。需要 down 或恢复备份时先评估数据丢失,取得人工确认。
- 若新版本已写入旧版本无法识别的数据,停止回滚并采用前滚修复或已演练的备份恢复方案。
- 回滚后检查 migration version、陈旧 worker CAS、任务重复、文件一致性和 dev-tools 路由。
- 每次真实发布前至少在隔离环境演练相同升级与回滚步骤。
## 已知限制
- 尚未完成真实 Linux/systemd/nginx 部署、备份恢复和回滚演练;
- 高可用、多机 worker、对象存储和滚动升级尚未设计;
- 生产域名、TLS、容量、保留期、告警、RPO/RTO 和具体超时/lease 阈值待首发部署工单确认;
- 在这些门禁完成前,本页不能作为“已验证可上线”的证据。