deploy-prod.sh 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. #!/bin/bash
  2. #
  3. # 有声书项目 - 生产环境部署脚本
  4. # 部署到 8.159.134.106:/data/ai/audio
  5. # 前端域名: book.rrbrr.com
  6. # 后端 API 域名: bookapi.rrbrr.com
  7. # 后端端口: 3100
  8. set -e
  9. REMOTE_HOST="8.159.134.106"
  10. REMOTE_PATH="/data/ai/audio"
  11. LOCAL_PROJECT="$(cd "$(dirname "$0")" && pwd)"
  12. SSH_KEY="$HOME/.ssh/id_rsa"
  13. SSH_PORT="22622"
  14. echo "=== 有声书项目 - 生产环境部署 ==="
  15. echo "时间: $(date)"
  16. echo "主机: $REMOTE_HOST"
  17. echo "路径: $REMOTE_PATH"
  18. echo "前端: book.rrbrr.com"
  19. echo "后端: bookapi.rrbrr.com:3100"
  20. echo ""
  21. # 1. 构建前端(后端使用已有的 dist)
  22. echo "=== 1. 构建前端 ==="
  23. cd "$LOCAL_PROJECT/my-uniapp-vue3"
  24. npm run build:h5
  25. echo "前端构建完成"
  26. cd "$LOCAL_PROJECT"
  27. # 2. 同步文件到服务器
  28. echo ""
  29. echo "=== 2. 同步文件到服务器 ==="
  30. # 创建临时目录
  31. TEMP_DIR="/tmp/deploy_audio_$(date +%Y%m%d_%H%M%S)"
  32. ssh -i "$SSH_KEY" -p "$SSH_PORT" root@$REMOTE_HOST "mkdir -p $TEMP_DIR"
  33. # 本地临时目录
  34. mkdir -p "$LOCAL_PROJECT/tmp"
  35. # 打包后端(使用已有的 dist,打包所有必要文件,排除 node_modules, .git, *.ts)
  36. echo "打包后端文件(排除大目录,避免 SSH buffer 撑爆)..."
  37. cd "$LOCAL_PROJECT/server"
  38. tar \
  39. --exclude='node_modules' --exclude='.git' \
  40. --exclude='uploads' --exclude='coverage' --exclude='.playwright-cli' \
  41. --exclude='cache' --exclude='temp' --exclude='logs' --exclude='tmp' \
  42. --exclude='_*.txt' --exclude='_*.cjs' --exclude='_*.mjs' --exclude='_*.json' \
  43. -czf "$LOCAL_PROJECT/tmp/server.tar.gz" .
  44. cd "$LOCAL_PROJECT"
  45. # 打包前端(只打包 build/h5 目录内容,对接 nginx root)
  46. echo "打包前端文件..."
  47. cd "$LOCAL_PROJECT/my-uniapp-vue3/dist/build/h5"
  48. tar -czf "$LOCAL_PROJECT/tmp/frontend.tar.gz" .
  49. cd "$LOCAL_PROJECT"
  50. # 上传到服务器(用 -C 调小 SSH 压缩级别,避免大包 buffer 撑爆)
  51. echo "上传后端..."
  52. scp -i "$SSH_KEY" -P "$SSH_PORT" -C -o "CompressionLevel=3" "$LOCAL_PROJECT/tmp/server.tar.gz" root@$REMOTE_HOST:$TEMP_DIR/
  53. echo "上传前端..."
  54. scp -i "$SSH_KEY" -P "$SSH_PORT" -C -o "CompressionLevel=3" "$LOCAL_PROJECT/tmp/frontend.tar.gz" root@$REMOTE_HOST:$TEMP_DIR/
  55. # 清理本地临时文件
  56. rm -rf "$LOCAL_PROJECT/tmp"
  57. # 3. 在服务器上安装 Node.js(如需要)
  58. echo ""
  59. echo "=== 3. 检查并安装 Node.js ==="
  60. ssh -i "$SSH_KEY" -p "$SSH_PORT" root@$REMOTE_HOST << 'ENDSSH'
  61. set -e
  62. # 检查 Node.js 是否已安装
  63. if ! command -v node &> /dev/null; then
  64. echo "安装 Node.js 20.x..."
  65. curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
  66. dnf install -y nodejs
  67. fi
  68. echo "Node.js 版本: $(node --version)"
  69. echo "npm 版本: $(npm --version)"
  70. ENDSSH
  71. # 4. 在服务器上执行部署
  72. echo ""
  73. echo "=== 4. 执行服务器部署 ==="
  74. ssh -i "$SSH_KEY" -p "$SSH_PORT" root@$REMOTE_HOST << 'ENDSSH'
  75. set -e
  76. TEMP_DIR=$(ls -td /tmp/deploy_audio_* | head -1)
  77. REMOTE_PATH="/data/ai/audio"
  78. BACKUP_DIR="$REMOTE_PATH/backup_$(date +%Y%m%d_%H%M%S)"
  79. echo "创建备份..."
  80. mkdir -p $BACKUP_DIR
  81. if [ -d "$REMOTE_PATH/server" ]; then
  82. cp -r $REMOTE_PATH/server $BACKUP_DIR/ 2>/dev/null || true
  83. fi
  84. if [ -d "$REMOTE_PATH/frontend" ]; then
  85. cp -r $REMOTE_PATH/frontend $BACKUP_DIR/ 2>/dev/null || true
  86. fi
  87. echo "解压文件到临时目录..."
  88. cd $TEMP_DIR
  89. rm -rf server frontend
  90. mkdir -p server frontend
  91. tar -xzf server.tar.gz -C server/
  92. tar -xzf frontend.tar.gz -C frontend/
  93. echo "部署后端到目标目录..."
  94. rm -rf $REMOTE_PATH/server
  95. mv server $REMOTE_PATH/
  96. echo "部署前端到 nginx 目录..."
  97. rm -rf /data/ai/frontend/build/h5/*
  98. mkdir -p /data/ai/frontend/build/h5
  99. cp -r frontend/* /data/ai/frontend/build/h5/
  100. rm -rf frontend
  101. echo "验证关键文件..."
  102. ls -la $REMOTE_PATH/server/dist/ 2>/dev/null || echo "dist 目录不存在"
  103. ls -la $REMOTE_PATH/server/prisma/ 2>/dev/null || echo "prisma 目录不存在"
  104. echo "安装后端依赖..."
  105. cd $REMOTE_PATH/server
  106. npm install --production
  107. echo "复制生产环境配置..."
  108. cp $REMOTE_PATH/server/.env.production $REMOTE_PATH/server/.env
  109. echo "生成 Prisma Client..."
  110. npx prisma generate
  111. echo "同步数据库 Schema (prisma db push)..."
  112. # 治根:每次部署把 schema 推到 DB,避免 client vs DB 长期漂移导致运行时 'column does not exist'
  113. # --accept-data-loss 允许破坏性变更(如删列);生产如有重要数据请先备份再改破坏性字段
  114. npx prisma db push --accept-data-loss --skip-generate
  115. DB_PUSH_EXIT=$?
  116. if [ $DB_PUSH_EXIT -ne 0 ]; then
  117. echo "❌ prisma db push 失败 (exit=$DB_PUSH_EXIT),部署中止"
  118. exit $DB_PUSH_EXIT
  119. fi
  120. echo "清理临时文件..."
  121. rm -rf $TEMP_DIR
  122. echo "服务器部署完成!"
  123. ENDSSH
  124. # 5. 配置 Nginx
  125. echo ""
  126. echo "=== 5. 配置 Nginx ==="
  127. echo "Nginx 配置由宝塔面板管理,请手动配置:"
  128. echo "- book.rrbrr.com: /www/server/panel/vhost/nginx/book.rrbrr.com.conf"
  129. echo "- bookapi.rrbrr.com: /www/server/panel/vhost/nginx/bookapi.rrbrr.com.conf"
  130. echo "后端端口: 3100"
  131. # 6. 启动后端服务
  132. echo ""
  133. echo "=== 6. 启动后端服务 ==="
  134. ssh -i "$SSH_KEY" -p "$SSH_PORT" root@$REMOTE_HOST << 'ENDSSH'
  135. set -e
  136. cd /data/ai/audio/server
  137. # 安装 PM2(如果没有)
  138. if ! command -v pm2 &> /dev/null; then
  139. echo "安装 PM2..."
  140. npm install -g pm2
  141. fi
  142. # 停止旧服务
  143. pm2 delete server 2>/dev/null || true
  144. # 设置环境变量(使用 3100 端口,避免与 SSH 22622 冲突)
  145. export SERVER_PORT=3100
  146. # 启动服务
  147. pm2 start dist/app.js --name server --env production
  148. # 保存并设置开机启动
  149. pm2 save
  150. pm2 startup
  151. echo "后端服务已启动 (端口 3100)!"
  152. ENDSSH
  153. # 7. 部署后 OSS 配置校验 (不阻塞部署,仅警告)
  154. echo ""
  155. echo "=== 7. 部署后 OSS 配置校验 ==="
  156. cd "$LOCAL_PROJECT/server"
  157. node "$LOCAL_PROJECT/deploy-package/scripts/check-oss-config.cjs" 2>&1 || echo "⚠️ OSS 配置校验失败, 请人工检查 (deploy 仍成功)"
  158. echo ""
  159. echo "=== 部署完成 ==="
  160. echo "前端地址: http://book.rrbrr.com"
  161. echo "后端 API: http://bookapi.rrbrr.com/api"
  162. echo "健康检查: http://bookapi.rrbrr.com/health"