deploy.sh 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #!/bin/bash
  2. # ============================================================
  3. # 一键部署脚本 (2核4G 低配服务器优化版)
  4. # 用法: ./deploy.sh [admin|miniapp|all] [--skip-frontend] [--no-stop]
  5. # --no-stop 构建前不停止服务 (零停机,JVM 已限制内存)
  6. # 调试: bash -x ./deploy.sh
  7. # ============================================================
  8. APP_DIR="/data/app"
  9. CODE_DIR="/data/code/car-wash-java"
  10. BACKUP_DIR="/data/backup"
  11. LOG_DIR="/data/logs"
  12. HISTORY_FILE="/data/history"
  13. RED='\033[0;31m'
  14. GREEN='\033[0;32m'
  15. YELLOW='\033[1;33m'
  16. NC='\033[0m'
  17. log() { echo -e "[$(date '+%H:%M:%S')] $1"; }
  18. info() { log "${GREEN}INFO${NC} $1"; }
  19. warn() { log "${YELLOW}WARN${NC} $1"; }
  20. error() { log "${RED}ERROR${NC} $1"; }
  21. mkdir -p "$LOG_DIR" "$BACKUP_DIR"
  22. # ============================================================
  23. # 资源限制配置 (2核4G 服务器)
  24. # ============================================================
  25. # ---- 构建阶段 ----
  26. NODE_MAX_MEM="${NODE_MAX_MEM:-1024}" # Node 最大 old-space MB
  27. MAVEN_XMX="${MAVEN_XMX:-512}" # Maven JVM 最大堆 MB
  28. MAVEN_XMS="${MAVEN_XMS:-128}" # Maven JVM 初始堆 MB
  29. MAVEN_THREADS="${MAVEN_THREADS:-1}" # Maven 编译线程数
  30. # ---- 运行时 JVM (admin 模块) ----
  31. ADMIN_XMX="${ADMIN_XMX:-512}" # 最大堆 MB (含 POI Excel 处理)
  32. ADMIN_XMS="${ADMIN_XMS:-128}" # 初始堆 MB
  33. ADMIN_META="${ADMIN_META:-128}" # 元空间上限 MB
  34. ADMIN_CODE_CACHE="${ADMIN_CODE_CACHE:-64}" # JIT 代码缓存 MB
  35. ADMIN_XSS="${ADMIN_XSS:-256}" # 线程栈 KB
  36. # ---- 运行时 JVM (miniapp 模块) ----
  37. MINIAPP_XMX="${MINIAPP_XMX:-384}"
  38. MINIAPP_XMS="${MINIAPP_XMS:-128}"
  39. MINIAPP_META="${MINIAPP_META:-128}"
  40. MINIAPP_CODE_CACHE="${MINIAPP_CODE_CACHE:-64}"
  41. MINIAPP_XSS="${MINIAPP_XSS:-256}"
  42. # 低优先级包装器
  43. low_prio() {
  44. nice -n 19 ionice -c 2 -n 7 "$@"
  45. }
  46. # ---- 参数解析 ----
  47. TARGET="${1:-all}"
  48. SKIP_FRONTEND=false
  49. NO_STOP=false
  50. for arg in "$@"; do
  51. [ "$arg" = "--skip-frontend" ] && SKIP_FRONTEND=true
  52. [ "$arg" = "--no-stop" ] && NO_STOP=true
  53. done
  54. info "开始部署 (目标=$TARGET, 零停机=$NO_STOP)"
  55. info "Node:${NODE_MAX_MEM}M | Maven:${MAVEN_XMX}M | Admin-JVM:${ADMIN_XMX}M | Miniapp-JVM:${MINIAPP_XMX}M"
  56. # ---- 拉取代码 ----
  57. info "拉取最新代码..."
  58. cd "$CODE_DIR" || { error "无法进入 $CODE_DIR"; exit 1; }
  59. low_prio git pull origin master || { error "git pull 失败"; exit 1; }
  60. # ============================================================
  61. # 阶段 1: 停止服务 (释放内存给构建)
  62. # ============================================================
  63. stop_service() {
  64. local module=$1
  65. local pid=$(ps -ef | grep java | grep "$module" | grep -v grep | awk '{print $2}')
  66. if [ -z "$pid" ]; then
  67. info "$module 未在运行"
  68. return 0
  69. fi
  70. for p in $pid; do
  71. info "终止 $module (pid=$p)..."
  72. kill "$p" 2>/dev/null
  73. for i in $(seq 1 10); do
  74. if ! kill -0 "$p" 2>/dev/null; then
  75. info "进程 $p 已退出"
  76. break
  77. fi
  78. sleep 1
  79. done
  80. if kill -0 "$p" 2>/dev/null; then
  81. warn "强制终止 $p"
  82. kill -9 "$p" 2>/dev/null
  83. sleep 1
  84. fi
  85. done
  86. }
  87. if [ "$NO_STOP" = false ]; then
  88. case "$TARGET" in
  89. admin) stop_service "car-wash-admin" ;;
  90. miniapp) stop_service "car-wash-miniapp" ;;
  91. all) stop_service "car-wash-admin"
  92. stop_service "car-wash-miniapp" ;;
  93. esac
  94. sleep 3
  95. fi
  96. # ============================================================
  97. # 阶段 2: 构建
  98. # ============================================================
  99. if [ "$SKIP_FRONTEND" = false ] && [ "$TARGET" != "miniapp" ]; then
  100. for item in "admin-web:admin-web" "admin-h5:admin-h5"; do
  101. dir="${item%%:*}"
  102. name="${item##*:}"
  103. info "构建前端 $name ..."
  104. (
  105. cd "$CODE_DIR/$dir" || exit 1
  106. export NODE_OPTIONS="--max-old-space-size=$NODE_MAX_MEM"
  107. low_prio npm run build
  108. ) || { error "$name 构建失败"; exit 1; }
  109. info "$name 构建完成"
  110. sleep 2
  111. done
  112. info "前端构建全部完成"
  113. fi
  114. export MAVEN_OPTS="-Xmx${MAVEN_XMX}m -Xms${MAVEN_XMS}m -XX:+UseSerialGC"
  115. if [ "$TARGET" = "miniapp" ]; then
  116. info "Maven 打包 (仅 miniapp)..."
  117. (
  118. cd "$CODE_DIR"
  119. low_prio mvn clean package -DskipTests -pl car-wash-miniapp -am \
  120. -T "${MAVEN_THREADS}" -Dmaven.test.skip=true
  121. ) || { error "Maven 打包失败"; exit 1; }
  122. else
  123. info "Maven 打包 (全量, 线程=${MAVEN_THREADS})..."
  124. (
  125. cd "$CODE_DIR"
  126. low_prio mvn clean package -DskipTests \
  127. -T "${MAVEN_THREADS}" \
  128. -Dmaven.test.skip=true \
  129. -Dmaven.compiler.fork=false
  130. ) || { error "Maven 打包失败"; exit 1; }
  131. fi
  132. sleep 2
  133. # ============================================================
  134. # 阶段 3: 备份 & 部署 & 启动
  135. # ============================================================
  136. backup_and_copy() {
  137. local module=$1
  138. local jar_src="$CODE_DIR/$module/target/${module}-0.0.1-SNAPSHOT.jar"
  139. local jar_dst="$APP_DIR/${module}-0.0.1-SNAPSHOT.jar"
  140. if [ ! -f "$jar_src" ]; then
  141. error "未找到 jar 文件: $jar_src"
  142. exit 1
  143. fi
  144. if [ -f "$jar_dst" ]; then
  145. cp "$jar_dst" "$BACKUP_DIR/${module}-0.0.1-SNAPSHOT.jar.$(date +%Y%m%d_%H%M%S)"
  146. info "已备份 $module (保留最近 5 个)"
  147. ls -t "$BACKUP_DIR/${module}"-*.jar 2>/dev/null | tail -n +6 | xargs -r rm -f
  148. fi
  149. cp "$jar_src" "$jar_dst"
  150. info "$module jar 已复制到 $APP_DIR"
  151. }
  152. # 构建模块专用的 JVM 参数
  153. build_jvm_opts() {
  154. local module=$1
  155. if [ "$module" = "car-wash-admin" ]; then
  156. echo "-Xmx${ADMIN_XMX}m -Xms${ADMIN_XMS}m -Xss${ADMIN_XSS}k \
  157. -XX:MaxMetaspaceSize=${ADMIN_META}m -XX:ReservedCodeCacheSize=${ADMIN_CODE_CACHE}m \
  158. -XX:+UseSerialGC -XX:+UseStringDeduplication"
  159. else
  160. echo "-Xmx${MINIAPP_XMX}m -Xms${MINIAPP_XMS}m -Xss${MINIAPP_XSS}k \
  161. -XX:MaxMetaspaceSize=${MINIAPP_META}m -XX:ReservedCodeCacheSize=${MINIAPP_CODE_CACHE}m \
  162. -XX:+UseSerialGC -XX:+UseStringDeduplication"
  163. fi
  164. }
  165. start_service() {
  166. local module=$1
  167. local jar_file="${module}-0.0.1-SNAPSHOT.jar"
  168. local start_log="$LOG_DIR/${module}.log"
  169. local jvm_opts=$(build_jvm_opts "$module")
  170. info "启动 $module (JVM: $(echo $jvm_opts | tr -s ' '))..."
  171. local cert_arg=""
  172. if [ "$module" = "car-wash-admin" ]; then
  173. cert_arg="-Dwechat.payment.certPath=/data/wash-pem/apiclient_cert.pem -Dwechat.payment.keyPath=/data/wash-pem/apiclient_key.pem"
  174. fi
  175. cd "$APP_DIR"
  176. nohup java $jvm_opts -jar -Dspring.profiles.active=prod $cert_arg "$jar_file" > "$start_log" 2>&1 &
  177. sleep 5
  178. local new_pid=$(ps -ef | grep java | grep "$module" | grep -v grep | awk '{print $2}')
  179. if [ -n "$new_pid" ]; then
  180. info "$module 启动成功 (pid=$new_pid)"
  181. echo "$(date) $module restarted" >> "$HISTORY_FILE"
  182. else
  183. error "$module 可能启动失败,查看日志:"
  184. echo "--- $start_log ---"
  185. tail -30 "$start_log"
  186. echo "--- end ---"
  187. exit 1
  188. fi
  189. }
  190. case "$TARGET" in
  191. admin)
  192. backup_and_copy "car-wash-admin"
  193. start_service "car-wash-admin"
  194. ;;
  195. miniapp)
  196. backup_and_copy "car-wash-miniapp"
  197. start_service "car-wash-miniapp"
  198. ;;
  199. all)
  200. backup_and_copy "car-wash-admin"
  201. backup_and_copy "car-wash-miniapp"
  202. start_service "car-wash-admin"
  203. start_service "car-wash-miniapp"
  204. ;;
  205. *)
  206. error "未知模块: $TARGET (可选: admin | miniapp | all)"
  207. exit 1
  208. ;;
  209. esac
  210. echo "========================================"
  211. info "部署完成"
  212. echo "========================================"