feat(deploy): prepare offline provision tools and container loadtest
This commit is contained in:
@@ -89,7 +89,7 @@ function printHelp(isError) {
|
||||
Commands:
|
||||
container:init 生成 deploy/container/api-server.env
|
||||
container:build 构建 api-server 容器镜像
|
||||
container:up 后台启动 api-server + nginx + otelcol
|
||||
container:up 后台启动 spacetimedb + api-server + nginx + otelcol
|
||||
container:down 停止并清理容器
|
||||
container:logs 查看容器日志
|
||||
container:ps 查看容器状态
|
||||
|
||||
@@ -1,6 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROVISION_TOOLS_DIR="${PROVISION_TOOLS_DIR:-provision-tools}"
|
||||
SPACETIME_BIN_SOURCE="${SPACETIME_BIN_SOURCE:-${PROVISION_TOOLS_DIR}/spacetime/spacetime}"
|
||||
OTELCOL_BIN_SOURCE="${OTELCOL_BIN_SOURCE:-${PROVISION_TOOLS_DIR}/otelcol-contrib}"
|
||||
|
||||
require_non_root_relative_path() {
|
||||
local label="$1"
|
||||
local path="$2"
|
||||
|
||||
if [[ -z "${path}" ]]; then
|
||||
echo "[server-provision] ${label} 不能为空。" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${path}" == /* || "${path}" == *..* ]]; then
|
||||
echo "[server-provision] ${label} 只能是工作区内的相对路径: ${path}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_path() {
|
||||
local path="$1"
|
||||
if [[ ! -e "${path}" ]]; then
|
||||
@@ -81,16 +99,16 @@ install_sccache() {
|
||||
fi
|
||||
|
||||
echo "[server-provision] 未找到 sccache,准备通过 cargo install sccache 安装。"
|
||||
if ! command -v cargo >/dev/null 2>&1; then
|
||||
echo "[server-provision] 未找到 cargo,无法自动安装 sccache。请先安装 Rust 工具链后重跑 Server-Provision。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${DRY_RUN}" == "true" ]]; then
|
||||
echo "+ cargo install sccache --locked"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! command -v cargo >/dev/null 2>&1; then
|
||||
echo "[server-provision] 未找到 cargo,无法自动安装 sccache。请先安装 Rust 工具链后重跑 Server-Provision。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cargo install sccache --locked
|
||||
if ! command -v sccache >/dev/null 2>&1 && [[ ! -x /root/.cargo/bin/sccache ]]; then
|
||||
echo "[server-provision] sccache 安装后仍不可用,请检查 cargo bin 目录是否在 PATH 中。" >&2
|
||||
@@ -98,6 +116,42 @@ install_sccache() {
|
||||
fi
|
||||
}
|
||||
|
||||
sync_otelcol_install() {
|
||||
local target_bin="/usr/local/bin/otelcol-contrib"
|
||||
local source_bin="${OTELCOL_BIN_SOURCE}"
|
||||
local version="${OTELCOL_VERSION:-0.151.0}"
|
||||
local resolved_source="${source_bin}"
|
||||
|
||||
if [[ "${ENABLE_OTELCOL:-true}" != "true" ]]; then
|
||||
echo "[server-provision] ENABLE_OTELCOL=${ENABLE_OTELCOL:-},跳过 otelcol-contrib 配置。"
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v readlink >/dev/null 2>&1; then
|
||||
resolved_source="$(readlink -f "${source_bin}" 2>/dev/null || echo "${source_bin}")"
|
||||
fi
|
||||
|
||||
if [[ ! -x "${resolved_source}" ]]; then
|
||||
echo "[server-provision] otelcol-contrib 不存在或不可执行: ${source_bin}" >&2
|
||||
echo "[server-provision] 请先在构建机准备好 otelcol-contrib ${version},再通过 provision-tools 上传到目标机。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${DRY_RUN}" == "true" ]]; then
|
||||
echo "+ install -m 0755 ${resolved_source} ${target_bin}"
|
||||
return
|
||||
fi
|
||||
|
||||
install -m 0755 "${resolved_source}" "${target_bin}"
|
||||
if ! "${target_bin}" --version >/dev/null 2>&1; then
|
||||
echo "[server-provision] otelcol-contrib 安装后无法执行: ${target_bin}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! "${target_bin}" --version 2>/dev/null | grep -q "${version}"; then
|
||||
echo "[server-provision] 警告: otelcol-contrib 版本不是期望的 ${version}: $("${target_bin}" --version 2>/dev/null || true)" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
sync_spacetime_install() {
|
||||
local root_dir="$1"
|
||||
local target_bin_dir="${root_dir}/bin/current"
|
||||
@@ -106,14 +160,6 @@ sync_spacetime_install() {
|
||||
local resolved_command="${SPACETIME_BIN_SOURCE}"
|
||||
local install_dir=""
|
||||
local root_bin="${root_dir}/bin"
|
||||
local share_bin_dir=""
|
||||
local version_dir=""
|
||||
local parent_dir=""
|
||||
|
||||
if [[ -x "${target_cli}" && -x "${target_standalone}" ]]; then
|
||||
echo "[server-provision] SpacetimeDB current 目录已存在: ${target_bin_dir}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "[server-provision] 同步 SpacetimeDB current 目录到 ${target_bin_dir}"
|
||||
if [[ "${DRY_RUN}" == "true" ]]; then
|
||||
@@ -128,26 +174,10 @@ sync_spacetime_install() {
|
||||
install_dir="$(cd -- "$(dirname -- "${resolved_command}")" && pwd)"
|
||||
mkdir -p "${root_bin}"
|
||||
|
||||
for share_bin_dir in \
|
||||
"/usr/.local/share/spacetime/bin" \
|
||||
"/root/.local/share/spacetime/bin" \
|
||||
"${HOME:-}/.local/share/spacetime/bin"; do
|
||||
if [[ -d "${share_bin_dir}" ]]; then
|
||||
version_dir="$(find "${share_bin_dir}" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -n 1)"
|
||||
if [[ -n "${version_dir}" && -x "${version_dir}/spacetimedb-cli" && -x "${version_dir}/spacetimedb-standalone" ]]; then
|
||||
echo "[server-provision] 同步 SpacetimeDB 安装: ${version_dir} -> ${target_bin_dir}"
|
||||
rm -rf "${target_bin_dir}"
|
||||
mkdir -p "${target_bin_dir}"
|
||||
cp -a "${version_dir}/." "${target_bin_dir}/"
|
||||
chmod +x "${target_cli}" "${target_standalone}"
|
||||
chown -R spacetimedb:spacetimedb "${root_bin}"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -d "${install_dir}/bin" ]]; then
|
||||
echo "[server-provision] 同步 SpacetimeDB 安装: ${install_dir}/bin -> ${root_bin}"
|
||||
rm -rf "${root_bin}"
|
||||
mkdir -p "${root_bin}"
|
||||
cp -a "${install_dir}/bin/." "${root_bin}/"
|
||||
elif [[ -x "${install_dir}/spacetimedb-cli" && -x "${install_dir}/spacetimedb-standalone" ]]; then
|
||||
echo "[server-provision] 同步 SpacetimeDB 安装: ${install_dir} -> ${target_bin_dir}"
|
||||
@@ -156,14 +186,8 @@ sync_spacetime_install() {
|
||||
cp -f "${install_dir}/spacetimedb-cli" "${target_cli}"
|
||||
cp -f "${install_dir}/spacetimedb-standalone" "${target_standalone}"
|
||||
chmod +x "${target_cli}" "${target_standalone}"
|
||||
elif [[ -f "${resolved_command}" ]]; then
|
||||
parent_dir="$(cd -- "${install_dir}/.." && pwd)"
|
||||
if [[ -d "${parent_dir}/bin" && -x "${parent_dir}/bin/current/spacetimedb-cli" && -x "${parent_dir}/bin/current/spacetimedb-standalone" ]]; then
|
||||
echo "[server-provision] 同步 SpacetimeDB 安装: ${parent_dir}/bin -> ${root_bin}"
|
||||
cp -a "${parent_dir}/bin/." "${root_bin}/"
|
||||
else
|
||||
echo "[server-provision] 未能从 spacetime 命令路径推断完整 SpacetimeDB 安装目录: ${resolved_command}" >&2
|
||||
fi
|
||||
else
|
||||
echo "[server-provision] 未能从 SpacetimeDB 交付包推断完整安装目录: ${resolved_command}" >&2
|
||||
fi
|
||||
|
||||
if [[ ! -x "${target_cli}" || ! -x "${target_standalone}" ]]; then
|
||||
@@ -387,6 +411,10 @@ render_api_env_example() {
|
||||
deploy/env/api-server.env.example
|
||||
}
|
||||
|
||||
render_otelcol_service() {
|
||||
cat deploy/systemd/otelcol-contrib.service
|
||||
}
|
||||
|
||||
validate_nginx_tls() {
|
||||
local cert_dir="/etc/letsencrypt/live/${SERVER_NAME}"
|
||||
if [[ "${SERVER_NAME}" == "genarrative.example.com" ]]; then
|
||||
@@ -523,6 +551,8 @@ render_api_service() {
|
||||
|
||||
require_path deploy/systemd/spacetimedb.service
|
||||
require_path deploy/systemd/genarrative-api.service
|
||||
require_path deploy/systemd/otelcol-contrib.service
|
||||
require_path deploy/otelcol/genarrative-debug.yaml
|
||||
require_path deploy/nginx/genarrative.conf
|
||||
require_path deploy/nginx/genarrative-dev-http.conf
|
||||
require_path deploy/nginx/snippets/genarrative-maintenance.conf
|
||||
@@ -532,6 +562,7 @@ require_path scripts/deploy/maintenance-off.sh
|
||||
require_path scripts/deploy/maintenance-status.sh
|
||||
|
||||
validate_server_names
|
||||
require_non_root_relative_path "PROVISION_TOOLS_DIR" "${PROVISION_TOOLS_DIR}"
|
||||
|
||||
echo "[server-provision] target=${DEPLOY_TARGET}, dry_run=${DRY_RUN}, nginx_config_mode=${NGINX_CONFIG_MODE}, source_commit=$(cat .jenkins-source-commit)"
|
||||
|
||||
@@ -585,6 +616,16 @@ else
|
||||
echo "[server-provision] 已存在环境文件,保留不覆盖: ${API_ENV_FILE}"
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_OTELCOL:-true}" == "true" ]]; then
|
||||
sync_otelcol_install
|
||||
otelcol_service="$(mktemp)"
|
||||
render_otelcol_service >"${otelcol_service}"
|
||||
install_file "${otelcol_service}" /etc/systemd/system/otelcol-contrib.service 0644
|
||||
rm -f "${otelcol_service}"
|
||||
else
|
||||
echo "[server-provision] ENABLE_OTELCOL=${ENABLE_OTELCOL:-},跳过 otelcol-contrib service 安装。"
|
||||
fi
|
||||
|
||||
if [[ "${NGINX_CONFIG_MODE}" != "none" ]]; then
|
||||
install_nginx_config_with_rollback
|
||||
else
|
||||
@@ -593,7 +634,13 @@ fi
|
||||
|
||||
run_cmd systemctl daemon-reload
|
||||
if [[ "${ENABLE_SERVICES}" == "true" ]]; then
|
||||
if [[ "${ENABLE_OTELCOL:-true}" == "true" ]]; then
|
||||
run_cmd systemctl enable otelcol-contrib.service
|
||||
fi
|
||||
run_cmd systemctl enable spacetimedb.service genarrative-api.service
|
||||
if [[ "${ENABLE_OTELCOL:-true}" == "true" ]]; then
|
||||
run_cmd systemctl restart otelcol-contrib.service
|
||||
fi
|
||||
run_cmd systemctl restart spacetimedb.service
|
||||
wait_for_spacetimedb_service
|
||||
ensure_spacetime_owner_client_token
|
||||
|
||||
132
scripts/prepare-server-provision-tools.sh
Normal file
132
scripts/prepare-server-provision-tools.sh
Normal file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
PROVISION_TOOLS_DIR="${PROVISION_TOOLS_DIR:-provision-tools}"
|
||||
OTELCOL_VERSION="${OTELCOL_VERSION:-0.151.0}"
|
||||
OTELCOL_DOWNLOAD_ROOT="${OTELCOL_DOWNLOAD_ROOT:-https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download}"
|
||||
SPACETIME_INSTALLER_URL="${SPACETIME_INSTALLER_URL:-https://install.spacetimedb.com}"
|
||||
SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/latest/download}"
|
||||
PROVISION_TOOLS_TMP_PARENT="${PROVISION_TOOLS_TMP_PARENT:-${WORKSPACE:-$(pwd)}/.tmp/server-provision-tools}"
|
||||
TMP_DIR_TO_CLEAN=""
|
||||
|
||||
cleanup_tmp_dir() {
|
||||
if [[ -n "${TMP_DIR_TO_CLEAN}" ]]; then
|
||||
rm -rf "${TMP_DIR_TO_CLEAN}"
|
||||
fi
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
local name="$1"
|
||||
if ! command -v "${name}" >/dev/null 2>&1; then
|
||||
echo "[prepare-provision-tools] 缺少命令: ${name}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
download_file() {
|
||||
local url="$1"
|
||||
local output="$2"
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL --retry 3 --retry-delay 2 "${url}" -o "${output}"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -O "${output}" "${url}"
|
||||
else
|
||||
echo "[prepare-provision-tools] 需要 curl 或 wget 下载: ${url}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
make_spacetime_wrapper() {
|
||||
local target="$1"
|
||||
|
||||
cat >"${target}" <<'EOF'
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
SELF_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
exec "$SELF_DIR/bin/current/spacetimedb-cli" "$@"
|
||||
EOF
|
||||
chmod 0755 "${target}"
|
||||
}
|
||||
|
||||
prepare_otelcol() {
|
||||
local tmp_dir="$1"
|
||||
local archive="${tmp_dir}/otelcol-contrib.tar.gz"
|
||||
local extract_dir="${tmp_dir}/otelcol-contrib"
|
||||
local url="${OTELCOL_DOWNLOAD_ROOT}/v${OTELCOL_VERSION}/otelcol-contrib_${OTELCOL_VERSION}_linux_amd64.tar.gz"
|
||||
local target="${PROVISION_TOOLS_DIR}/otelcol-contrib"
|
||||
|
||||
require_cmd tar
|
||||
|
||||
echo "[prepare-provision-tools] 下载 otelcol-contrib: ${url}"
|
||||
mkdir -p "${extract_dir}"
|
||||
download_file "${url}" "${archive}"
|
||||
tar -xzf "${archive}" -C "${extract_dir}"
|
||||
|
||||
if [[ ! -x "${extract_dir}/otelcol-contrib" ]]; then
|
||||
echo "[prepare-provision-tools] otelcol-contrib 包中缺少可执行文件。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install -m 0755 "${extract_dir}/otelcol-contrib" "${target}"
|
||||
"${target}" --version >/dev/null
|
||||
}
|
||||
|
||||
prepare_spacetime() {
|
||||
local tmp_dir="$1"
|
||||
local install_root="${tmp_dir}/spacetime-root"
|
||||
local target_dir="${PROVISION_TOOLS_DIR}/spacetime"
|
||||
|
||||
echo "[prepare-provision-tools] 使用官方安装器准备 SpacetimeDB: ${SPACETIME_INSTALLER_URL}"
|
||||
mkdir -p "${install_root}"
|
||||
download_file "${SPACETIME_INSTALLER_URL}" "${tmp_dir}/spacetime-install.sh"
|
||||
chmod 0755 "${tmp_dir}/spacetime-install.sh"
|
||||
TMPDIR="${tmp_dir}" SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT}" sh "${tmp_dir}/spacetime-install.sh" --root-dir "${install_root}" -y
|
||||
|
||||
if [[ ! -x "${install_root}/bin/current/spacetimedb-cli" ]]; then
|
||||
echo "[prepare-provision-tools] SpacetimeDB 安装结果缺少 bin/current/spacetimedb-cli。" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -x "${install_root}/bin/current/spacetimedb-standalone" ]]; then
|
||||
echo "[prepare-provision-tools] SpacetimeDB 安装结果缺少 bin/current/spacetimedb-standalone。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${target_dir}"
|
||||
cp -a "${install_root}/bin" "${target_dir}/bin"
|
||||
make_spacetime_wrapper "${target_dir}/spacetime"
|
||||
|
||||
"${target_dir}/spacetime" --version >/dev/null
|
||||
}
|
||||
|
||||
main() {
|
||||
local tmp_dir
|
||||
|
||||
require_cmd chmod
|
||||
require_cmd cp
|
||||
require_cmd install
|
||||
require_cmd mktemp
|
||||
require_cmd rm
|
||||
|
||||
mkdir -p "${PROVISION_TOOLS_TMP_PARENT}"
|
||||
tmp_dir="$(mktemp -d "${PROVISION_TOOLS_TMP_PARENT%/}/run.XXXXXX")"
|
||||
TMP_DIR_TO_CLEAN="${tmp_dir}"
|
||||
trap cleanup_tmp_dir EXIT
|
||||
|
||||
rm -rf "${PROVISION_TOOLS_DIR}"
|
||||
mkdir -p "${PROVISION_TOOLS_DIR}"
|
||||
|
||||
prepare_otelcol "${tmp_dir}"
|
||||
prepare_spacetime "${tmp_dir}"
|
||||
|
||||
cat >"${PROVISION_TOOLS_DIR}/MANIFEST.txt" <<EOF
|
||||
otelcol-contrib ${OTELCOL_VERSION}
|
||||
spacetime installer ${SPACETIME_INSTALLER_URL}
|
||||
spacetime download root ${SPACETIME_DOWNLOAD_ROOT}
|
||||
EOF
|
||||
|
||||
echo "[prepare-provision-tools] 工具包已准备: ${PROVISION_TOOLS_DIR}"
|
||||
find "${PROVISION_TOOLS_DIR}" -maxdepth 5 \( -type f -o -type l \) | sort
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user