fix: publish stdb with service identity

This commit is contained in:
2026-05-03 02:11:44 +08:00
parent 562b5eb720
commit 62afaf620a
4 changed files with 80 additions and 5 deletions

View File

@@ -452,7 +452,8 @@ WASM_SOURCE="${CARGO_TARGET_DIR}/wasm32-unknown-unknown/release/spacetime_module
- 先按 `SOURCE_BRANCH` / `COMMIT_HASH` 解析并 checkout 发布脚本源码,默认使用 `origin/master` 最新 commit上游构建触发时使用上游传入的实际构建 commit。
- 进入维护模式。
- 将 wasm 上传到生产实例。
- 在生产实例本机执行 `spacetime publish -s local --bin-path spacetime_module.wasm <database-name>`
- 在生产实例本机执行 `spacetime --root-dir=/stdb publish <database-name> --server http://127.0.0.1:3101 --bin-path spacetime_module.wasm --yes`
- 发布动作默认以 `spacetimedb` 服务用户执行,避免 root 默认 CLI 身份对自托管数据库验签失败,也避免 root 写入 `/stdb/config` 造成后续服务用户启动权限错误。
- 成功后执行必要 smoke test。
- 成功后解除维护模式。
- 失败时保留维护模式并发邮件。
@@ -463,6 +464,7 @@ WASM_SOURCE="${CARGO_TARGET_DIR}/wasm32-unknown-unknown/release/spacetime_module
- 并行执行 Web / API / Stdb 三条构建流水线。
- 并行构建阶段必须开启 fail-fast任一构建流水线失败时立即中断其他仍在执行的并行构建分支本次全量编排不再继续进入发布阶段。
- 构建全部成功后,按顺序执行 Stdb publish、API deploy、Web deploy并把同一个 `DEPLOY_TARGET` 透传给三条发布流水线。
- Stdb publish 同时透传 `SPACETIME_SERVER_URL``SPACETIME_ROOT_DIR``SPACETIME_RUN_AS_USER`,默认分别为 `http://127.0.0.1:3101``/stdb``spacetimedb`
- 每条下游构建都只消费自己的归档产物,不直接复用别的 workspace。
- 生产 Web 发布只处理 `web.tar.gz` 与 checksumAPI 发布只处理 `api-server` 与 checksumStdb 发布只处理 `spacetime_module.wasm` 与 checksum。

View File

@@ -31,6 +31,8 @@ pipeline {
booleanParam(name: 'CONFIRM_RELEASE_DEPLOY_AGENT', defaultValue: false, description: '确认 release 目标已有独立 release 部署 agent当前 Linux 开发/构建/开发部署 agent 不可冒充 release 部署机')
string(name: 'DATABASE', defaultValue: 'genarrative-prod', description: '生产 SpacetimeDB database')
string(name: 'SPACETIME_SERVER_URL', defaultValue: 'http://127.0.0.1:3101', description: 'Stdb 发布目标 URL默认避开本机 Git/Web 使用的 3000 端口')
string(name: 'SPACETIME_ROOT_DIR', defaultValue: '/stdb', description: 'Stdb 发布使用的 spacetime CLI root-dir')
string(name: 'SPACETIME_RUN_AS_USER', defaultValue: 'spacetimedb', description: 'Stdb 发布使用的本机用户')
}
stages {
@@ -136,6 +138,8 @@ pipeline {
string(name: 'NOTIFICATION_EMAILS', value: params.NOTIFICATION_EMAILS ?: ''),
string(name: 'DATABASE', value: params.DATABASE),
string(name: 'SPACETIME_SERVER_URL', value: params.SPACETIME_SERVER_URL ?: ''),
string(name: 'SPACETIME_ROOT_DIR', value: params.SPACETIME_ROOT_DIR ?: '/stdb'),
string(name: 'SPACETIME_RUN_AS_USER', value: params.SPACETIME_RUN_AS_USER ?: 'spacetimedb'),
string(name: 'DEPLOY_TARGET', value: params.DEPLOY_TARGET),
booleanParam(name: 'CONFIRM_RELEASE_DEPLOY_AGENT', value: params.CONFIRM_RELEASE_DEPLOY_AGENT),
string(name: 'BUILD_JOB_NAME', value: params.STDB_BUILD_JOB_NAME),

View File

@@ -23,6 +23,8 @@ pipeline {
string(name: 'DATABASE', defaultValue: 'genarrative-prod', description: '生产 SpacetimeDB database')
string(name: 'SPACETIME_SERVER', defaultValue: 'local', description: 'SpacetimeDB server alias')
string(name: 'SPACETIME_SERVER_URL', defaultValue: 'http://127.0.0.1:3101', description: '显式 SpacetimeDB server URL填写后优先于 SPACETIME_SERVER')
string(name: 'SPACETIME_ROOT_DIR', defaultValue: '/stdb', description: 'spacetime CLI root-dir需与自托管 spacetimedb.service 一致')
string(name: 'SPACETIME_RUN_AS_USER', defaultValue: 'spacetimedb', description: '执行 spacetime publish 的本机用户,默认使用自托管服务用户')
booleanParam(name: 'CLEAR_DATABASE', defaultValue: false, description: '是否清空数据库后发布')
}
@@ -51,6 +53,14 @@ pipeline {
if (!params.SPACETIME_SERVER?.trim() && !params.SPACETIME_SERVER_URL?.trim()) {
error('SPACETIME_SERVER 与 SPACETIME_SERVER_URL 不能同时为空。')
}
def spacetimeRootDir = params.SPACETIME_ROOT_DIR?.trim() ? params.SPACETIME_ROOT_DIR.trim() : '/stdb'
if (!(spacetimeRootDir ==~ /^\/(?!.*\.\.)[A-Za-z0-9._\/-]+$/)) {
error("SPACETIME_ROOT_DIR 必须是 Linux 绝对路径且不能包含 ..: ${spacetimeRootDir}")
}
def spacetimeRunAsUser = params.SPACETIME_RUN_AS_USER?.trim()
if (spacetimeRunAsUser && !(spacetimeRunAsUser ==~ /^[A-Za-z_][A-Za-z0-9_-]*$/)) {
error("SPACETIME_RUN_AS_USER 只能是本机用户名: ${spacetimeRunAsUser}")
}
def spacetimeServerUrl = params.SPACETIME_SERVER_URL?.trim()
if (spacetimeServerUrl && !(spacetimeServerUrl ==~ /^https?:\/\/[A-Za-z0-9._:-]+$/)) {
error("SPACETIME_SERVER_URL 只能是 http(s) URL且不能包含路径或 shell 特殊字符: ${spacetimeServerUrl}")
@@ -111,6 +121,10 @@ pipeline {
steps {
script {
def clearArg = params.CLEAR_DATABASE ? '--clear-database' : ''
def rootArg = "--root-dir \"${params.SPACETIME_ROOT_DIR?.trim() ? params.SPACETIME_ROOT_DIR.trim() : '/stdb'}\""
def runAsArg = params.SPACETIME_RUN_AS_USER?.trim()
? "--run-as-user \"${params.SPACETIME_RUN_AS_USER.trim()}\""
: ''
def serverArg = params.SPACETIME_SERVER_URL?.trim()
? "--server-url \"${params.SPACETIME_SERVER_URL.trim()}\""
: "--server \"${params.SPACETIME_SERVER}\""
@@ -121,6 +135,8 @@ pipeline {
scripts/deploy/production-stdb-publish.sh \\
--source-dir "build/${params.BUILD_VERSION}" \\
--database "${params.DATABASE}" \\
${rootArg} \\
${runAsArg} \\
${serverArg} \\
${clearArg}
'

View File

@@ -5,11 +5,12 @@ set -euo pipefail
usage() {
cat <<'EOF'
用法:
./scripts/deploy/production-stdb-publish.sh --source-dir build/<version> --database <database> [--server-url http://127.0.0.1:3101] [--server local] [--clear-database]
./scripts/deploy/production-stdb-publish.sh --source-dir build/<version> --database <database> [--server-url http://127.0.0.1:3101] [--server local] [--root-dir /stdb] [--run-as-user spacetimedb] [--clear-database]
说明:
进入维护模式,校验 spacetime_module.wasm.sha256并在生产实例本机执行 spacetime publish。
默认使用 http://127.0.0.1:3101避免与部署机本机 Git/Web 服务的 3000 端口冲突。
默认使用 /stdb 作为 spacetime CLI root-dir并以 spacetimedb 用户发布,避免 root CLI 身份污染自托管实例。
失败时保留维护模式。
EOF
}
@@ -38,8 +39,11 @@ SOURCE_DIR=""
DATABASE=""
SERVER_ALIAS="local"
SERVER_URL="http://127.0.0.1:3101"
SPACETIME_ROOT_DIR="/stdb"
RUN_AS_USER="spacetimedb"
CLEAR_DATABASE=0
DEPLOY_COMPLETED=0
PUBLISH_TMP_DIR=""
while [[ $# -gt 0 ]]; do
case "$1" in
@@ -64,6 +68,14 @@ while [[ $# -gt 0 ]]; do
SERVER_URL="${2:?缺少 --server-url 的值}"
shift 2
;;
--root-dir)
SPACETIME_ROOT_DIR="${2:?缺少 --root-dir 的值}"
shift 2
;;
--run-as-user)
RUN_AS_USER="${2:?缺少 --run-as-user 的值}"
shift 2
;;
--clear-database)
CLEAR_DATABASE=1
shift
@@ -80,6 +92,16 @@ require_argument "${SOURCE_DIR}" "--source-dir"
require_argument "${DATABASE}" "--database"
validate_spacetime_database_name "${DATABASE}"
if [[ ! "${SPACETIME_ROOT_DIR}" == /* || "${SPACETIME_ROOT_DIR}" == *".."* ]]; then
echo "[production-stdb-publish] --root-dir 必须是 Linux 绝对路径且不能包含 ..: ${SPACETIME_ROOT_DIR}" >&2
exit 1
fi
if [[ -n "${RUN_AS_USER}" && ! "${RUN_AS_USER}" =~ ^[A-Za-z_][A-Za-z0-9_-]*$ ]]; then
echo "[production-stdb-publish] --run-as-user 只能是本机用户名: ${RUN_AS_USER}" >&2
exit 1
fi
if [[ ! -d "${SOURCE_DIR}" ]]; then
echo "[production-stdb-publish] 发布目录不存在: ${SOURCE_DIR}" >&2
exit 1
@@ -94,6 +116,9 @@ fi
on_exit() {
local exit_code=$?
if [[ -n "${PUBLISH_TMP_DIR}" && -d "${PUBLISH_TMP_DIR}" ]]; then
rm -rf "${PUBLISH_TMP_DIR}"
fi
if [[ "${exit_code}" -ne 0 && "${DEPLOY_COMPLETED}" -ne 1 ]]; then
echo "[production-stdb-publish] 发布失败,保持维护模式。" >&2
fi
@@ -111,6 +136,7 @@ echo "[production-stdb-publish] 校验 wasm"
)
PUBLISH_ARGS=(
--root-dir="${SPACETIME_ROOT_DIR}"
publish
"${DATABASE}"
--bin-path "${SOURCE_DIR}/spacetime_module.wasm"
@@ -128,11 +154,38 @@ if [[ "${CLEAR_DATABASE}" -eq 1 ]]; then
fi
if [[ -n "${SERVER_URL}" ]]; then
echo "[production-stdb-publish] 发布 SpacetimeDB module: ${DATABASE} -> ${SERVER_URL}"
echo "[production-stdb-publish] 发布 SpacetimeDB module: ${DATABASE} -> ${SERVER_URL}, root=${SPACETIME_ROOT_DIR}"
else
echo "[production-stdb-publish] 发布 SpacetimeDB module: ${DATABASE} -> ${SERVER_ALIAS}"
echo "[production-stdb-publish] 发布 SpacetimeDB module: ${DATABASE} -> ${SERVER_ALIAS}, root=${SPACETIME_ROOT_DIR}"
fi
if [[ -n "${RUN_AS_USER}" && "$(id -u)" -eq 0 ]]; then
if ! id "${RUN_AS_USER}" >/dev/null 2>&1; then
echo "[production-stdb-publish] 发布用户不存在: ${RUN_AS_USER}" >&2
exit 1
fi
PUBLISH_TMP_DIR="$(mktemp -d /tmp/genarrative-stdb-publish.XXXXXX)"
install -m 0644 "${SOURCE_DIR}/spacetime_module.wasm" "${PUBLISH_TMP_DIR}/spacetime_module.wasm"
chown -R "${RUN_AS_USER}:${RUN_AS_USER}" "${PUBLISH_TMP_DIR}"
PUBLISH_ARGS=(
--root-dir="${SPACETIME_ROOT_DIR}"
publish
"${DATABASE}"
--bin-path "${PUBLISH_TMP_DIR}/spacetime_module.wasm"
--yes
)
if [[ -n "${SERVER_URL}" ]]; then
PUBLISH_ARGS+=(--server "${SERVER_URL}")
else
PUBLISH_ARGS+=(--server "${SERVER_ALIAS}")
fi
if [[ "${CLEAR_DATABASE}" -eq 1 ]]; then
PUBLISH_ARGS+=(--clear-database)
fi
runuser -u "${RUN_AS_USER}" -- spacetime "${PUBLISH_ARGS[@]}"
else
spacetime "${PUBLISH_ARGS[@]}"
fi
spacetime "${PUBLISH_ARGS[@]}"
"${SCRIPT_DIR}/maintenance-off.sh"
DEPLOY_COMPLETED=1