# 生产部署计划 更新时间:2026-05-02 ## 目标 将当前部署方式调整为单机生产推荐方案:生产运行路径不使用 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。 - 静态资源仍允许访问,避免维护页样式和资源加载失败。 - 发布成功后自动解除维护模式。 - 发布失败时保持维护模式,并通过邮件通知人工处理。 ## 构建产物 每次构建产物按版本号归档: ```text build// ├─ web/ │ ├─ index.html │ ├─ assets/ │ ├─ maintenance.html │ └─ admin/ ├─ api-server ├─ spacetime_module.wasm ├─ scripts/ │ ├─ spacetime-publish-prod.sh │ ├─ database-export.sh │ ├─ database-import.sh │ ├─ maintenance-on.sh │ ├─ maintenance-off.sh │ └─ maintenance-status.sh ├─ deploy/ │ ├─ systemd/ │ │ ├─ spacetimedb.service │ │ └─ genarrative-api.service │ ├─ nginx/ │ │ ├─ genarrative.conf │ │ └─ snippets/maintenance.conf │ └─ env/api-server.env.example └─ README.md ``` 不再生成旧产物: - `web-server.mjs` - 旧的一体化 `start.sh` - 旧的一体化 `stop.sh` ## Jenkins 节点 Jenkins 可运行在 Windows 或其他机器上,但构建与发布动作使用 Linux agent。 ### 开发/构建实例 - 节点名:`genarrative-dev` - 标签:`genarrative-linux dev build` - 用途:拉代码、安装依赖、构建主站、构建后台、构建 `api-server`、构建 SpacetimeDB wasm、归档产物。 ### 生产/发布实例 - 节点名:`genarrative-prod` - 标签:`genarrative-linux prod deploy` - 用途:服务器配置、发布静态网站、发布 `api-server`、发布 SpacetimeDB 模块、数据库导入导出、维护模式切换。 ### SSH PEM 凭证 在 Jenkins 中使用 `SSH Username with private key` 类型添加 PEM 私钥: - `genarrative-dev-ssh-key`:开发/构建实例 SSH 凭证。 - `genarrative-prod-ssh-key`:生产/发布实例 SSH 凭证。 推荐使用非 root 用户,例如 `jenkins`。该用户只通过 sudoers 获得必要命令权限,例如 `systemctl restart genarrative-api`、`nginx -t`、维护脚本、发布目录切换等。 ## 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` 构建流水线运行在 `build && dev`,发布、导入导出和服务器配置流水线运行在 `deploy && prod`。 构建流水线支持参数 `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`。 该流水线属于高风险操作,默认要求人工确认后执行。 ### Web Build / Deploy 构建: - 构建主站静态文件。 - 构建后台前端,base path 为 `/admin/`。 - 生成或复制 `maintenance.html`。 - 归档 `web/` 产物。 发布: - 解包到 `/opt/genarrative/releases//web`。 - 更新 `/opt/genarrative/current` 与 `/srv/genarrative/web` 指向。 - 执行 Nginx 配置测试和静态页面 smoke test。 - 不进入维护模式。 ### Api Build / Deploy 构建: - 编译 Rust `api-server`。 - 归档单一可执行文件和必要运行说明。 发布: - 进入维护模式。 - 解包到 `/opt/genarrative/releases//api-server`。 - 更新 `/opt/genarrative/current`。 - 重启 `genarrative-api.service`。 - 检查本机 `/healthz`。 - 成功后解除维护模式。 - 失败时保留维护模式并发邮件。 ### Stdb Module Build / Publish 构建: - 使用 `spacetime build` 构建 `spacetime_module.wasm`。 - 归档 wasm 与发布脚本。 发布: - 进入维护模式。 - 将 wasm 上传到生产实例。 - 在生产实例本机执行 `spacetime publish -s local --bin-path spacetime_module.wasm `。 - 成功后执行必要 smoke test。 - 成功后解除维护模式。 - 失败时保留维护模式并发邮件。 ## 数据库导出与导入 ### 导出 `Genarrative-Database-Export` 用于人工导出生产数据: - 运行在 `deploy && prod`。 - 进入维护模式,避免导出期间继续写入。 - 从本机 SpacetimeDB 导出指定数据库数据。 - 产物归档到 Jenkins,并可额外保存到服务器备份目录。 - 成功后解除维护模式。 - 失败时保留维护模式并邮件通知。 ### 导入 `Genarrative-Database-Import` 用于人工导入或恢复数据: - 运行在 `deploy && prod`。 - 必须要求人工确认目标数据库、导入文件和是否覆盖。 - 进入维护模式。 - 导入前先生成一次安全备份。 - 执行导入。 - 执行数据校验和服务 smoke test。 - 成功后解除维护模式。 - 失败时保留维护模式并邮件通知。 数据库表结构变更必须同步检查并更新 `migration.rs`,不能只发布 wasm。 ## 全量构建并发布 `Genarrative-Full-Build-And-Deploy` 顺序: 1. 触发 `Genarrative-Web-Build`。 2. 触发 `Genarrative-Api-Build`。 3. 触发 `Genarrative-Stdb-Module-Build`。 4. 触发 `Genarrative-Stdb-Module-Publish`。 5. 触发 `Genarrative-Api-Deploy`。 6. 触发 `Genarrative-Web-Deploy`。 7. 执行生产 smoke test。 网站最后发布,避免后台或主站提前指向尚未完成发布的后端能力。 ## 回滚 - 网站回滚:将 `/srv/genarrative/web` 或 `/opt/genarrative/current` 切回上一版本并 reload Nginx。 - `api-server` 回滚:将 `/opt/genarrative/current` 切回上一版本并重启 `genarrative-api.service`。 - SpacetimeDB 模块回滚:发布上一版本 `spacetime_module.wasm`。 - 数据回滚:使用导入流水线恢复指定备份,必须进入维护模式。 ## 待落地文件 后续工程落地时需要新增或改造: - `deploy/systemd/spacetimedb.service` - `deploy/systemd/genarrative-api.service` - `deploy/nginx/genarrative.conf` - `deploy/nginx/snippets/maintenance.conf` - `deploy/env/api-server.env.example` - `scripts/deploy/maintenance-on.sh` - `scripts/deploy/maintenance-off.sh` - `scripts/deploy/maintenance-status.sh` - 新 Jenkinsfile 或 Job DSL,用于上述 10 条流水线。 - 更新旧部署文档,标记旧一体化脚本为废弃或迁移对象。 ## 参考 - SpacetimeDB 官方自托管文档:https://spacetimedb.com/docs/how-to/deploy/self-hosting/