Install production build toolchain in provision

This commit is contained in:
2026-05-02 22:10:01 +08:00
parent 73d5ef40ed
commit ace13c7047
5 changed files with 38 additions and 3 deletions

View File

@@ -323,6 +323,8 @@ Rust 构建流水线还必须在真正执行 `cargo` 前 source `scripts/jenkins
`server-rs/.cargo/config.toml` 只保留 Linux release 目标的 linker/rustflags 等仓库级构建配置,不在仓库级 `config.toml` 里重定义 agent 全局镜像源。不要把这些约束写到单个 crate 的 `Cargo.toml`,因为 Cargo 不会从 crate manifest 的 `[target.x86_64-unknown-linux-gnu]` 读取构建器配置。 `server-rs/.cargo/config.toml` 只保留 Linux release 目标的 linker/rustflags 等仓库级构建配置,不在仓库级 `config.toml` 里重定义 agent 全局镜像源。不要把这些约束写到单个 crate 的 `Cargo.toml`,因为 Cargo 不会从 crate manifest 的 `[target.x86_64-unknown-linux-gnu]` 读取构建器配置。
由于 `server-rs/.cargo/config.toml` 使用 `clang``-fuse-ld=lld` 构建 Linux release 目标,构建 agent 必须安装 `clang``lld``Genarrative-Server-Provision` 负责通过 `apt-get``dnf``yum` 安装 `clang``lld``pkg-config/pkgconf-pkg-config`、OpenSSL headers 与 CA 证书API/Stdb 构建流水线在执行 Cargo 前必须检查 `clang``lld`,缺失时直接失败并提示先运行 Server-Provision。
`scripts/build-production-release.sh` 必须尊重 `CARGO_TARGET_DIR`,不能硬编码从 `server-rs/target/` 拷贝 Rust 产物。脚本中的产物路径应按以下口径计算: `scripts/build-production-release.sh` 必须尊重 `CARGO_TARGET_DIR`,不能硬编码从 `server-rs/target/` 拷贝 Rust 产物。脚本中的产物路径应按以下口径计算:
```bash ```bash
@@ -379,13 +381,13 @@ WASM_SOURCE="${CARGO_TARGET_DIR}/wasm32-unknown-unknown/release/spacetime_module
- 安装或更新 SpacetimeDB。 - 安装或更新 SpacetimeDB。
- 安装 systemd unit。 - 安装 systemd unit。
- 可选安装 Nginx 配置和维护模式 snippet。 - 可选安装 Nginx 配置和维护模式 snippet。
- 安装 Nginx 配置时执行 `nginx -t` - 安装 Nginx 配置时执行 `nginx -t`,通过后必须执行 `nginx -s reload`,确保新配置对当前 Nginx master/worker 生效
- 启用并启动 `spacetimedb.service``genarrative-api.service` - 启用并启动 `spacetimedb.service``genarrative-api.service`
该流水线属于高风险操作,默认要求人工确认后执行。 该流水线属于高风险操作,默认要求人工确认后执行。
已落地的 Jenkinsfile 为 `jenkins/Jenkinsfile.production-server-provision`。该流水线默认 `DRY_RUN=true`只打印将执行的初始化动作真正写入系统用户、目录、systemd、环境文件并启动服务时必须设置 `DRY_RUN=false` 且勾选 `CONFIRM_PROVISION`。当 `DEPLOY_TARGET=release` 时,还必须勾选 `CONFIRM_RELEASE_DEPLOY_AGENT`,并通过 `linux && genarrative-release-deploy` 调度到独立 release 部署 agent。 已落地的 Jenkinsfile 为 `jenkins/Jenkinsfile.production-server-provision`。该流水线默认 `DRY_RUN=true`只打印将执行的初始化动作真正写入系统用户、目录、systemd、环境文件并启动服务时必须设置 `DRY_RUN=false` 且勾选 `CONFIRM_PROVISION`。当 `DEPLOY_TARGET=release` 时,还必须勾选 `CONFIRM_RELEASE_DEPLOY_AGENT`,并通过 `linux && genarrative-release-deploy` 调度到独立 release 部署 agent。
首次真实初始化默认保持 `NGINX_CONFIG_MODE=none`先完成系统用户、目录、SpacetimeDB、systemd unit 与 `/etc/genarrative/api-server.env` 落盘。开发服没有域名时,使用 `DEPLOY_TARGET=development` + `NGINX_CONFIG_MODE=development-http` 安装 `deploy/nginx/genarrative-dev-http.conf`,并把 `SERVER_NAME` 填为开发机 IP 或临时主机名。等正式域名确定,并且目标机已经存在 `/etc/letsencrypt/live/<SERVER_NAME>/fullchain.pem``/etc/letsencrypt/live/<SERVER_NAME>/privkey.pem` 后,再把 `SERVER_NAME` 改成真实域名,并设置 `NGINX_CONFIG_MODE=production-https` 安装 Nginx HTTPS 配置。流水线会拒绝 release 目标安装 `development-http`,也会拒绝用占位域名或缺失证书安装 `production-https` 首次真实初始化默认保持 `NGINX_CONFIG_MODE=none`先完成系统用户、目录、SpacetimeDB、systemd unit 与 `/etc/genarrative/api-server.env` 落盘。开发服没有域名时,使用 `DEPLOY_TARGET=development` + `NGINX_CONFIG_MODE=development-http` 安装 `deploy/nginx/genarrative-dev-http.conf`,并把 `SERVER_NAME` 填为开发机 IP 或临时主机名。等正式域名确定,并且目标机已经存在 `/etc/letsencrypt/live/<SERVER_NAME>/fullchain.pem``/etc/letsencrypt/live/<SERVER_NAME>/privkey.pem` 后,再把 `SERVER_NAME` 改成真实域名,并设置 `NGINX_CONFIG_MODE=production-https` 安装 Nginx HTTPS 配置。流水线会拒绝 release 目标安装 `development-http`,也会拒绝用占位域名或缺失证书安装 `production-https`Nginx 配置写入后必须先 `nginx -t`,再 `nginx -s reload`,不能只验证配置而不重载当前进程。
若误用占位域名执行过真实初始化,失败通常发生在 `nginx -t`,错误表现为找不到 `/etc/letsencrypt/live/genarrative.example.com/fullchain.pem``privkey.pem`。新版初始化在 `NGINX_CONFIG_MODE=none` 时会检测并禁用上一轮留下的占位域名 Nginx 配置,避免它继续影响后续 `nginx -t` 若误用占位域名执行过真实初始化,失败通常发生在 `nginx -t`,错误表现为找不到 `/etc/letsencrypt/live/genarrative.example.com/fullchain.pem``privkey.pem`。新版初始化在 `NGINX_CONFIG_MODE=none` 时会检测并禁用上一轮留下的占位域名 Nginx 配置,避免它继续影响后续 `nginx -t`
@@ -450,6 +452,7 @@ WASM_SOURCE="${CARGO_TARGET_DIR}/wasm32-unknown-unknown/release/spacetime_module
- 先解析一次最终 `SOURCE_COMMIT`,所有下游构建和发布都使用同一个分支与 commit。 - 先解析一次最终 `SOURCE_COMMIT`,所有下游构建和发布都使用同一个分支与 commit。
- 并行执行 Web / API / Stdb 三条构建流水线。 - 并行执行 Web / API / Stdb 三条构建流水线。
- 并行构建阶段必须开启 fail-fast任一构建流水线失败时立即中断其他仍在执行的并行构建分支本次全量编排不再继续进入发布阶段。
- 构建全部成功后,按顺序执行 Stdb publish、API deploy、Web deploy并把同一个 `DEPLOY_TARGET` 透传给三条发布流水线。 - 构建全部成功后,按顺序执行 Stdb publish、API deploy、Web deploy并把同一个 `DEPLOY_TARGET` 透传给三条发布流水线。
- 每条下游构建都只消费自己的归档产物,不直接复用别的 workspace。 - 每条下游构建都只消费自己的归档产物,不直接复用别的 workspace。
- 生产 Web 发布只处理 `web.tar.gz` 与 checksumAPI 发布只处理 `api-server` 与 checksumStdb 发布只处理 `spacetime_module.wasm` 与 checksum。 - 生产 Web 发布只处理 `web.tar.gz` 与 checksumAPI 发布只处理 `api-server` 与 checksumStdb 发布只处理 `spacetime_module.wasm` 与 checksum。
@@ -497,7 +500,7 @@ WASM_SOURCE="${CARGO_TARGET_DIR}/wasm32-unknown-unknown/release/spacetime_module
`Genarrative-Full-Build-And-Deploy` 编排: `Genarrative-Full-Build-And-Deploy` 编排:
1.`SOURCE_BRANCH` / `COMMIT_HASH` 解析一次最终 `SOURCE_COMMIT`,默认 `origin/master` 最新 commit。 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` 2. 并行触发 `Genarrative-Web-Build``Genarrative-Api-Build``Genarrative-Stdb-Module-Build`,三条构建都必须使用同一个 `SOURCE_BRANCH``SOURCE_COMMIT`;并行阶段开启 fail-fast任一构建失败就中断其他仍在执行的构建分支
3. 三条构建全部成功后,按顺序触发 `Genarrative-Stdb-Module-Publish``Genarrative-Api-Deploy``Genarrative-Web-Deploy`,同样继续透传同一个 `SOURCE_BRANCH``SOURCE_COMMIT``DEPLOY_TARGET` 3. 三条构建全部成功后,按顺序触发 `Genarrative-Stdb-Module-Publish``Genarrative-Api-Deploy``Genarrative-Web-Deploy`,同样继续透传同一个 `SOURCE_BRANCH``SOURCE_COMMIT``DEPLOY_TARGET`
4. 最后执行生产 smoke test。 4. 最后执行生产 smoke test。

View File

@@ -64,6 +64,10 @@ pipeline {
set -euo pipefail set -euo pipefail
chmod +x scripts/jenkins-prepare-cargo-env.sh chmod +x scripts/jenkins-prepare-cargo-env.sh
source scripts/jenkins-prepare-cargo-env.sh source scripts/jenkins-prepare-cargo-env.sh
if ! command -v clang >/dev/null 2>&1 || ! command -v lld >/dev/null 2>&1; then
echo "[api-build] 缺少 clang/lld。请先运行 Genarrative-Server-Provision 安装 Linux 构建依赖。" >&2
exit 1
fi
if ! command -v sccache >/dev/null 2>&1; then if ! command -v sccache >/dev/null 2>&1; then
echo "[api-build] 未找到 sccache改用 rustc 直接构建。" echo "[api-build] 未找到 sccache改用 rustc 直接构建。"
unset RUSTC_WRAPPER unset RUSTC_WRAPPER

View File

@@ -66,6 +66,8 @@ pipeline {
} }
stage('Build Components') { stage('Build Components') {
// 任一构建分支失败时立即中断其他并行分支,避免失败后继续消耗构建资源。
failFast true
parallel { parallel {
stage('Web') { stage('Web') {
steps { steps {

View File

@@ -123,6 +123,21 @@ pipeline {
fi fi
} }
install_build_dependencies() {
echo "[server-provision] 安装 Linux 构建依赖: clang, lld, pkg-config, OpenSSL headers"
if command -v apt-get >/dev/null 2>&1; then
run_cmd apt-get update
run_cmd apt-get install -y clang lld pkg-config libssl-dev ca-certificates
elif command -v dnf >/dev/null 2>&1; then
run_cmd dnf install -y clang lld pkgconf-pkg-config openssl-devel ca-certificates
elif command -v yum >/dev/null 2>&1; then
run_cmd yum install -y clang lld pkgconf-pkg-config openssl-devel ca-certificates
else
echo "[server-provision] 未找到 apt-get/dnf/yum无法自动安装 clang/lld。请手动安装后重跑构建。" >&2
exit 1
fi
}
render_nginx_https_config() { render_nginx_https_config() {
sed "s/genarrative.example.com/${SERVER_NAME}/g" deploy/nginx/genarrative.conf sed "s/genarrative.example.com/${SERVER_NAME}/g" deploy/nginx/genarrative.conf
} }
@@ -174,6 +189,7 @@ pipeline {
if [[ "${DRY_RUN}" == "true" ]]; then if [[ "${DRY_RUN}" == "true" ]]; then
echo "+ nginx -t" echo "+ nginx -t"
echo "+ nginx -s reload"
return return
fi fi
@@ -216,6 +232,8 @@ pipeline {
rm -f "${rendered_config}" "${rendered_snippet}" "${config_backup}" "${snippet_backup}" rm -f "${rendered_config}" "${rendered_snippet}" "${config_backup}" "${snippet_backup}"
exit 1 exit 1
fi fi
echo "+ nginx -s reload"
nginx -s reload
rm -f "${rendered_config}" "${rendered_snippet}" "${config_backup}" "${snippet_backup}" rm -f "${rendered_config}" "${rendered_snippet}" "${config_backup}" "${snippet_backup}"
} }
@@ -239,6 +257,9 @@ pipeline {
if command -v nginx >/dev/null 2>&1; then if command -v nginx >/dev/null 2>&1; then
if ! nginx -t; then if ! nginx -t; then
echo "[server-provision] 占位配置已禁用,但 nginx -t 仍失败;请检查其他 Nginx 配置。" >&2 echo "[server-provision] 占位配置已禁用,但 nginx -t 仍失败;请检查其他 Nginx 配置。" >&2
else
echo "+ nginx -s reload"
nginx -s reload
fi fi
fi fi
fi fi
@@ -279,6 +300,7 @@ pipeline {
echo "[server-provision] target=${DEPLOY_TARGET}, dry_run=${DRY_RUN}, nginx_config_mode=${NGINX_CONFIG_MODE}, source_commit=$(cat .jenkins-source-commit)" echo "[server-provision] target=${DEPLOY_TARGET}, dry_run=${DRY_RUN}, nginx_config_mode=${NGINX_CONFIG_MODE}, source_commit=$(cat .jenkins-source-commit)"
run_cmd id run_cmd id
install_build_dependencies
run_cmd mkdir -p "${SPACETIME_ROOT}" "${RELEASE_ROOT}" "$(dirname "${CURRENT_LINK}")" "$(dirname "${WEB_LINK}")" /etc/genarrative /var/lib/genarrative/maintenance /var/lib/genarrative/auth run_cmd mkdir -p "${SPACETIME_ROOT}" "${RELEASE_ROOT}" "$(dirname "${CURRENT_LINK}")" "$(dirname "${WEB_LINK}")" /etc/genarrative /var/lib/genarrative/maintenance /var/lib/genarrative/auth
if ! id spacetimedb >/dev/null 2>&1; then if ! id spacetimedb >/dev/null 2>&1; then

View File

@@ -65,6 +65,10 @@ pipeline {
set -euo pipefail set -euo pipefail
chmod +x scripts/jenkins-prepare-cargo-env.sh chmod +x scripts/jenkins-prepare-cargo-env.sh
source scripts/jenkins-prepare-cargo-env.sh source scripts/jenkins-prepare-cargo-env.sh
if ! command -v clang >/dev/null 2>&1 || ! command -v lld >/dev/null 2>&1; then
echo "[stdb-build] 缺少 clang/lld。请先运行 Genarrative-Server-Provision 安装 Linux 构建依赖。" >&2
exit 1
fi
if ! command -v sccache >/dev/null 2>&1; then if ! command -v sccache >/dev/null 2>&1; then
echo "[stdb-build] 未找到 sccache改用 rustc 直接构建。" echo "[stdb-build] 未找到 sccache改用 rustc 直接构建。"
unset RUSTC_WRAPPER unset RUSTC_WRAPPER