Compare commits
2 Commits
1abec5754e
...
fb6fb6e9f5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb6fb6e9f5 | ||
|
|
d796e7d491 |
@@ -16,7 +16,7 @@
|
||||
|
||||
1. 构建产物目录统一使用 `build/<版本号>/`。
|
||||
2. 默认使用 Jenkins `BUILD_NUMBER` 作为版本号,避免依赖时间戳;如有需要也允许显式传 `BUILD_VERSION`。
|
||||
3. `构建` 与 `构建并部署` 在 `checkout scm` 后、实际构建前必须执行 `git reset --hard HEAD` 与 `git clean -fd`,避免固定源码目录内的 Git 变更和未跟踪文件影响发布包;不使用 `-x`,避免删除 `node_modules/` 等忽略目录后与 `RUN_NPM_CI=false` 冲突。
|
||||
3. 所有使用仓库源码的 Jenkins 流水线在实际执行脚本前必须先执行 `git reset --hard HEAD`,避免固定源码目录内的 Git 变更影响本次构建、部署或迁移操作;其中 `构建` 与 `构建并部署` 在实际构建前还必须执行 `git clean -fd` 清理未跟踪文件,不使用 `-x`,避免删除 `node_modules/` 等忽略目录后与 `RUN_NPM_CI=false` 冲突。
|
||||
4. `构建并部署` 可选填写 `COMMIT_HASH`。留空时使用 Jenkins SCM 当前检出的提交;填写时只能是 7 到 40 位十六进制 commit hash,流水线会先按 SCM checkout 得到仓库,再尽量拉取 `origin` 全部分支引用、解析该 hash 并 detached checkout 到对应 commit 后构建。
|
||||
5. `部署` 流水线允许人工启动;没有上游触发 cause 时按人工部署处理,不再直接失败。
|
||||
6. `部署` 流水线仅在存在上游触发 cause 时校验上游作业名与传入的 `EXPECTED_UPSTREAM_JOB` 一致;如配置了环境变量 `GENARRATIVE_ALLOWED_UPSTREAM_JOB`,还必须与该值一致。
|
||||
@@ -84,7 +84,8 @@ jenkins/Jenkinsfile.deploy
|
||||
|
||||
1. 读取触发原因;人工启动时跳过上游门禁,上游触发时同时兼容 `BuildUpstreamCause` 与经典 `UpstreamCause` 并继续校验上游作业名。
|
||||
2. 校验 `BUILD_VERSION`、`SOURCE_WORKSPACE_ROOT`、`DEPLOY_DIRECTORY` 非空。
|
||||
3. 执行:
|
||||
3. 在 `SOURCE_WORKSPACE_ROOT` 内执行 `git reset --hard HEAD`,确保部署脚本和构建产物选择不受本地改动影响。
|
||||
4. 执行:
|
||||
|
||||
```bash
|
||||
scripts/jenkins-deploy-release.sh \
|
||||
@@ -100,7 +101,7 @@ scripts/jenkins-deploy-release.sh \
|
||||
脚本语义:
|
||||
|
||||
1. 若部署目录已有旧版本且存在 `stop.sh`,先执行旧版本 `stop.sh`。
|
||||
2. 覆盖前如果旧部署目录存在 `migration-bootstrap-secret.txt`,先复制到 `deploy-state/migration-bootstrap-secret.previous.txt`,供新版本 `start.sh` 在 schema 冲突自动迁移时授权导出旧库。该文件属于 Jenkins 部署状态,不放入 `run/`,避免 `sudo` 启停脚本生成的 root 私有运行目录阻断后续部署写入。
|
||||
2. 覆盖前如果旧部署目录存在 `migration-bootstrap-secret.txt`,先复制到 `deploy-state/migration-bootstrap-secret.previous.txt`,供新版本 `start.sh` 在 schema 冲突自动迁移时授权导出旧库。该文件属于 Jenkins 部署状态,不放入 `run/`,避免 `sudo` 启停脚本生成的 root 私有运行目录阻断后续部署写入;如果后续部署失败,部署脚本必须把该快照复制回部署目录根下的 `migration-bootstrap-secret.txt`,避免当前仍在运行的数据库丢失对应迁移引导密钥。
|
||||
3. 只删除发布产物白名单中的旧文件,例如 `web/`、`api-server`、`spacetime_module.wasm`、`migration-bootstrap-secret.txt`、`scripts/`、`.env*`、`start.sh`、`stop.sh`、`web-server.mjs`、`README.md`。
|
||||
4. 将指定版本目录中的同名发布产物复制到部署目录;文件产物使用普通复制,`web/`、`scripts/` 等目录产物必须递归复制。
|
||||
5. 把 `WEB_PORT`、`MIGRATE_ON_CONFLICT`、`MIGRATION_DIRECTORY` 写入部署目录 `.env.local`,确保通过 sudo 执行 `start.sh` 时仍能读取 Jenkins 参数;启动前读取 `.env` 与 `.env.local` 中最终的 `GENARRATIVE_SPACETIME_DATABASE`,打印并校验其符合 SpacetimeDB 数据库名规则。Jenkins 参数 `MIGRATION_EXPORT_TOKEN` / `MIGRATION_IMPORT_TOKEN` 会分别写入 `GENARRATIVE_SPACETIME_MIGRATION_EXPORT_TOKEN` / `GENARRATIVE_SPACETIME_MIGRATION_IMPORT_TOKEN`;如果参数为空,部署目录已有同名变量时会尽量保留。
|
||||
@@ -109,7 +110,7 @@ scripts/jenkins-deploy-release.sh \
|
||||
|
||||
如果 `RUN_DEPLOY_HOOKS_WITH_SUDO=true`,旧版本 `stop.sh` 和新版本 `start.sh` 会改为 `sudo -n` 调用;这要求 Jenkins 运行用户提前配置免密 sudo,否则部署会直接失败,不会进入交互式密码提示。
|
||||
|
||||
这样可以满足“发布文件直接覆盖”的要求,同时保留部署目录里像 `.spacetimedb/`、`logs/`、`run/`、`deploy-state/`、`database-migrations/` 这类运行态目录,不会因为部署被整体删除。`run/` 只承载 pid 等启停运行状态;`deploy-state/` 承载 Jenkins 覆盖部署前保存的旧迁移引导密钥,必须由 Jenkins 用户保持可写。发布白名单内的 `.env`、`.env.local` 会先以构建产物中的文件为准;部署脚本会在启动 hook 前移除这些环境文件中的 UTF-8 BOM 与 CRLF,并把 Jenkins 部署参数 `WEB_PORT` 写入 `.env.local` 的 `GENARRATIVE_WEB_PORT`,把 `MIGRATE_ON_CONFLICT` 写入 `GENARRATIVE_SPACETIME_MIGRATE_ON_CONFLICT`,把 `MIGRATION_DIRECTORY` 写入 `GENARRATIVE_SPACETIME_MIGRATION_DIR`,并在启动前输出最终 `GENARRATIVE_SPACETIME_DATABASE`,避免 `start.sh` 在 Bash 下把首行变量名误解析成命令,也避免端口、数据库名和迁移配置只停留在上游构建阶段。`start.sh` 会先执行 Ubuntu 专用 `sync_ubuntu_spacetime_install`,优先从 `/usr/.local/share/spacetime/bin/<version>/spacetimedb-cli` 或 `$HOME/.local/share/spacetime/bin/<version>/spacetimedb-cli` 同步到部署目录 `.spacetimedb/bin/current/spacetimedb-cli`,后续启动、探活和 root-dir 占用判定都使用部署目录内 `.spacetimedb/`,且不再额外设置 `--data-dir`,避免 Jenkins 机器全局 `spacetime login` 变化影响本地库更新;如遇 `403 Forbidden`,按 `SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md` 排查数据库所有者与 CLI 身份。
|
||||
这样可以满足“发布文件直接覆盖”的要求,同时保留部署目录里像 `.spacetimedb/`、`logs/`、`run/`、`deploy-state/`、`database-migrations/` 这类运行态目录,不会因为部署被整体删除。`run/` 只承载 pid 等启停运行状态;`deploy-state/` 承载 Jenkins 覆盖部署前保存的旧迁移引导密钥,必须由 Jenkins 用户保持可写,并在部署失败时作为恢复源写回根目录 `migration-bootstrap-secret.txt`。发布白名单内的 `.env`、`.env.local` 会先以构建产物中的文件为准;部署脚本会在启动 hook 前移除这些环境文件中的 UTF-8 BOM 与 CRLF,并把 Jenkins 部署参数 `WEB_PORT` 写入 `.env.local` 的 `GENARRATIVE_WEB_PORT`,把 `MIGRATE_ON_CONFLICT` 写入 `GENARRATIVE_SPACETIME_MIGRATE_ON_CONFLICT`,把 `MIGRATION_DIRECTORY` 写入 `GENARRATIVE_SPACETIME_MIGRATION_DIR`,并在启动前输出最终 `GENARRATIVE_SPACETIME_DATABASE`,避免 `start.sh` 在 Bash 下把首行变量名误解析成命令,也避免端口、数据库名和迁移配置只停留在上游构建阶段。`start.sh` 会先执行 Ubuntu 专用 `sync_ubuntu_spacetime_install`,优先从 `/usr/.local/share/spacetime/bin/<version>/spacetimedb-cli` 或 `$HOME/.local/share/spacetime/bin/<version>/spacetimedb-cli` 同步到部署目录 `.spacetimedb/bin/current/spacetimedb-cli`,后续启动、探活和 root-dir 占用判定都使用部署目录内 `.spacetimedb/`,且不再额外设置 `--data-dir`,避免 Jenkins 机器全局 `spacetime login` 变化影响本地库更新;如遇 `403 Forbidden`,按 `SPACETIMEDB_START_SH_PUBLISH_403_IDENTITY_FIX_2026-04-26.md` 排查数据库所有者与 CLI 身份。
|
||||
|
||||
### 4.3 构建并部署
|
||||
|
||||
|
||||
@@ -86,7 +86,8 @@ Genarrative-Database-Import
|
||||
2. `INCREMENTAL` 与 `REPLACE_EXISTING` 互斥,Jenkinsfile 会在执行前阻止同时启用。
|
||||
3. Jenkinsfile 不打印 token;生产环境应通过 Jenkins 凭据或目标机器环境变量传入敏感值。
|
||||
4. 如果不传 `TOKEN`,导入脚本会创建临时 Web API identity,并调用迁移授权/撤销 procedure 收敛权限窗口。
|
||||
5. 如果日志出现 `SpacetimeDB HTTP 413: Failed to buffer the request body: length limit exceeded`,优先把 `CHUNK_SIZE` 调低到 `262144` 或更小后重跑。该参数只降低单次 HTTP body,不改变导入表范围。
|
||||
5. 导入导出流水线在调用仓库内迁移脚本前都会执行 `git reset --hard HEAD`,确保固定源码目录中的本地改动不会影响本次迁移操作。
|
||||
6. 如果日志出现 `SpacetimeDB HTTP 413: Failed to buffer the request body: length limit exceeded`,优先把 `CHUNK_SIZE` 调低到 `262144` 或更小后重跑。该参数只降低单次 HTTP body,不改变导入表范围。
|
||||
|
||||
## 5. 本地部署测试参数
|
||||
|
||||
|
||||
@@ -113,6 +113,8 @@ pipeline {
|
||||
sh '''
|
||||
bash -lc '
|
||||
set -euo pipefail
|
||||
# 每条流水线开头先强制回到 SCM 检出的干净提交,避免固定源码目录残留改动影响本次执行。
|
||||
git reset --hard HEAD
|
||||
requested_commit="${COMMIT_HASH:-}"
|
||||
if [[ -n "${requested_commit}" ]]; then
|
||||
# Jenkins 先按 SCM 配置完成 checkout;如指定 commit,再拉取远端引用并切到该提交构建。
|
||||
|
||||
@@ -56,6 +56,8 @@ pipeline {
|
||||
sh """
|
||||
bash -lc '
|
||||
set -euo pipefail
|
||||
# 导出流水线复用固定源码目录时,先清掉本地改动,确保执行的是 Jenkins SCM 检出的脚本。
|
||||
git reset --hard HEAD
|
||||
export_dir="${params.OUTPUT_DIRECTORY}"
|
||||
if [[ -z "\${export_dir}" ]]; then
|
||||
export_dir="database-exports"
|
||||
|
||||
@@ -70,6 +70,8 @@ pipeline {
|
||||
sh """
|
||||
bash -lc '
|
||||
set -euo pipefail
|
||||
# 导入流水线复用固定源码目录时,先清掉本地改动,确保迁移脚本来自 Jenkins SCM 检出的版本。
|
||||
git reset --hard HEAD
|
||||
args=(scripts/spacetime-import-migration-json.mjs --in "${params.INPUT_FILE}")
|
||||
if [[ -n "${params.DATABASE}" ]]; then
|
||||
args+=(--database "${params.DATABASE}")
|
||||
|
||||
@@ -115,6 +115,8 @@ pipeline {
|
||||
sh """
|
||||
bash -lc '
|
||||
set -euo pipefail
|
||||
# 部署流水线也先清回上游工作区的当前提交,避免复用目录中的本地改动影响部署脚本或产物选择。
|
||||
git reset --hard HEAD
|
||||
test -d "build/${params.BUILD_VERSION}"
|
||||
deploy_script="${env.DEPLOY_SCRIPT_PATH}"
|
||||
chmod +x "\${deploy_script}"
|
||||
|
||||
@@ -182,6 +182,8 @@ PRESERVED_MIGRATION_EXPORT_TOKEN=""
|
||||
PRESERVED_MIGRATION_IMPORT_TOKEN=""
|
||||
PRESERVED_SPACETIME_TOKEN=""
|
||||
PRESERVED_SPACETIME_MAINCLOUD_TOKEN=""
|
||||
DEPLOY_COMPLETED="0"
|
||||
RESTORE_PREVIOUS_MIGRATION_BOOTSTRAP_SECRET_ON_FAILURE="0"
|
||||
DEPLOY_ITEMS=(
|
||||
".env"
|
||||
".env.local"
|
||||
@@ -307,9 +309,40 @@ save_previous_migration_bootstrap_secret() {
|
||||
exit 1
|
||||
}
|
||||
chmod 600 "${target_file}" 2>/dev/null || true
|
||||
RESTORE_PREVIOUS_MIGRATION_BOOTSTRAP_SECRET_ON_FAILURE="1"
|
||||
echo "[jenkins-deploy] 已保存旧模块迁移引导密钥,用于 schema 冲突时导出旧库。"
|
||||
}
|
||||
|
||||
restore_previous_migration_bootstrap_secret_on_failure() {
|
||||
local exit_code=$?
|
||||
local source_file=""
|
||||
local target_file=""
|
||||
|
||||
if [[ "${exit_code}" -eq 0 || "${DEPLOY_COMPLETED}" == "1" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "${RESTORE_PREVIOUS_MIGRATION_BOOTSTRAP_SECRET_ON_FAILURE}" != "1" ]]; then
|
||||
exit "${exit_code}"
|
||||
fi
|
||||
|
||||
source_file="$(previous_migration_bootstrap_secret_file)"
|
||||
target_file="${DEPLOY_DIR}/migration-bootstrap-secret.txt"
|
||||
if [[ ! -f "${source_file}" ]]; then
|
||||
echo "[jenkins-deploy] 部署失败,但未找到旧迁移引导密钥快照,无法恢复: ${source_file}" >&2
|
||||
exit "${exit_code}"
|
||||
fi
|
||||
|
||||
if cp "${source_file}" "${target_file}"; then
|
||||
chmod 600 "${target_file}" 2>/dev/null || true
|
||||
echo "[jenkins-deploy] 部署失败,已恢复旧迁移引导密钥: ${target_file}" >&2
|
||||
else
|
||||
echo "[jenkins-deploy] 部署失败,且恢复旧迁移引导密钥失败: ${target_file}" >&2
|
||||
fi
|
||||
|
||||
exit "${exit_code}"
|
||||
}
|
||||
|
||||
clear_previous_migration_bootstrap_secret() {
|
||||
local target_file
|
||||
|
||||
@@ -358,6 +391,7 @@ fi
|
||||
SOURCE_DIR="$(cd "${SOURCE_DIR}" && pwd)"
|
||||
mkdir -p "${DEPLOY_DIR}"
|
||||
DEPLOY_DIR="$(cd "${DEPLOY_DIR}" && pwd)"
|
||||
trap restore_previous_migration_bootstrap_secret_on_failure EXIT
|
||||
|
||||
if [[ ! -f "${SOURCE_DIR}/start.sh" ]]; then
|
||||
echo "[jenkins-deploy] 发布目录缺少 start.sh: ${SOURCE_DIR}" >&2
|
||||
@@ -457,3 +491,4 @@ else
|
||||
fi
|
||||
|
||||
echo "[jenkins-deploy] 完成"
|
||||
DEPLOY_COMPLETED="1"
|
||||
|
||||
Reference in New Issue
Block a user