Clone
6
unnamed
ila edited this page 2026-08-24 10:14:58 +08:00
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.

部署与运维

本页用途

本页定义 chorus 常驻服务的生产部署基线。当前尚无产品代码和真实生产环境,命令是后续实现必须满足的运维契约;域名、容量、保留期和阈值在首发工单确认后补充,不能由 Agent 猜测。

安全边界

  • 生产只部署已审核制品和 migrations/;不从 D:\github\goadmin 构建,不运行 AutoMigrate。
  • dev-tools 生成路由、/gen/todb 和写源码能力不得注册或被 nginx 代理;仅隐藏菜单不合格。
  • DSN、会话密钥、JWT secret、TLS 私钥只来自受控环境文件或密钥管理系统,权限最小化,不写入 Git/Wiki/日志。
  • 原图、结果和缩略图保存在受保护目录,通过 portal 鉴权读取,不由 nginx 直接暴露。
  • 数据迁移、回退、删除、清理和密钥轮换均是高风险操作,必须有工单、备份和人工确认。

服务概览

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_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 历史查询上限 否
保留期与磁盘告警 清理和容量保护 否

生产启动必须校验必需配置、会话/JWT 密钥、目录权限、超时与 lease 关系;缺失或不安全时 fail closed。CHORUS_ENV=production 下若检测到 AutoMigrate 或 dev-tools 注册必须拒绝启动。

制品构建

在干净 CI 环境按固定提交来源导入后的 chorus 代码构建:

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 -C admin build -trimpath -o ../dist/chorus-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、路由或密钥。
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/下载响应读取上限

Provider API Key 由授权管理员通过管理端写入 provider_credentials.api_key。数据库、备份和管理员会话泄露会直接暴露完整 Key;必须限制数据库和管理端权限,列表/普通详情/日志/audit 禁止返回完整值,单条读取响应禁止缓存。部署环境不再需要 CHORUS_MASTER_KEY。

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 阈值待首发部署工单确认;
  • 在这些门禁完成前,本页不能作为“已验证可上线”的证据。

#24 管理端部署补充(2026-08-22)

  • 先执行全部 migrations/,再启动 chorus-admin server --config <受保护 settings.yml>;启动过程不会建库、迁移、seed 或 AutoMigrate。
  • Casbin 只使用 migration 管理的 sys_casbin_rule;发布检查应确认未生成或依赖默认 casbin_rule。
  • admin-ui 静态产物通过 pnpm --dir admin-ui build:prod 构建,API 基址在部署时配置并由反向代理限制到管理网络。
  • 首次管理员只通过仓库外环境变量运行 chorus-admin-bootstrap;密码不得进入服务文件、命令历史、日志或文档。

单一外部 Host 与内部端口(#38)

config/local-services.yml 和 scripts/*-all.bat 仅用于 Windows 本地开发,不是生产服务管理器。生产继续由 systemd/等价服务管理器和反向代理托管,敏感配置分别保存在 Portal 环境与 Admin settings 中。

推荐同一外部 HTTPS Host 使用路径分流:

/             -> chorus-portal 内部 loopback 地址
/admin/       -> admin-ui 静态构建产物
/admin-api/   -> chorus-admin 内部 loopback 地址

反向代理必须正确剥离或保留前缀,并把 Admin UI 的构建期 API 基址设置为同源 /admin-api;不得把 Admin API 或 Portal 直接绑定到公网地址。Portal 与 Admin API 内部端口仍由各自配置控制,Admin UI 生产态没有独立 Node 端口。路径、Cookie scope、CORS、CSP、上传上限和 HTTPS 终止必须在独立部署工单验证后才能发布;#38 不执行发布或修改生产反向代理。

Windows 本机 Supervisor 运行

D:\supervisor 是当前 Windows 本地常驻运行方式,不替代生产反向代理或正式服务管理器。通过 scripts/install-supervisor.bat 生成三个独立实例:Portal、Admin API 和 Admin UI。Supervisor program 配置只保存进程路径、配置路径、Host/Port 与日志策略;Portal 凭据继续从 portal.environment_file 指向的受保护 PowerShell 文件读取,Admin 敏感值继续只存在于 admin/config/settings.yml。

安装或更新:

scripts\install-supervisor.bat
D:\supervisor\supervisord.exe ctl /c D:\supervisor\supervisord.conf reload
D:\supervisor\supervisord.exe ctl /c D:\supervisor\supervisord.conf status

回退时停止 chorus-user、chorus-admin-api、chorus-admin-ui,移除 D:\supervisor\programs\chorus.conf 后 reload,再按需使用 scripts/start-all.bat。不得同时使用两套入口占用相同端口。