chore(deploy): 新增一键部署脚本 deploy.sh
- rsync 源码并排除 .env/node_modules/构建产物,避免覆盖生产配置 - 构建前 source .env,确保 NEXT_PUBLIC_*/VITE_API_URL/ADMIN_BASE 正确注入 - 支持 --migrate/--seed/--api/--web/--admin/--restart/--no-sync - pm2 startOrReload + 健康检查;支持 SSH 密钥或 DEPLOY_PASS
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================
|
||||
# 中华文明全图鉴 —— 一键部署脚本
|
||||
#
|
||||
# 用法:
|
||||
# ./deploy.sh # 同步源码 + 安装 + 构建 + 重启(默认全量)
|
||||
# ./deploy.sh --migrate # 额外执行数据库 migration
|
||||
# ./deploy.sh --seed # 额外执行 migration + seed(首次部署用)
|
||||
# ./deploy.sh --api # 只构建并重启后端 api
|
||||
# ./deploy.sh --web # 只构建并重启前端 web
|
||||
# ./deploy.sh --admin # 只构建管理后台(静态)
|
||||
# ./deploy.sh --restart # 不构建,仅重启 pm2 进程
|
||||
# ./deploy.sh --no-sync # 跳过 rsync(用服务器现有代码构建)
|
||||
#
|
||||
# 鉴权:
|
||||
# 优先使用 SSH 密钥(推荐,配好后免密)。
|
||||
# 如需密码登录,设置环境变量 DEPLOY_PASS 后运行(需本机装 sshpass):
|
||||
# DEPLOY_PASS='xxxx' ./deploy.sh
|
||||
#
|
||||
# 可用环境变量覆盖目标(默认指向生产机):
|
||||
# REMOTE_USER REMOTE_HOST REMOTE_DIR SSH_PORT
|
||||
# ============================================================
|
||||
set -euo pipefail
|
||||
|
||||
# ---- 目标服务器(可用环境变量覆盖)----
|
||||
REMOTE_USER="${REMOTE_USER:-ubuntu}"
|
||||
REMOTE_HOST="${REMOTE_HOST:-152.136.182.184}"
|
||||
REMOTE_DIR="${REMOTE_DIR:-/home/ubuntu/wenwumap}"
|
||||
SSH_PORT="${SSH_PORT:-22}"
|
||||
|
||||
# ---- 本地项目根(脚本所在目录)----
|
||||
LOCAL_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# ---- 解析参数 ----
|
||||
DO_SYNC=1; DO_INSTALL=1
|
||||
BUILD_API=0; BUILD_WEB=0; BUILD_ADMIN=0
|
||||
DO_MIGRATE=0; DO_SEED=0; RESTART_ONLY=0
|
||||
SELECTIVE=0
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--no-sync) DO_SYNC=0 ;;
|
||||
--migrate) DO_MIGRATE=1 ;;
|
||||
--seed) DO_SEED=1; DO_MIGRATE=1 ;;
|
||||
--api) BUILD_API=1; SELECTIVE=1 ;;
|
||||
--web) BUILD_WEB=1; SELECTIVE=1 ;;
|
||||
--admin) BUILD_ADMIN=1; SELECTIVE=1 ;;
|
||||
--restart) RESTART_ONLY=1 ;;
|
||||
-h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||
*) echo "未知参数:$arg(用 --help 查看用法)"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 默认(未指定 --api/--web/--admin)则三者全构建
|
||||
if [ "$SELECTIVE" -eq 0 ]; then BUILD_API=1; BUILD_WEB=1; BUILD_ADMIN=1; fi
|
||||
|
||||
# ---- 组装 ssh / rsync 鉴权 ----
|
||||
SSH_BASE=(ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new -p "$SSH_PORT")
|
||||
if [ -n "${DEPLOY_PASS:-}" ]; then
|
||||
if ! command -v sshpass >/dev/null 2>&1; then
|
||||
echo "✗ 设置了 DEPLOY_PASS 但未安装 sshpass。请 brew install hudochenkov/sshpass/sshpass 或改用 SSH 密钥。"
|
||||
exit 1
|
||||
fi
|
||||
SSH=(sshpass -p "$DEPLOY_PASS" "${SSH_BASE[@]}")
|
||||
else
|
||||
SSH=("${SSH_BASE[@]}")
|
||||
fi
|
||||
REMOTE=("${SSH[@]}" "${REMOTE_USER}@${REMOTE_HOST}")
|
||||
|
||||
run_remote() { "${REMOTE[@]}" "bash -s"; }
|
||||
|
||||
echo "============================================================"
|
||||
echo " 部署目标 : ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}"
|
||||
echo " 同步源码 : $([ $DO_SYNC -eq 1 ] && echo 是 || echo 否)"
|
||||
echo " 构建 : api=$BUILD_API web=$BUILD_WEB admin=$BUILD_ADMIN"
|
||||
echo " 迁移/灌种: migrate=$DO_MIGRATE seed=$DO_SEED"
|
||||
echo "============================================================"
|
||||
|
||||
# ============================================================
|
||||
# 1) 同步源码(关键:绝不覆盖服务器 .env / node_modules / 构建产物)
|
||||
# ============================================================
|
||||
if [ "$RESTART_ONLY" -eq 0 ] && [ "$DO_SYNC" -eq 1 ]; then
|
||||
echo "▶ [1/5] rsync 源码到服务器(排除 .env 等)..."
|
||||
RSYNC_RSH="${SSH[*]}"
|
||||
rsync -az --delete \
|
||||
--exclude='.git/' \
|
||||
--exclude='.env' \
|
||||
--exclude='**/.env' \
|
||||
--exclude='node_modules/' \
|
||||
--exclude='**/node_modules/' \
|
||||
--exclude='**/dist/' \
|
||||
--exclude='**/.next/' \
|
||||
--exclude='**/.cache/' \
|
||||
--exclude='apps/api/.cache/' \
|
||||
--exclude='e2e/videos/' \
|
||||
--exclude='*.zip' \
|
||||
--exclude='.DS_Store' \
|
||||
-e "${RSYNC_RSH}" \
|
||||
"${LOCAL_DIR}/" "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/"
|
||||
echo " ✓ 源码已同步"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 2) 远程:检查 .env、安装依赖、迁移、构建、重启
|
||||
# ============================================================
|
||||
run_remote <<REMOTE_SCRIPT
|
||||
set -euo pipefail
|
||||
cd "${REMOTE_DIR}"
|
||||
|
||||
# --- 防呆:生产 .env 必须存在(脚本不会同步它)---
|
||||
if [ ! -f .env ]; then
|
||||
echo "✗ 服务器缺少 ${REMOTE_DIR}/.env,请先在服务器上创建生产配置后再部署。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RESTART_ONLY=${RESTART_ONLY}
|
||||
DO_INSTALL=${DO_INSTALL}
|
||||
DO_MIGRATE=${DO_MIGRATE}
|
||||
DO_SEED=${DO_SEED}
|
||||
BUILD_API=${BUILD_API}
|
||||
BUILD_WEB=${BUILD_WEB}
|
||||
BUILD_ADMIN=${BUILD_ADMIN}
|
||||
|
||||
if [ "\$RESTART_ONLY" -eq 0 ]; then
|
||||
if [ "\$DO_INSTALL" -eq 1 ]; then
|
||||
echo "▶ [2/5] pnpm install ..."
|
||||
pnpm install --no-frozen-lockfile 2>&1 | tail -4
|
||||
fi
|
||||
|
||||
if [ "\$DO_MIGRATE" -eq 1 ]; then
|
||||
echo "▶ 数据库 migration ..."
|
||||
pnpm --filter @wenwumap/db migrate 2>&1 | tail -6
|
||||
fi
|
||||
if [ "\$DO_SEED" -eq 1 ]; then
|
||||
echo "▶ 数据库 seed ..."
|
||||
pnpm --filter @wenwumap/db seed 2>&1 | tail -4
|
||||
fi
|
||||
|
||||
# 关键:构建前加载 .env,使 NEXT_PUBLIC_* / VITE_API_URL / ADMIN_BASE 正确注入产物
|
||||
set -a; . ./.env; set +a
|
||||
export NODE_OPTIONS="--max-old-space-size=1536"
|
||||
|
||||
if [ "\$BUILD_API" -eq 1 ]; then
|
||||
echo "▶ [3/5] 构建 api ..."
|
||||
pnpm --filter @wenwumap/api build 2>&1 | tail -3
|
||||
fi
|
||||
if [ "\$BUILD_ADMIN" -eq 1 ]; then
|
||||
echo "▶ 构建 admin (base=\${ADMIN_BASE:-/}) ..."
|
||||
pnpm --filter @wenwumap/admin build 2>&1 | tail -3
|
||||
fi
|
||||
if [ "\$BUILD_WEB" -eq 1 ]; then
|
||||
echo "▶ 构建 web (API=\${NEXT_PUBLIC_API_URL:-?}) ..."
|
||||
pnpm --filter @wenwumap/web build 2>&1 | tail -4
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "▶ [4/5] 重启 pm2 进程 ..."
|
||||
if [ -f ecosystem.config.js ]; then
|
||||
pm2 startOrReload ecosystem.config.js --update-env >/dev/null 2>&1 || pm2 restart wenwumap-api wenwumap-web --update-env
|
||||
else
|
||||
pm2 restart wenwumap-api wenwumap-web --update-env
|
||||
fi
|
||||
pm2 save >/dev/null 2>&1 || true
|
||||
|
||||
echo "▶ [5/5] 健康检查 ..."
|
||||
sleep 3
|
||||
PORT=\$(grep -E '^PORT=' .env | cut -d= -f2 | tr -d '[:space:]'); PORT=\${PORT:-3101}
|
||||
echo -n " api : "; curl -s -m 8 -o /dev/null -w "%{http_code}\n" "http://127.0.0.1:\${PORT}/api/v1/map/stats" || echo "FAIL"
|
||||
pm2 list | grep -E "wenwumap" || true
|
||||
echo "✓ 远程部署完成"
|
||||
REMOTE_SCRIPT
|
||||
|
||||
echo "============================================================"
|
||||
echo " ✅ 部署完成:https://ww.all8ai.top"
|
||||
echo "============================================================"
|
||||
Reference in New Issue
Block a user