#!/usr/bin/env bash # deploy_crm_only.sh — 把 sub2api-cn-relay-manager(CRM 控制面)单进程部署到 # remote43。不起 sub2api host / PG / Redis 容器。 # # 复用 scripts/deploy/remote43_patched_stack_lib.sh 的 env 渲染 helper。 set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" # shellcheck disable=SC1091 source "$ROOT_DIR/scripts/deploy/remote43_patched_stack_lib.sh" KEY="${KEY:-/home/long/下载/zjsea.pem}" REMOTE="${REMOTE:-ubuntu@43.155.133.187}" STACK_NAME="${STACK_NAME:-crm-only-$(date +%Y%m%d)}" CRM_PORT="${CRM_PORT:-18190}" CRM_BINARY="${CRM_BINARY:-$ROOT_DIR/server}" LOCAL_REPO_BUNDLE="${LOCAL_REPO_BUNDLE:-/tmp/${STACK_NAME}-repo.bundle}" LOCAL_OPERATOR_ENV_FILE="${LOCAL_OPERATOR_ENV_FILE:-/tmp/${STACK_NAME}.env}" LOCAL_TUNNEL_SCRIPT="${LOCAL_TUNNEL_SCRIPT:-/tmp/${STACK_NAME}.tunnel.sh}" LOCAL_DEPLOY_DIR="${LOCAL_DEPLOY_DIR:-/tmp/${STACK_NAME}-stage}" REMOTE_ROOT="${REMOTE_ROOT:-/home/ubuntu/${STACK_NAME}_${CRM_PORT}}" REMOTE_REPO_ROOT="${REMOTE_REPO_ROOT:-/home/ubuntu/sub2api-cn-relay-manager-git-current}" REMOTE_REPO_BUNDLE="$REMOTE_ROOT/sub2api-cn-relay-manager.bundle" REMOTE_CRM_ENV_FILE="$REMOTE_ROOT/.env.crm" REMOTE_BOOTSTRAP_FILE="$REMOTE_ROOT/bootstrap.sh" REMOTE_CRM_BINARY="$REMOTE_ROOT/sub2api-cn-relay-manager-server" REMOTE_CRM_DB_FILE="$REMOTE_ROOT/sub2api-cn-relay-manager.db" REMOTE_CRM_PID_FILE="$REMOTE_ROOT/crm.pid" REMOTE_CRM_LOG_FILE="$REMOTE_ROOT/crm.log" crm_admin_token="${crm_admin_token:-$(remote43_random_hex 24)}" crm_admin_username="${crm_admin_username:-admin}" crm_admin_password="${crm_admin_password:-$crm_admin_token}" DRY_RUN="${DRY_RUN:-0}" die() { echo "$*" >&2; exit 1; } require_cmd() { command -v "$1" >/dev/null 2>&1 || die "missing command: $1"; } run_cmd() { if [[ "$DRY_RUN" == "1" ]]; then printf "DRY_RUN:"; printf " %q" "$@"; printf "\n" return 0 fi "$@" } ssh_remote() { run_cmd ssh -i "$KEY" -o StrictHostKeyChecking=no "$REMOTE" "$@"; } scp_remote() { run_cmd scp -i "$KEY" -o StrictHostKeyChecking=no "$@"; } write_local_tunnel_script() { cat > "$LOCAL_TUNNEL_SCRIPT" < "$tmp_bootstrap" <<'BOOTSTRAP_EOF' #!/usr/bin/env bash set -euo pipefail export REMOTE_ROOT=__REMOTE_ROOT__ export CRM_ENV_FILE=__CRM_ENV_FILE__ export CRM_BINARY=__CRM_BINARY__ export CRM_DB_FILE=__CRM_DB_FILE__ export CRM_PID_FILE=__CRM_PID_FILE__ export CRM_LOG_FILE=__CRM_LOG_FILE__ export REMOTE_REPO_ROOT=__REMOTE_REPO_ROOT__ export REMOTE_REPO_BUNDLE=__REMOTE_REPO_BUNDLE__ export CRM_PORT=__CRM_PORT__ mkdir -p "$REMOTE_ROOT" "$(dirname "$REMOTE_REPO_ROOT")" chmod 755 "$CRM_BINARY" if [[ -f "$REMOTE_REPO_BUNDLE" ]]; then if [[ -d "$REMOTE_REPO_ROOT/.git" ]]; then git -C "$REMOTE_REPO_ROOT" fetch "$REMOTE_REPO_BUNDLE" main git -C "$REMOTE_REPO_ROOT" reset --hard FETCH_HEAD else rm -rf "$REMOTE_REPO_ROOT" git clone "$REMOTE_REPO_BUNDLE" "$REMOTE_REPO_ROOT" git -C "$REMOTE_REPO_ROOT" checkout main fi git -C "$REMOTE_REPO_ROOT" config user.name "Remote43 CRM" git -C "$REMOTE_REPO_ROOT" config user.email "remote43-crm@tksea.top" fi if [[ -f "$CRM_PID_FILE" ]]; then OLD_PID="$(cat "$CRM_PID_FILE")" if kill "$OLD_PID" >/dev/null 2>&1; then sleep 1 fi rm -f "$CRM_PID_FILE" fi rm -f "$CRM_DB_FILE" "$CRM_LOG_FILE" nohup bash -lc 'set -a; source "$CRM_ENV_FILE"; set +a; exec "$CRM_BINARY"' >"$CRM_LOG_FILE" 2>&1 & echo $! > "$CRM_PID_FILE" python3 - "$CRM_PORT" <<'PY' import subprocess, sys, time url = f"http://127.0.0.1:{sys.argv[1]}/healthz" for _ in range(30): r = subprocess.run(["curl", "-fsS", url], text=True, capture_output=True) if r.returncode == 0 and r.stdout.strip() == "ok": raise SystemExit(0) time.sleep(1) raise SystemExit(f"crm healthz did not become ready on {url}") PY printf "crm_base=http://127.0.0.1:%s\n" "$CRM_PORT" printf "crm_pid_file=%s\n" "$CRM_PID_FILE" printf "crm_log=%s\n" "$CRM_LOG_FILE" printf "remote_repo_root=%s\n" "$REMOTE_REPO_ROOT" BOOTSTRAP_EOF sed -i -e "s|__REMOTE_ROOT__|$remote_root_q|g" -e "s|__CRM_ENV_FILE__|$crm_env_q|g" -e "s|__CRM_BINARY__|$crm_binary_q|g" -e "s|__CRM_DB_FILE__|$crm_db_q|g" -e "s|__CRM_PID_FILE__|$crm_pid_q|g" -e "s|__CRM_LOG_FILE__|$crm_log_q|g" -e "s|__REMOTE_REPO_ROOT__|$remote_repo_root_q|g" -e "s|__REMOTE_REPO_BUNDLE__|$remote_repo_bundle_q|g" -e "s|__CRM_PORT__|$crm_port_q|g" "$tmp_bootstrap" cat "$tmp_bootstrap" rm -f "$tmp_bootstrap" } main() { require_cmd bash curl git python3 ssh scp remote43_require_file "$KEY" "ssh key" remote43_require_file "$CRM_BINARY" "crm server binary" rm -f "$LOCAL_REPO_BUNDLE" git -C "$ROOT_DIR" bundle create "$LOCAL_REPO_BUNDLE" main write_local_tunnel_script write_operator_env local crm_env_file bootstrap_file crm_env_file="$(mktemp)" bootstrap_file="$(mktemp)" trap "rm -f \"$crm_env_file\" \"$bootstrap_file\"" EXIT render_remote43_crm_env \ "$CRM_PORT" \ "file:${REMOTE_CRM_DB_FILE}?_foreign_keys=on&_busy_timeout=5000" \ "$crm_admin_token" \ "$REMOTE_REPO_ROOT" \ "$crm_admin_username" \ "$crm_admin_password" > "$crm_env_file" render_crm_only_bootstrap > "$bootstrap_file" chmod +x "$bootstrap_file" mkdir -p "$LOCAL_DEPLOY_DIR" cp "$crm_env_file" "$LOCAL_DEPLOY_DIR/.env.crm" cp "$bootstrap_file" "$LOCAL_DEPLOY_DIR/bootstrap.sh" ssh_remote "mkdir -p $(printf "%q" "$REMOTE_ROOT") if [[ -f $(printf "%q" "$REMOTE_CRM_PID_FILE") ]]; then OLDPID=\$(cat $(printf "%q" "$REMOTE_CRM_PID_FILE")) kill \$OLDPID 2>/dev/null || true sleep 1 fi rm -f $(printf "%q" "$REMOTE_CRM_PID_FILE") $(printf "%q" "$REMOTE_CRM_DB_FILE") $(printf "%q" "$REMOTE_CRM_LOG_FILE") $(printf "%q" "$REMOTE_CRM_BINARY")" scp_remote "$CRM_BINARY" "$REMOTE:$REMOTE_CRM_BINARY" scp_remote "$LOCAL_REPO_BUNDLE" "$REMOTE:$REMOTE_REPO_BUNDLE" scp_remote "$crm_env_file" "$REMOTE:$REMOTE_CRM_ENV_FILE" scp_remote "$bootstrap_file" "$REMOTE:$REMOTE_BOOTSTRAP_FILE" ssh_remote "bash $(printf "%q" "$REMOTE_BOOTSTRAP_FILE")" cat <