deploy-sygpudev.sh 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. #!/bin/bash
  2. # ============================================
  3. # 灵越智报 - 发布到 sygpudev 服务器
  4. # 本地编译 → 上传 jar → 重启服务
  5. # ============================================
  6. # 不使用 set -e,因为 ssh 远程命令的退出码会导致误退出
  7. # 颜色定义
  8. RED='\033[0;31m'
  9. GREEN='\033[0;32m'
  10. YELLOW='\033[1;33m'
  11. BLUE='\033[0;34m'
  12. NC='\033[0m'
  13. # ========== 配置区域 ==========
  14. SERVER_USER="root"
  15. SERVER_HOST="sygpudev"
  16. SERVER_PORT="${SERVER_PORT:-28529}"
  17. # 路径配置
  18. LOCAL_PROJECT_DIR="/home/hws/workspace/GitLab/ay/lingyue-zhibao"
  19. LOCAL_BACKEND_DIR="${LOCAL_PROJECT_DIR}/backend"
  20. LOCAL_JAR_PATH="${LOCAL_BACKEND_DIR}/lingyue-starter/target/lingyue-starter.jar"
  21. REMOTE_APP_DIR="/data/application/lingyue-zhibao"
  22. REMOTE_JAR="${REMOTE_APP_DIR}/lingyue-starter.jar"
  23. REMOTE_LOG_DIR="${REMOTE_APP_DIR}/logs"
  24. # 应用配置
  25. JAR_NAME="lingyue-starter.jar"
  26. # ==============================
  27. log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
  28. log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
  29. log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
  30. log_title() { echo -e "\n${BLUE}========== $1 ==========${NC}\n"; }
  31. ssh_cmd() {
  32. ssh -p ${SERVER_PORT} ${SERVER_USER}@${SERVER_HOST} "$@"
  33. }
  34. # 检查服务器连接
  35. check_connection() {
  36. log_title "检查服务器连接"
  37. if ssh_cmd "echo 'OK'" > /dev/null 2>&1; then
  38. log_info "服务器连接成功: ${SERVER_USER}@${SERVER_HOST}"
  39. else
  40. log_error "无法连接服务器: ${SERVER_USER}@${SERVER_HOST}"
  41. log_warn "请检查:"
  42. log_warn " 1. 服务器地址是否正确(可在 /etc/hosts 或 ~/.ssh/config 中配置 sygpudev)"
  43. log_warn " 2. SSH 密钥是否配置"
  44. log_warn " 3. 可以通过 SERVER_HOST=<IP> 指定服务器地址"
  45. exit 1
  46. fi
  47. }
  48. # 本地编译
  49. build_local() {
  50. log_title "本地编译项目"
  51. cd ${LOCAL_BACKEND_DIR}
  52. log_info "清理并编译..."
  53. mvn clean package -DskipTests -q
  54. if [ ! -f "${LOCAL_JAR_PATH}" ]; then
  55. log_error "编译产物不存在: ${LOCAL_JAR_PATH}"
  56. exit 1
  57. fi
  58. local jar_size=$(du -h "${LOCAL_JAR_PATH}" | awk '{print $1}')
  59. log_info "编译完成,jar 大小: ${jar_size}"
  60. }
  61. # 停止远程应用
  62. stop_app() {
  63. log_title "停止远程应用"
  64. # 优先使用服务器上的 start.sh stop(如果支持)
  65. ssh_cmd "test -f ${REMOTE_APP_DIR}/start.sh && cd ${REMOTE_APP_DIR} && bash start.sh stop; true"
  66. sleep 2
  67. # 确保进程已停止
  68. ssh_cmd "pkill -f '${JAR_NAME}'; true"
  69. sleep 2
  70. if ssh_cmd "pgrep -f '${JAR_NAME}'" > /dev/null 2>&1; then
  71. log_warn "进程仍在运行,强制终止..."
  72. ssh_cmd "pkill -9 -f '${JAR_NAME}'; true"
  73. sleep 2
  74. fi
  75. log_info "应用已停止"
  76. }
  77. # 上传 jar
  78. upload_jar() {
  79. log_title "上传 JAR 到服务器"
  80. # 备份旧 jar
  81. ssh_cmd "cd ${REMOTE_APP_DIR} && \
  82. [ -f ${JAR_NAME} ] && cp ${JAR_NAME} ${JAR_NAME}.bak || true"
  83. log_info "已备份旧版本为 ${JAR_NAME}.bak"
  84. # 上传新 jar
  85. log_info "正在上传 ${JAR_NAME}..."
  86. scp -P ${SERVER_PORT} "${LOCAL_JAR_PATH}" "${SERVER_USER}@${SERVER_HOST}:${REMOTE_JAR}"
  87. local remote_size=$(ssh_cmd "du -h ${REMOTE_JAR}" | awk '{print $1}')
  88. log_info "上传完成,远程文件大小: ${remote_size}"
  89. }
  90. # 启动远程应用
  91. start_app() {
  92. log_title "启动远程应用"
  93. # 优先使用服务器上的 start.sh
  94. if ssh_cmd "test -f ${REMOTE_APP_DIR}/start.sh" 2>/dev/null; then
  95. log_info "使用服务器 start.sh 启动..."
  96. ssh_cmd "cd ${REMOTE_APP_DIR} && bash start.sh start"
  97. else
  98. log_info "直接启动 jar..."
  99. ssh_cmd "cd ${REMOTE_APP_DIR} && \
  100. mkdir -p ${REMOTE_LOG_DIR} && \
  101. nohup java -Xms1g -Xmx2g -XX:+UseG1GC \
  102. -jar ${JAR_NAME} \
  103. --spring.config.location=file:./application.yml \
  104. > ${REMOTE_LOG_DIR}/app.log 2>&1 &"
  105. fi
  106. log_info "应用启动中..."
  107. sleep 5
  108. if ssh_cmd "pgrep -f '${JAR_NAME}'" > /dev/null 2>&1; then
  109. local pid=$(ssh_cmd "pgrep -f '${JAR_NAME}'")
  110. log_info "应用启动成功 (PID: ${pid})"
  111. else
  112. log_error "应用启动失败,查看日志:"
  113. ssh_cmd "tail -50 ${REMOTE_LOG_DIR}/app.log 2>/dev/null || tail -50 /var/log/lingyue.log 2>/dev/null || echo '未找到日志文件'"
  114. exit 1
  115. fi
  116. }
  117. # 健康检查
  118. health_check() {
  119. log_title "健康检查"
  120. local max_attempts=12
  121. local attempt=1
  122. while [ $attempt -le $max_attempts ]; do
  123. log_info "尝试 ${attempt}/${max_attempts}..."
  124. local response=$(ssh_cmd "curl -s -o /dev/null -w '%{http_code}' http://localhost:8001/api/v1/projects 2>/dev/null" || echo "000")
  125. if [ "$response" != "000" ] && [ "$response" != "404" ]; then
  126. log_info "健康检查通过 ✓ (HTTP ${response})"
  127. echo ""
  128. return 0
  129. fi
  130. sleep 5
  131. attempt=$((attempt + 1))
  132. done
  133. log_warn "健康检查超时,应用可能仍在启动中"
  134. log_info "可手动检查: ssh ${SERVER_USER}@${SERVER_HOST} 'curl http://localhost:8001/actuator/health'"
  135. }
  136. # 回滚到上一版本
  137. rollback() {
  138. log_title "回滚到上一版本"
  139. if ssh_cmd "test -f ${REMOTE_APP_DIR}/${JAR_NAME}.bak" 2>/dev/null; then
  140. stop_app
  141. ssh_cmd "cd ${REMOTE_APP_DIR} && mv ${JAR_NAME}.bak ${JAR_NAME}"
  142. log_info "已恢复上一版本"
  143. start_app
  144. health_check
  145. else
  146. log_error "没有找到备份文件 ${JAR_NAME}.bak,无法回滚"
  147. exit 1
  148. fi
  149. }
  150. # 查看远程日志
  151. show_logs() {
  152. log_title "应用日志"
  153. ssh_cmd "tail -100 ${REMOTE_LOG_DIR}/app.log 2>/dev/null || tail -100 /var/log/lingyue.log 2>/dev/null || echo '未找到日志文件'"
  154. }
  155. tail_logs() {
  156. log_info "实时日志 (Ctrl+C 退出)"
  157. ssh_cmd "tail -f ${REMOTE_LOG_DIR}/app.log 2>/dev/null || tail -f /var/log/lingyue.log 2>/dev/null || echo '未找到日志文件'"
  158. }
  159. show_status() {
  160. log_title "应用状态"
  161. if ssh_cmd "pgrep -f '${JAR_NAME}'" > /dev/null 2>&1; then
  162. local pid=$(ssh_cmd "pgrep -f '${JAR_NAME}'")
  163. log_info "应用运行中 (PID: ${pid})"
  164. ssh_cmd "ps -p ${pid} -o pid,rss,vsz,etime,args --no-headers" 2>/dev/null || true
  165. else
  166. log_warn "应用未运行"
  167. fi
  168. }
  169. # 完整部署: 编译 → 上传 → 重启
  170. full_deploy() {
  171. check_connection
  172. build_local
  173. stop_app
  174. upload_jar
  175. start_app
  176. health_check
  177. log_title "部署完成 🎉"
  178. echo -e "${GREEN}服务器: ${SERVER_USER}@${SERVER_HOST}:${REMOTE_APP_DIR}${NC}"
  179. echo ""
  180. }
  181. # 快速部署: 仅上传 jar 并重启(跳过编译,使用已有的 target)
  182. quick_deploy() {
  183. if [ ! -f "${LOCAL_JAR_PATH}" ]; then
  184. log_error "本地 jar 不存在,请先编译或使用 deploy 命令"
  185. exit 1
  186. fi
  187. check_connection
  188. stop_app
  189. upload_jar
  190. start_app
  191. health_check
  192. log_title "快速部署完成 🎉"
  193. }
  194. # 帮助
  195. show_help() {
  196. cat <<EOF
  197. 灵越智报 - 发布到 sygpudev 服务器
  198. 用法: ./deploy-sygpudev.sh [命令]
  199. 命令:
  200. deploy 完整部署(本地编译 + 上传 + 重启)
  201. quick 快速部署(上传已编译的 jar + 重启)
  202. build 仅本地编译
  203. upload 仅上传 jar(不重启)
  204. restart 重启远程应用(不编译不上传)
  205. stop 停止远程应用
  206. rollback 回滚到上一版本
  207. status 查看应用状态
  208. logs 查看最近日志
  209. tail 实时查看日志
  210. help 显示此帮助
  211. 示例:
  212. ./deploy-sygpudev.sh deploy # 完整部署
  213. ./deploy-sygpudev.sh quick # 快速部署(已编译过)
  214. ./deploy-sygpudev.sh rollback # 回滚到上一版本
  215. ./deploy-sygpudev.sh tail # 实时看日志
  216. EOF
  217. }
  218. # 主函数
  219. main() {
  220. case "${1:-deploy}" in
  221. deploy)
  222. full_deploy
  223. ;;
  224. quick)
  225. quick_deploy
  226. ;;
  227. build)
  228. build_local
  229. ;;
  230. upload)
  231. check_connection
  232. upload_jar
  233. log_info "上传完成(未重启)"
  234. ;;
  235. restart)
  236. check_connection
  237. stop_app
  238. start_app
  239. health_check
  240. ;;
  241. stop)
  242. check_connection
  243. stop_app
  244. ;;
  245. rollback)
  246. check_connection
  247. rollback
  248. ;;
  249. status)
  250. check_connection
  251. show_status
  252. ;;
  253. logs)
  254. check_connection
  255. show_logs
  256. ;;
  257. tail)
  258. check_connection
  259. tail_logs
  260. ;;
  261. help|--help|-h)
  262. show_help
  263. ;;
  264. *)
  265. log_error "未知命令: $1"
  266. show_help
  267. exit 1
  268. ;;
  269. esac
  270. }
  271. main "$@"