# 生产部署计划 更新时间:2026-05-02 ## 当前落地进度 已落地生产基础设施骨架与首批生产 Jenkinsfile: - `deploy/systemd/spacetimedb.service` - `deploy/systemd/genarrative-api.service` - `deploy/nginx/genarrative.conf` - `deploy/nginx/snippets/genarrative-maintenance.conf` - `deploy/env/api-server.env.example` - `scripts/deploy/maintenance-on.sh` - `scripts/deploy/maintenance-off.sh` - `scripts/deploy/maintenance-status.sh` - `scripts/build-production-release.sh` - `scripts/jenkins-checkout-source.sh` - `scripts/deploy/production-web-deploy.sh` - `scripts/deploy/production-api-deploy.sh` - `scripts/deploy/production-stdb-publish.sh` - `jenkins/Jenkinsfile.production-web-build` - `jenkins/Jenkinsfile.production-web-deploy` - `jenkins/Jenkinsfile.production-api-build` - `jenkins/Jenkinsfile.production-api-deploy` - `jenkins/Jenkinsfile.production-stdb-module-build` - `jenkins/Jenkinsfile.production-stdb-module-publish` - `jenkins/Jenkinsfile.production-full-build-and-deploy` - `jenkins/Jenkinsfile.production-server-provision` - `jenkins/Jenkinsfile.production-database-export` - `jenkins/Jenkinsfile.production-database-import` - `npm run build:production-release` 旧 Jenkins 一体化发布链对应的 Jenkinsfile 已从仓库移除,生产构建和发布入口统一切到 `jenkins/Jenkinsfile.production-*`。`scripts/deploy-rust-remote.sh` 等旧发布包脚本暂保留为历史迁移参考,不再作为生产 Jenkins Job 的入口。 ## 目标 将当前部署方式调整为单机生产推荐方案:生产运行路径不使用 Docker,不再使用旧的一体化启动脚本,由 systemd 托管 SpacetimeDB 与 Rust `api-server`,由 Nginx 托管主站、后台前端与必要反向代理。 本计划用于重新创建 Jenkins 流水线、服务器环境配置、网站发布、`api-server` 发布、SpacetimeDB 模块发布,以及数据库人工导入导出流程。 ## 生产架构 - Nginx 作为唯一公网入口,负责 HTTPS、静态站点、后台静态页面、维护页与 `/admin/api/` 反向代理。 - SpacetimeDB 作为系统服务运行,监听 `127.0.0.1:3000`,数据根目录为 `/stdb`。 - Rust `api-server` 作为系统服务运行,监听 `127.0.0.1:8082`,只被 Nginx 的 `/admin/api/` 访问。 - 主站与后台前端构建为静态文件,发布到服务器固定目录,不放入 Jenkins 目录,也不跟随 Docker 镜像。 - 除网站静态发布外,`api-server` 发布、SpacetimeDB 模块发布、数据库导入、服务器配置变更都必须先进入维护模式。 ## 服务器目录 - `/opt/genarrative/releases//`:每次发布的完整版本目录。 - `/opt/genarrative/current`:指向当前生效版本的软链接。 - `/srv/genarrative/web`:指向 `/opt/genarrative/current/web`,供 Nginx 托管静态站点。 - `/etc/genarrative/api-server.env`:`api-server` 生产环境变量文件。 - `/var/lib/genarrative/maintenance/enabled`:维护模式开关文件。 - `/stdb`:SpacetimeDB 程序、配置与数据根目录。 ## 生产密钥 `/etc/genarrative/api-server.env` 中的生产密钥指所有只能存在于生产服务器、不能进入 Git、不能进入构建产物的敏感配置。典型内容包括: - LLM 或第三方服务 API Key。 - 短信服务 Access Key 与 Secret。 - 后台登录、会话、签名、加密相关密钥。 - 生产 SpacetimeDB 地址与数据库名。 - 只允许生产使用的回调地址、白名单或内部令牌。 该文件由服务器配置流水线或人工初始化创建,权限建议为 `root:genarrative`、`0640`。Jenkins 构建任务不能读取该文件;只有生产发布或服务启动需要读取。 ## systemd 服务 ### SpacetimeDB - 服务名:`spacetimedb.service` - 运行用户:`spacetimedb` - 工作目录:`/stdb` - 启动命令:`/stdb/spacetime --root-dir=/stdb start --listen-addr=127.0.0.1:3000` - 对外暴露:默认不直接暴露公网端口。 该方案与 SpacetimeDB 官方自托管文档一致:使用 Ubuntu、专用用户、`/stdb` 根目录、systemd 服务和 Nginx。 ### api-server - 服务名:`genarrative-api.service` - 运行用户:`genarrative` - 工作目录:`/opt/genarrative/current` - 可执行文件:`/opt/genarrative/current/api-server` - 环境文件:`/etc/genarrative/api-server.env` - 监听地址:`127.0.0.1:8082` `api-server` 不放入 Docker,也不直接暴露公网端口。发布时替换版本目录并重启 `genarrative-api.service`。 ## Nginx 规则 只保留必要入口: - `/`:主站静态页面。 - `/admin/`:后台前端静态页面,后台构建时使用 `/admin/` 作为 base path。 - `/admin/api/`:反向代理到 `http://127.0.0.1:8082/admin/api/`。 - HTTP 到 HTTPS:只保留 301 重定向。 - `/maintenance.html`:维护中页面。 移除这些公网反向代理: - `/api/*` - `/generated-*` - 公网 `/healthz` - 其他旧的一体化 web server 代理入口。 SpacetimeDB 公网路由默认保持收敛,只按实际前端 SDK 需要暴露最小集合。禁止开放可远程发布数据库或管理实例的通用入口。 ## 维护模式 维护模式由 `/var/lib/genarrative/maintenance/enabled` 控制: - 文件存在:进入维护模式。 - 文件不存在:退出维护模式。 行为: - 网站静态资源发布不进入维护模式。 - `api-server` 发布、SpacetimeDB 模块发布、数据库导入、服务器配置变更必须进入维护模式。 - 普通页面在维护模式下展示 `/maintenance.html`。 - `/admin/api/*` 在维护模式下返回 503。 - 静态资源仍允许访问,避免维护页样式和资源加载失败。 - 发布成功后自动解除维护模式。 - 发布失败时保持维护模式,并通过邮件通知人工处理。 ## 构建产物 生产发布包构建入口: ```bash npm run build:production-release -- --name ``` 每次构建产物按版本号归档: ```text build// ├─ web/ │ ├─ index.html │ ├─ assets/ │ ├─ maintenance.html │ └─ admin/ ├─ web.tar.gz ├─ web.tar.gz.sha256 ├─ api-server ├─ api-server.sha256 ├─ spacetime_module.wasm ├─ spacetime_module.wasm.sha256 ├─ release-manifest.json ├─ scripts/ │ ├─ database-export.mjs │ ├─ database-import.mjs │ ├─ spacetime-migration-common.mjs │ ├─ maintenance-on.sh │ ├─ maintenance-off.sh │ └─ maintenance-status.sh ├─ deploy/ │ ├─ systemd/ │ │ ├─ spacetimedb.service │ │ └─ genarrative-api.service │ ├─ nginx/ │ │ ├─ genarrative.conf │ │ └─ snippets/genarrative-maintenance.conf │ └─ env/api-server.env.example └─ README.md ``` `web/` 可以保留在构建目录中供本地 smoke test 与人工排查使用,但 Jenkins Web Build 归档和 Web Deploy 传输必须以 `web.tar.gz` 为主,避免把大量静态碎文件逐个传回 Jenkins controller。`api-server` 和 `spacetime_module.wasm` 是单文件产物,默认直接归档单文件与对应 `.sha256`,不强制压缩。 不再生成旧产物: - `web-server.mjs` - 旧的一体化 `start.sh` - 旧的一体化 `stop.sh` ## Jenkins 节点 Jenkins 可运行在 Windows 或其他机器上,本机 Windows 只作为人工触发入口;构建与发布动作只允许由 Jenkins 调度到 Linux agent 执行。当前已接入的 Linux agent 是开发/构建机,同时也是 development 环境部署机。 ### 开发/构建/开发部署实例 - Jenkins Job 参数不暴露真实节点名、IP 或带 IP 的标签。 - 构建 Job 固定使用 label expression:`linux && genarrative-build`。 - 当前开发/构建/开发部署 agent 必须同时配置 `linux` 与 `genarrative-build` 两个标签;非 Linux 节点不能承担构建或部署。 - 用途:拉代码、安装依赖、构建主站、构建后台、构建 `api-server`、构建 SpacetimeDB wasm、归档产物,并执行 `DEPLOY_TARGET=development` 的开发环境部署。 ### 生产/发布实例 - Jenkins Job 参数不暴露真实节点名、IP 或带 IP 的标签。 - 生产机已作为独立 Linux Jenkins agent 接入,节点名使用脱敏名称 `genarrative-release-deploy-01`,调度标签只使用 `linux` 与 `genarrative-release-deploy`。 - 生产机真实连接地址只允许保存在 Jenkins 节点 SSH launcher 的 `host` 字段中,不能写入节点名、调度标签、Job 参数默认值或文档推荐命令。 - 发布 Job 通过 `DEPLOY_TARGET` 选择逻辑部署目标,再在 Jenkinsfile 内部映射到 Linux-only 脱敏调度表达式:`development -> linux && genarrative-build`,`release -> linux && genarrative-release-deploy`。 - 用途:服务器配置、发布静态网站、发布 `api-server`、发布 SpacetimeDB 模块、数据库导入导出、维护模式切换。 ### Git 仓库访问 Jenkins controller 与 Linux agent 看到的 Git 服务地址不同,必须拆成两层配置: - Jenkins Job 的 `Pipeline script from SCM` 由 controller 执行,SCM URL 使用 controller 可访问的公网地址:`http://82.157.175.59:3000/GenarrativeAI/Genarrative.git`。 - Jenkinsfile 内部的源码、脚本 checkout 在 Linux agent 上执行,`GIT_REMOTE_URL` 使用 agent 本机可访问地址:`http://127.0.0.1:3000/GenarrativeAI/Genarrative.git`。 因此生产 Jenkinsfile 不使用 `checkout scm` 作为构建源码入口,而是显式 `checkout([$class: 'GitSCM', userRemoteConfigs: [[url: "${GIT_REMOTE_URL}"]], ...])`。后续 `scripts/jenkins-checkout-source.sh` 会继续把 `origin` 设置为 `GIT_REMOTE_URL`,并按 `SOURCE_BRANCH` / `COMMIT_HASH` 拉取和校验目标提交。 `127.0.0.1` 只代表当前执行该阶段的 Linux agent 自身;如果 release agent 与 Git 服务不在同一台机器,必须把对应 Jenkinsfile 的 `GIT_REMOTE_URL` 改成 release agent 可访问的内网地址,不能让 release 发布阶段回退到 controller 公网拉取。 ### SSH PEM 凭证 在 Jenkins 中使用 `SSH Username with private key` 类型添加 PEM 私钥: - `genarrative-dev-ssh-key`:开发/构建实例 SSH 凭证。 - `genarrative-prod-root-ssh`:当前开发/构建实例已使用的 SSH 凭证;生产/发布实例复用同一个凭证。 推荐使用非 root 用户,例如 `jenkins`。该用户只通过 sudoers 获得必要命令权限,例如 `systemctl restart genarrative-api`、`nginx -t`、维护脚本、发布目录切换等。 ## Jenkins 流水线 生产 Jenkins 目标流水线: 1. `Genarrative-Server-Provision` 2. `Genarrative-Web-Build` 3. `Genarrative-Web-Deploy` 4. `Genarrative-Api-Build` 5. `Genarrative-Api-Deploy` 6. `Genarrative-Stdb-Module-Build` 7. `Genarrative-Stdb-Module-Publish` 8. `Genarrative-Database-Export` 9. `Genarrative-Database-Import` 10. `Genarrative-Full-Build-And-Deploy` 已落地的生产流水线脚本文件: - `jenkins/Jenkinsfile.production-web-build` - `jenkins/Jenkinsfile.production-web-deploy` - `jenkins/Jenkinsfile.production-api-build` - `jenkins/Jenkinsfile.production-api-deploy` - `jenkins/Jenkinsfile.production-stdb-module-build` - `jenkins/Jenkinsfile.production-stdb-module-publish` - `jenkins/Jenkinsfile.production-full-build-and-deploy` - `jenkins/Jenkinsfile.production-server-provision` - `jenkins/Jenkinsfile.production-database-export` - `jenkins/Jenkinsfile.production-database-import` `Genarrative-Database-Export`、`Genarrative-Database-Import` 的生产版 Jenkinsfile 已落地;旧的数据库导入导出 Jenkinsfile 已删除,避免继续沿用旧部署目录和旧一体化发布链假设。 构建流水线运行在当前 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 插件。生产发布不能退回到读取构建 workspace 本地目录的旧模式。 所有发布流水线必须提供 `DEPLOY_TARGET` 参数,用于选择逻辑部署目标: - 默认值:`development`,用于当前 Linux 开发/构建/开发部署 agent 上的开发环境部署,对应脱敏调度表达式 `linux && genarrative-build`。 - 备选值:`release`,对应生产发布目标,由独立 Linux 生产部署 agent 执行。 发布流水线的 `agent` 必须使用 `DEPLOY_TARGET` 在 Jenkinsfile 内部映射到脱敏 label expression,并且表达式必须包含 `linux`,避免在参数页面暴露真实节点名、IP 或带 IP 的 Jenkins label,也避免非 Linux 节点执行构建或部署。`release` 目标还必须要求 `CONFIRM_RELEASE_DEPLOY_AGENT=true`。`Genarrative-Full-Build-And-Deploy` 也必须透传同一个 `DEPLOY_TARGET`,确保 Stdb publish、API deploy、Web deploy 三个部署动作落到同一类目标部署环境。 ### Rust 构建缓存与磁盘控制 Jenkins 在 agent 上执行构建时会为不同 Job 或不同构建创建独立 workspace;Rust 默认把编译产物写入仓库内 `server-rs/target/`,会导致每个 workspace 都保留一份完整 target 目录,占用大量磁盘。生产构建流水线必须把 Rust 缓存固定到 workspace 外的稳定目录。 如果构建 agent 使用 `root` 账户执行,缓存目录不应写死为 `/var/lib/jenkins`。推荐优先使用单独数据盘,例如 `/data/jenkins-cache/genarrative/`;如果没有数据盘,可使用 `/var/cache/genarrative-build/`: ```bash mkdir -p /var/cache/genarrative-build/{cargo-home,cargo-target,sccache} chmod 700 /var/cache/genarrative-build ``` Rust 构建流水线建议统一设置: ```groovy environment { CARGO_HOME = '/var/cache/genarrative-build/cargo-home' CARGO_TARGET_DIR = '/var/cache/genarrative-build/cargo-target/prod-release' CARGO_INCREMENTAL = '0' RUSTC_WRAPPER = 'sccache' SCCACHE_DIR = '/var/cache/genarrative-build/sccache' SCCACHE_CACHE_SIZE = '30G' } ``` 如使用数据盘,则把上述路径替换为: ```groovy environment { CARGO_HOME = '/data/jenkins-cache/genarrative/cargo-home' CARGO_TARGET_DIR = '/data/jenkins-cache/genarrative/cargo-target/prod-release' CARGO_INCREMENTAL = '0' RUSTC_WRAPPER = 'sccache' SCCACHE_DIR = '/data/jenkins-cache/genarrative/sccache' SCCACHE_CACHE_SIZE = '30G' } ``` `scripts/build-production-release.sh` 必须尊重 `CARGO_TARGET_DIR`,不能硬编码从 `server-rs/target/` 拷贝 Rust 产物。脚本中的产物路径应按以下口径计算: ```bash CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-${SERVER_RS_DIR}/target}" API_BINARY_SOURCE="${CARGO_TARGET_DIR}/x86_64-unknown-linux-gnu/release/api-server" WASM_SOURCE="${CARGO_TARGET_DIR}/wasm32-unknown-unknown/release/spacetime_module.wasm" ``` 并发与清理规则: - Rust 构建 Job 建议使用 `disableConcurrentBuilds()`,或对共享 `CARGO_TARGET_DIR` 加 Jenkins `lock`,避免多个同包 release 构建同时写入同一最终产物路径。 - 生产发布流水线只能消费 `build//` 或 Jenkins 归档产物,不允许从共享 `cargo-target` 目录直接发布。 - `SCCACHE_CACHE_SIZE` 必须设置上限,避免编译缓存无限增长。 - 对 `/var/cache/genarrative-build/cargo-target` 或数据盘对应目录配置定期清理,建议保留最近 14 到 30 天。 - Jenkins Job 必须配置构建记录和归档产物保留策略,避免历史 release 包长期堆积。 ### 统一源码版本参数 所有构建流水线、发布流水线和 `Genarrative-Full-Build-And-Deploy` 都必须支持以下参数: - `SOURCE_BRANCH`:源码分支,默认 `master`,代表 `origin/master` 最新提交。 - `COMMIT_HASH`:可选 Git commit hash,留空时使用 `origin/` 最新 commit;填写时必须是 7 到 40 位十六进制 hash,并且该 commit 必须属于 `origin/`。 - `DEPLOY_TARGET`:逻辑部署目标选择参数。发布流水线和 `Genarrative-Full-Build-And-Deploy` 必填;构建流水线仅在 `PUBLISH_AFTER_BUILD=true` 时用于触发下游发布。 执行规则: - 流水线先按 Jenkins SCM 配置 checkout 仓库,再执行 `git fetch --tags --prune origin "+refs/heads/:refs/remotes/origin/"`。 - 如果工作区是浅克隆,流水线必须尝试 `git fetch --unshallow --tags`,确保能验证目标 commit 与分支关系。 - `COMMIT_HASH` 为空时,detached checkout 到 `refs/remotes/origin/` 当前最新 commit。 - `COMMIT_HASH` 非空时,先解析到完整 commit,再用 `git merge-base --is-ancestor refs/remotes/origin/` 校验该提交属于指定分支,校验通过后 detached checkout。 - 流水线日志必须输出最终 `SOURCE_BRANCH` 与实际 `SOURCE_COMMIT`。 - 构建产物必须写入 `release-manifest.json`,至少包含 `version`、`source_branch`、`source_commit`、`built_at` 和组件类型,供发布、回滚和审计使用。 构建流水线使用上述参数决定实际构建源码。发布流水线也暴露同名参数,但只用于选择本次发布使用的部署脚本、配置模板和 smoke test 逻辑;被发布的应用文件仍必须来自 Jenkins 归档产物或指定 release 包,不允许在发布流水线中重新构建。 当构建流水线以 `PUBLISH_AFTER_BUILD=true` 触发下游发布流水线时,必须把 `SOURCE_BRANCH` 和实际解析出的 `SOURCE_COMMIT` 作为下游 `COMMIT_HASH` 传递,确保部署逻辑和刚生成的产物可追溯到同一源码版本。 构建流水线支持参数 `PUBLISH_AFTER_BUILD`: - `false`:只构建并归档产物。 - `true`:构建成功后触发对应发布流水线。 发布流水线必须从归档产物获取文件,不依赖构建 workspace 的本地状态。 ## 流水线职责 ### Genarrative-Server-Provision 用于生产服务器一次性或低频配置: - 创建 `spacetimedb`、`genarrative` 等系统用户。 - 创建 `/stdb`、`/opt/genarrative`、`/srv/genarrative`、`/etc/genarrative`、`/var/lib/genarrative/maintenance`。 - 安装或更新 SpacetimeDB。 - 安装 systemd unit。 - 安装 Nginx 配置和维护模式 snippet。 - 执行 `nginx -t`。 - 启用并启动 `spacetimedb.service` 与 `genarrative-api.service`。 该流水线属于高风险操作,默认要求人工确认后执行。 已落地的 Jenkinsfile 为 `jenkins/Jenkinsfile.production-server-provision`。该流水线默认 `DRY_RUN=true`,只打印将执行的初始化动作;真正写入系统用户、目录、systemd、Nginx 配置并启动服务时,必须设置 `DRY_RUN=false` 且勾选 `CONFIRM_PROVISION`。当 `DEPLOY_TARGET=release` 时,还必须勾选 `CONFIRM_RELEASE_DEPLOY_AGENT`,并通过 `linux && genarrative-release-deploy` 调度到独立 release 部署 agent。 ### Web Build / Deploy 构建: - 先按 `SOURCE_BRANCH` / `COMMIT_HASH` 解析并 checkout 目标源码,默认构建 `origin/master` 最新 commit。 - 构建主站静态文件。 - 构建后台前端,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 主归档对象。 发布: - 先按 `SOURCE_BRANCH` / `COMMIT_HASH` 解析并 checkout 部署脚本源码,默认使用 `origin/master` 最新 commit;上游构建触发时使用上游传入的实际构建 commit。 - 获取 `web.tar.gz` 与 `web.tar.gz.sha256`,先校验 checksum,再解压到 `/opt/genarrative/releases//web`。 - 更新 `/opt/genarrative/current` 与 `/srv/genarrative/web` 指向。 - 执行 Nginx 配置测试和静态页面 smoke test。 - 不进入维护模式。 ### Api Build / Deploy 构建: - 先按 `SOURCE_BRANCH` / `COMMIT_HASH` 解析并 checkout 目标源码,默认构建 `origin/master` 最新 commit。 - 编译 Rust `api-server`。 - 归档单一可执行文件、必要运行说明和 `release-manifest.json`。 发布: - 先按 `SOURCE_BRANCH` / `COMMIT_HASH` 解析并 checkout 部署脚本源码,默认使用 `origin/master` 最新 commit;上游构建触发时使用上游传入的实际构建 commit。 - 进入维护模式。 - 解包到 `/opt/genarrative/releases//api-server`。 - 更新 `/opt/genarrative/current`。 - 重启 `genarrative-api.service`。 - 检查本机 `/healthz`。 - 导出产物归档成功后解除维护模式。 - 失败时保留维护模式并发邮件。 ### Stdb Module Build / Publish 构建: - 先按 `SOURCE_BRANCH` / `COMMIT_HASH` 解析并 checkout 目标源码,默认构建 `origin/master` 最新 commit。 - 使用 `spacetime build` 构建 `spacetime_module.wasm`。 - 归档 wasm、发布脚本和 `release-manifest.json`。 发布: - 先按 `SOURCE_BRANCH` / `COMMIT_HASH` 解析并 checkout 发布脚本源码,默认使用 `origin/master` 最新 commit;上游构建触发时使用上游传入的实际构建 commit。 - 进入维护模式。 - 将 wasm 上传到生产实例。 - 在生产实例本机执行 `spacetime publish -s local --bin-path spacetime_module.wasm `。 - 成功后执行必要 smoke test。 - 成功后解除维护模式。 - 失败时保留维护模式并发邮件。 ### Full Build-And-Deploy - 先解析一次最终 `SOURCE_COMMIT`,所有下游构建和发布都使用同一个分支与 commit。 - 并行执行 Web / API / Stdb 三条构建流水线。 - 构建全部成功后,按顺序执行 Stdb publish、API deploy、Web deploy,并把同一个 `DEPLOY_TARGET` 透传给三条发布流水线。 - 每条下游构建都只消费自己的归档产物,不直接复用别的 workspace。 - 生产 Web 发布只处理 `web.tar.gz` 与 checksum,API 发布只处理 `api-server` 与 checksum,Stdb 发布只处理 `spacetime_module.wasm` 与 checksum。 ## 数据库导出与导入 ### 导出 `Genarrative-Database-Export` 用于人工导出生产数据: - 已落地 Jenkinsfile:`jenkins/Jenkinsfile.production-database-export`。 - 通过 `DEPLOY_TARGET` 选择逻辑导出目标;`development` 映射到 `linux && genarrative-build`,`release` 映射到 `linux && genarrative-release-deploy`。 - `release` 导出必须勾选 `CONFIRM_RELEASE_DEPLOY_AGENT`,避免当前开发/构建/开发部署 agent 冒充 release 部署机。 - 进入维护模式,避免导出期间继续写入。 - 从目标机器本机 SpacetimeDB 导出指定数据库数据,默认连接 `SPACETIME_SERVER=local`,自托管 `root-dir` 默认 `/stdb`。 - 产物归档到 Jenkins,并可额外保存到 `SERVER_BACKUP_DIRECTORY`。 - 敏感 token 与 bootstrap secret 只通过 Jenkins Secret Text 凭据 ID 注入,不作为明文 Job 参数。 - 成功后解除维护模式。 - 失败时保留维护模式并邮件通知。 ### 导入 `Genarrative-Database-Import` 用于人工导入或恢复数据: - 已落地 Jenkinsfile:`jenkins/Jenkinsfile.production-database-import`。 - 通过 `DEPLOY_TARGET` 选择逻辑导入目标;`development` 映射到 `linux && genarrative-build`,`release` 映射到 `linux && genarrative-release-deploy`。 - `release` 导入必须勾选 `CONFIRM_RELEASE_DEPLOY_AGENT`,避免当前开发/构建/开发部署 agent 冒充 release 部署机。 - 通过 `INPUT_SOURCE` 选择数据源,`pipeline_archive` 从 `Genarrative-Database-Export` 归档复制 `INPUT_FILE`,`manual_upload` 使用本次构建上传的 `MANUAL_INPUT_FILE`;两种方式互斥,`Prepare` 阶段会直接拦截混填。 - `DRY_RUN` 默认开启;真正写入数据时必须勾选 `CONFIRM_IMPORT`,并让 `CONFIRM_DATABASE` 与 `CONFIRM_INPUT_FILE` 分别完全匹配 `DATABASE` 与实际输入文件。 - `REPLACE_EXISTING=true` 且 `DRY_RUN=false` 时必须额外勾选 `CONFIRM_REPLACE_EXISTING`。 - 进入维护模式。 - 导入前先生成一次安全备份。 - 执行导入。 - 执行数据校验和服务 smoke test。 - 成功后解除维护模式。 - 失败时保留维护模式并邮件通知。 - `pipeline_archive` 模式默认使用导出流水线 `Genarrative-Database-Export`;只需要填写 `EXPORT_BUILD_NUMBER_TO_IMPORT` 时,归档输入路径自动解析为 `database-exports/spacetime-migration-<导出构建号>.json`。如果导出时覆盖过 `WORKSPACE_EXPORT_DIRECTORY` 或 `EXPORT_NAME`,再显式填写归档内相对路径 `INPUT_FILE`。 - `manual_upload` 模式需要上传 `MANUAL_INPUT_FILE`,并在 `CONFIRM_INPUT_FILE` 中填写原始文件名;此模式不再填写 `EXPORT_BUILD_NUMBER_TO_IMPORT` 或 `INPUT_FILE`,`EXPORT_JOB_NAME` 的默认值会被忽略。 - 敏感 token 与 bootstrap secret 只通过 Jenkins Secret Text 凭据 ID 注入,不作为明文 Job 参数。 数据库表结构变更必须同步检查并更新 `migration.rs`,不能只发布 wasm。 ## 全量构建并发布 `Genarrative-Full-Build-And-Deploy` 编排: 1. 按 `SOURCE_BRANCH` / `COMMIT_HASH` 解析一次最终 `SOURCE_COMMIT`,默认 `origin/master` 最新 commit。 2. 并行触发 `Genarrative-Web-Build`、`Genarrative-Api-Build`、`Genarrative-Stdb-Module-Build`,三条构建都必须使用同一个 `SOURCE_BRANCH` 和 `SOURCE_COMMIT`。 3. 三条构建全部成功后,按顺序触发 `Genarrative-Stdb-Module-Publish`、`Genarrative-Api-Deploy`、`Genarrative-Web-Deploy`,同样继续透传同一个 `SOURCE_BRANCH`、`SOURCE_COMMIT` 和 `DEPLOY_TARGET`。 4. 最后执行生产 smoke test。 网站最后发布,避免后台或主站提前指向尚未完成发布的后端能力。 这种编排能够在不牺牲版本一致性的前提下缩短总耗时,同时避免 Web / API / Stdb 彼此等待构建资源。并行构建时仍要保证每条构建流水线独立归档自己的产物,发布阶段只能消费归档结果,不能回到构建 workspace 重新取文件。 `Genarrative-Full-Build-And-Deploy` 额外作为定时任务运行,Jenkins 在每天凌晨 4 点自动触发一次,默认按 `SOURCE_BRANCH=master` 解析最新提交,并以 `DEPLOY_TARGET=development` 把全量构建结果部署到开发机。该定时任务不改写手动触发参数语义,只是给主线全量发布补一个固定的夜间全量刷新入口。 ## 回滚 - 网站回滚:将 `/srv/genarrative/web` 或 `/opt/genarrative/current` 切回上一版本并 reload Nginx。 - `api-server` 回滚:将 `/opt/genarrative/current` 切回上一版本并重启 `genarrative-api.service`。 - SpacetimeDB 模块回滚:发布上一版本 `spacetime_module.wasm`。 - 数据回滚:使用导入流水线恢复指定备份,必须进入维护模式。 ## 待落地文件 后续工程落地时需要新增或改造: - [x] `deploy/systemd/spacetimedb.service` - [x] `deploy/systemd/genarrative-api.service` - [x] `deploy/nginx/genarrative.conf` - [x] `deploy/nginx/snippets/genarrative-maintenance.conf` - [x] `deploy/env/api-server.env.example` - [x] `scripts/deploy/maintenance-on.sh` - [x] `scripts/deploy/maintenance-off.sh` - [x] `scripts/deploy/maintenance-status.sh` - [x] `scripts/build-production-release.sh` - [x] `scripts/jenkins-checkout-source.sh` - [x] `scripts/deploy/production-web-deploy.sh` - [x] `scripts/deploy/production-api-deploy.sh` - [x] `scripts/deploy/production-stdb-publish.sh` - [x] `jenkins/Jenkinsfile.production-web-build` - [x] `jenkins/Jenkinsfile.production-web-deploy` - [x] `jenkins/Jenkinsfile.production-api-build` - [x] `jenkins/Jenkinsfile.production-api-deploy` - [x] `jenkins/Jenkinsfile.production-stdb-module-build` - [x] `jenkins/Jenkinsfile.production-stdb-module-publish` - [x] `jenkins/Jenkinsfile.production-full-build-and-deploy` - [x] `jenkins/Jenkinsfile.production-server-provision` - [x] 删除旧 Jenkinsfile:`Jenkinsfile.build-and-deploy`、`Jenkinsfile.deploy`、`Jenkinsfile.database-export`、`Jenkinsfile.database-import` - [x] 更新旧部署文档,标记旧一体化脚本为废弃或迁移对象。 - [x] `jenkins/Jenkinsfile.production-database-export` - [x] `jenkins/Jenkinsfile.production-database-import` ## 参考 - SpacetimeDB 官方自托管文档:https://spacetimedb.com/docs/how-to/deploy/self-hosting/ - 该文档建议 Ubuntu 24.04、`spacetimedb` 专用用户、`/stdb` root-dir、systemd 托管,以及 Nginx/HTTPS。 - 默认公网路由只开放 TypeScript SDK 必需的 `/v1/identity` 与 `/v1/database//subscribe`,其他发布、SQL、管理类入口保持本机可用。