diff --git a/docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md b/docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md index baf79d06..aeb13536 100644 --- a/docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md +++ b/docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md @@ -177,7 +177,7 @@ build// └─ README.md ``` -`web/` 可以保留在构建目录中供本地 smoke test 与人工排查使用,但 Jenkins Web Build 归档和 Web Deploy 传输必须以 `web.tar.gz` 为主,避免把大量静态碎文件逐个传回 Jenkins controller。`api-server` 和 `spacetime_module.wasm` 是单文件产物,默认直接归档单文件与对应 `.sha256`,不强制压缩。 +`web/` 可以保留在构建目录中供本地 smoke test 与人工排查使用。Web Build 必须生成 `web.tar.gz` 与 `web.tar.gz.sha256`,但 `web.tar.gz` 不作为 Jenkins controller 默认归档对象,避免每次把约数百 MB 的 Web 大包从 Linux agent 拉回本地 controller。Web 大包保存在构建机稳定目录 `/var/cache/genarrative-build/web-artifacts////`,Jenkins 只归档 `web.tar.gz.sha256`、`release-manifest.json` 与 `web-artifact-pointer.txt`。`api-server` 和 `spacetime_module.wasm` 是单文件产物,默认直接归档单文件与对应 `.sha256`,不强制压缩。 不再生成旧产物: @@ -258,7 +258,7 @@ Jenkins controller 与 Linux agent 看到的 Git 服务地址不同,必须拆 构建流水线运行在当前 Linux agent 的脱敏 label expression `linux && genarrative-build`。发布、导入导出和服务器配置流水线通过 `DEPLOY_TARGET` 映射到 Linux-only 脱敏部署表达式;其中 `development` 映射到当前 Linux 开发/构建/开发部署 agent 的 `linux && genarrative-build`,`release` 映射到独立 Linux 生产部署 agent 的 `linux && genarrative-release-deploy`,不能复用当前开发/构建/开发部署 agent。真实机器名、IP 和带 IP 的 Jenkins label 只允许留在 Jenkins 节点连接配置中,不能暴露为 Job 参数默认值、调度标签或文档推荐值。 -发布流水线通过 Jenkins `copyArtifacts(...)` 从对应构建 Job 获取归档产物,因此 Jenkins 需要安装并启用 Copy Artifact 插件。数据库导入流水线的手动上传模式使用 `stashedFile` 文件参数,因此 Jenkins 还需要安装并启用 File Parameter 插件。所有生产 Pipeline 日志必须带时间戳以便审计,Jenkins 需要安装 Timestamper 插件,并在全局配置中启用 `Enabled for all Pipeline builds`。邮件通知流水线使用 Jenkins Pipeline `mail` step,Jenkins 需要安装/启用 Mailer 能力,并在系统配置中配置 SMTP。生产发布不能退回到读取构建 workspace 本地目录的旧模式。 +发布流水线通过 Jenkins `copyArtifacts(...)` 从对应构建 Job 获取归档产物,因此 Jenkins 需要安装并启用 Copy Artifact 插件。Web 大包例外:`Genarrative-Web-Build` 只把轻量元数据归档到 Jenkins controller,`web.tar.gz` 保留在 Linux 构建机稳定目录 `/var/cache/genarrative-build/web-artifacts/`,`Genarrative-Web-Deploy` 在部署目标机器上按构建 Job、构建号和版本号读取该目录。development 目标天然共享当前 Linux 开发/构建/开发部署机;release 目标若不是同一台机器,必须先把该目录通过共享存储、rsync 或其它内网同步方式提供给 release 部署 agent。数据库导入流水线的手动上传模式使用 `stashedFile` 文件参数,因此 Jenkins 还需要安装并启用 File Parameter 插件。所有生产 Pipeline 日志必须带时间戳以便审计,Jenkins 需要安装 Timestamper 插件,并在全局配置中启用 `Enabled for all Pipeline builds`。邮件通知流水线使用 Jenkins Pipeline `mail` step,Jenkins 需要安装/启用 Mailer 能力,并在系统配置中配置 SMTP。生产发布不能退回到读取构建 workspace 本地目录的旧模式。 邮件通知的持久收件人不写入 Git,由 Jenkins `Secret text` 凭据 `genarrative-notification-emails` 保存,凭据内容为逗号分隔邮箱。所有生产流水线仍提供 `NOTIFICATION_EMAILS` 参数作为本次运行的追加收件人;通知 Job 会把持久收件人凭据与本次 `NOTIFICATION_EMAILS` 合并去重后发送,参数留空时只发送给持久收件人。流水线结束时在 `post { always { ... } }` 中异步触发 `Genarrative-Notify-Email`,把来源 Job、构建号、构建 URL、结果、源码分支、源码 commit、发布版本、部署目标和数据库名传给通知 Job。通知 Job 失败不能反向改变业务流水线结果,只在来源流水线日志中记录触发失败。 @@ -408,12 +408,12 @@ WASM_SOURCE="${CARGO_TARGET_DIR}/wasm32-unknown-unknown/release/spacetime_module - 构建后台前端,base path 为 `/admin/`。 - 生成或复制 `maintenance.html`。 - 将 `web/` 打包为 `web.tar.gz`,生成 `web.tar.gz.sha256`。 -- 归档 `web.tar.gz`、`web.tar.gz.sha256` 和 `release-manifest.json`;`web/` 展开目录不作为 Jenkins 主归档对象。 +- 将 `web.tar.gz`、`web.tar.gz.sha256` 和 `release-manifest.json` 复制到 `/var/cache/genarrative-build/web-artifacts////`;Jenkins 只归档 `web.tar.gz.sha256`、`release-manifest.json` 和 `web-artifact-pointer.txt`,不把 `web.tar.gz` 拉回 controller。 发布: - 先按 `SOURCE_BRANCH` / `COMMIT_HASH` 解析并 checkout 部署脚本源码,默认使用 `origin/master` 最新 commit;上游构建触发时使用上游传入的实际构建 commit。 -- 获取 `web.tar.gz` 与 `web.tar.gz.sha256`,先校验 checksum,再解压到 `/opt/genarrative/releases//web`。 +- 通过 Jenkins 归档获取 `web.tar.gz.sha256`、`release-manifest.json` 和 `web-artifact-pointer.txt`,再从 `/var/cache/genarrative-build/web-artifacts////` 读取 `web.tar.gz`;先校验 checksum,再解压到 `/opt/genarrative/releases//web`。 - 更新 `/opt/genarrative/current` 与 `/srv/genarrative/web` 指向。 - 执行 Nginx 配置测试和静态页面 smoke test。 - 不进入维护模式。 diff --git a/jenkins/Jenkinsfile.production-web-build b/jenkins/Jenkinsfile.production-web-build index ff5aa5c1..e42d29c4 100644 --- a/jenkins/Jenkinsfile.production-web-build +++ b/jenkins/Jenkinsfile.production-web-build @@ -11,6 +11,7 @@ pipeline { environment { GIT_REMOTE_URL = 'http://127.0.0.1:3000/GenarrativeAI/Genarrative.git' + WEB_ARTIFACT_ROOT = '/var/cache/genarrative-build/web-artifacts' } parameters { @@ -72,7 +73,29 @@ pipeline { stage('Archive') { steps { - archiveArtifacts artifacts: "build/${env.EFFECTIVE_BUILD_VERSION}/web.tar.gz,build/${env.EFFECTIVE_BUILD_VERSION}/web.tar.gz.sha256,build/${env.EFFECTIVE_BUILD_VERSION}/release-manifest.json", fingerprint: true + sh ''' + bash -lc ' + set -euo pipefail + + artifact_dir="${WEB_ARTIFACT_ROOT}/${JOB_NAME}/${BUILD_NUMBER}/${EFFECTIVE_BUILD_VERSION}" + mkdir -p "${artifact_dir}" + rm -f "${artifact_dir}/web.tar.gz" "${artifact_dir}/web.tar.gz.sha256" "${artifact_dir}/release-manifest.json" + install -m 0644 "build/${EFFECTIVE_BUILD_VERSION}/web.tar.gz" "${artifact_dir}/web.tar.gz" + install -m 0644 "build/${EFFECTIVE_BUILD_VERSION}/web.tar.gz.sha256" "${artifact_dir}/web.tar.gz.sha256" + install -m 0644 "build/${EFFECTIVE_BUILD_VERSION}/release-manifest.json" "${artifact_dir}/release-manifest.json" + + cat >"build/${EFFECTIVE_BUILD_VERSION}/web-artifact-pointer.txt" <&2 + echo "[web-deploy] development 目标要求 Web 构建与发布共享同一 Linux 构建/开发部署机;release 目标需要预先同步或挂载 ${WEB_ARTIFACT_ROOT}。" >&2 + exit 1 + fi + + mkdir -p "build/${BUILD_VERSION}" + cp -f "${artifact_dir}/web.tar.gz" "build/${BUILD_VERSION}/web.tar.gz" + if [[ -f "${artifact_dir}/web.tar.gz.sha256" ]]; then + cp -f "${artifact_dir}/web.tar.gz.sha256" "build/${BUILD_VERSION}/web.tar.gz.sha256" + fi + if [[ -f "${artifact_dir}/release-manifest.json" ]]; then + cp -f "${artifact_dir}/release-manifest.json" "build/${BUILD_VERSION}/release-manifest.json" + fi + echo "[web-deploy] 已从构建机本地目录获取 Web 大包: ${artifact_dir}" + ' + ''' } }