Install production build toolchain in provision
This commit is contained in:
@@ -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` 与 checksum,API 发布只处理 `api-server` 与 checksum,Stdb 发布只处理 `spacetime_module.wasm` 与 checksum。
|
- 生产 Web 发布只处理 `web.tar.gz` 与 checksum,API 发布只处理 `api-server` 与 checksum,Stdb 发布只处理 `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。
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ pipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stage('Build Components') {
|
stage('Build Components') {
|
||||||
|
// 任一构建分支失败时立即中断其他并行分支,避免失败后继续消耗构建资源。
|
||||||
|
failFast true
|
||||||
parallel {
|
parallel {
|
||||||
stage('Web') {
|
stage('Web') {
|
||||||
steps {
|
steps {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user