6.0 KiB
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 覆盖本机路径,不要把私钥提交到仓库。
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:
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 会保留旧工作目录和程序路径,因此不能用它替代本流程的单应用定义重建。 若一次切换已经明确回滚并验证原版本健康,修复发布工具后,可保留已校验制品并显式重试:
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 须记录本次改动的验证、历史失败和未覆盖项目;当前流程不会自动触发生产发布。