ai-chatbot/docs/production-48.md

100 lines
6.0 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.

# 48 生产发布
本流程由维护电脑发起,使用已有 SSH 密钥。生产只更新 `ai-chatbot`,不运行数据库迁移,
不更新 ZCode 原生运行时,不重启主机、Nginx 或其他 PM2 应用。
## 已核实的机器
| 用途 | SSH 入口 | 主机 |
| --- | --- | --- |
| 构建机 | `root@192.168.102.146:22` | `dao02-Default-string`,Ubuntu 24.04,Node 20 |
| 同一构建机的公网入口 | `root@45.192.99.48:23322` | FRP 转发,不是生产宿主机 |
| 生产机 | `root@45.192.99.48:64192` | `SfSTE0ttmsycO`,CentOS Stream 9,Node 20 |
| 维护连接跳板 | `root@192.168.58.20:22` | 已信任的 NAS,仅转发 SSH |
公网页面 `https://ai.yydd.ai/` 由生产 Nginx 转发至 `127.0.0.1:3125` 的 PM2 应用。
脚本固定验证生产、构建机的 SSH 指纹和主机名;私钥留在维护电脑,不转发 SSH Agent。
构建机原有 `/var/www/ai-chatbot` 是旧实例,本流程不会使用或覆盖它。
## 操作入口
维护电脑需要 Python 3.9+、Paramiko 3.3+、Git,以及已信任的 SSH `known_hosts`。
默认使用 `~/.ssh/45.192.99.48.pem` 和跳板密钥 `~/.ssh/youyidian_prod_ed25519`。
可用 `--key`、`--jump-key`、`--known-hosts` 覆盖本机路径,不要把私钥提交到仓库。
```powershell
python scripts/production48.py status
python scripts/production48.py jobs
# 完成 PR 合并后,确认远端 main 的最新提交,工作区必须干净。
git fetch origin
git switch main
git merge --ff-only origin/main
python scripts/production48.py build
```
`build` 将确定的 `origin/main` 提交通过 `git archive` 送到构建机,
在 `/opt/ai-chatbot-builds/<时间-提交>/source` 安装锁定依赖并构建。
使用 pnpm 9.12.3,不改变全局 pnpm。安装时不运行依赖脚本,构建时禁用自动安装系统服务。
构建保持 TypeScript 检查,限制 Next 构建并行度和 Node 内存,并降低进程优先级。
构建机仅收到 `NEXT_PUBLIC_*` 等公开页面配置,以及指向本机关闭端口的占位数据库配置。
不会收到生产数据库密码、AI Key、认证密钥或存储凭据。随后在构建机回环地址启动隔离候选实例,
核对构建 ID 并执行公开路由烟测,测试结束自动关闭该候选实例。
成功后会输出发布 ID,例如 `20261030T120000Z-0123456789ab`。后续步骤使用这个完整 ID:
```powershell
python scripts/production48.py stage --release <发布ID>
python scripts/production48.py activate --release <发布ID>
python scripts/production48.py status
# 仅对当前生效的这一版执行回滚:
python scripts/production48.py rollback --release <发布ID>
```
`stage` 校验传输 SHA256,在 `/var/www/ai-chatbot-releases/<发布ID>` 解包。
它检查压缩包路径、磁盘容量、锁文件、实际依赖文件/链接清单和 public 文件校验和。
完成解包后至少保留 1 GiB 空间;不足时停止,不自动删除历史构建。
当前和旧浏览器标签页所需的静态资源通过硬链接保留,不改动旧构建。
`activate` 会重新核对生产版本和任务状态,拒绝在最近一小时仍有未结束生成任务时切换。
更早的历史挂起记录只写入发布回执,不会自动修改数据库中的状态。
它保存旧 PM2 配置和启动快照,然后仅重建 `ai-chatbot` 这一项 PM2 定义,
让新版本的工作目录、可执行路径和环境变量全部生效,不改变其他应用,
因此会有短暂切换窗口。健康检查同时核对进程目录、构建 ID、首页和路由。
检查失败自动恢复旧配置并再次验活;通过后执行 `pm2 save`,让重启后使用已验收版本。
PM2 的普通 restart 会保留旧工作目录和程序路径,因此不能用它替代本流程的单应用定义重建。
若一次切换已经明确回滚并验证原版本健康,修复发布工具后,可保留已校验制品并显式重试:
```powershell
python scripts/production48.py activate --release <发布ID> --retry-rolled-back
```
只有日志阶段为 `rolled-back` 且当前工作目录/构建目录仍匹配原版本才允许重试。
旧尝试日志另外保留。运行制品的 `sourceCommit` 始终指向当时实际构建的 main 提交,
后续工具修复不改写这个来源;`operatorCommit` 单独记录执行切换的维护工具版本。
## 运行资料与边界
每个发布目录包含构建机按锁文件安装的完整运行依赖和 public 源码资源。
节点之间不复用 node_modules 链接,避免服务器漏装依赖补丁却被误认为同一版本。
对内容完全相同的依赖文件,通过 XFS 的写入时复制创建独立 inode,复用底层数据块;
缺失或不同的文件从已校验制品写入。任何一份副本后续修改均不会改动另一份。
生产文件系统不支持该操作时停止,不自动回退成可能耗尽磁盘的完整复制。
public 先从当前运行版本创建写入时复制副本,保留未纳入 Git 的运行资源,再叠加本次源码资源。
完整文件和链接清单在切换前再次验证,Node ABI 必须一致,并在生产机测试 sharp 原生模块。
原目录 `/var/www/ai-chatbot` 中的 `.env.local`、`tmp` 和模型配置备份仍通过链接使用,
不会复制、删除或覆盖。新版本也不在生产机执行依赖安装或构建。
本流程适用于应用代码迭代;数据库、共享资源的删除/迁移和原生 Agent 升级各自单独发布。
原生产 checkout 的支线及未提交改动仍保留,不能据其 Git HEAD 判断已发布版本。
实际发布证据是:运行 cwd、`.next/BUILD_ID`、该目录 `release.json` 和 `activation.json`。
维护电脑的 `.git/releases/<发布ID>/` 保留提交、构建日志、烟测、传输校验和及操作回执。
服务器回滚配置可能含环境元数据,目录权限为 0700、文件为 0600,不放入公开目录或 Git。
仓库历史全量 lint 仍有已记录的问题,不能声称全部质量门禁通过。
每次 PR 须记录本次改动的验证、历史失败和未覆盖项目;当前流程不会自动触发生产发布。