SpringBoot应用部署神器:可视化服务管理脚本让运维更轻松

在SpringBoot应用的生产环境部署中,传统的手动启停服务方式不仅效率低下,还容易出错。

今天分享一个功能强大的可视化服务管理脚本,让SpringBoot应用的部署和运维变得简单高效。

痛点分析:传统部署方式的困扰

相信很多开发者都遇到过这些问题:

操作繁琐:每次部署都要手动执行一堆命令
状态不明:不知道服务是否真正启动成功
日志分散:查看日志需要记住各种路径
回滚困难:出问题时手忙脚乱找备份
多服务管理:微服务架构下管理复杂度倍增

这些问题不仅影响开发效率,还增加了生产环境的风险。

解决方案:可视化服务管理器

为了解决这些痛点,我开发了一套完整的SpringBoot服务管理解决方案,核心特性包括:

🎯 可视化操作界面

告别枯燥的命令行操作,采用彩色终端界面:

#################### SpringBoot服务管理器 #################### 当前时间: 2024-01-15 14:30:25 配置文件: /path/to/services.conf 日志目录: /path/to/logs ================== 服务列表 ================== 序号 服务名称 端口 状态 ----------------------------------------------- 1 user-service 8080 运行中 (PID: 1234, Port: 8080) 2 order-service 8081 已停止 3 payment-service 8082 启动中 (PID: 5678) ===============================================

界面直观清晰,服务状态一目了然,支持实时状态更新和彩色状态标识。

🚀 智能服务管理

1. 配置驱动的服务管理

通过简单的配置文件管理所有服务:

# services.conf 配置格式 # 服务名称|JAR路径|端口|环境|JVM参数 user-service|/opt/apps/user-service.jar|8080|prod|-Xms512m -Xmx1024m order-service|/opt/apps/order-service.jar|8081|prod|-Xms256m -Xmx512m

这种配置方式的优势:
统一管理:所有服务配置集中管理
灵活配置:支持不同JVM参数和环境配置
易于维护:修改配置无需改动脚本

2. 智能启停机制

优雅启动流程:

检查JAR文件 → 验证端口可用性 → 构建启动命令 → 后台启动服务 → 健康检查 → 状态确认

安全停止流程:

发送TERM信号 → 等待优雅停止 → 超时强制终止 → 状态确认

这种机制确保服务启停的可靠性,避免了常见的端口占用和进程残留问题。

📊 全方位监控功能

1. 实时状态监控
==================== 服务详细信息 ==================== 服务名称: user-service 运行状态: 运行中 (PID: 1234, Port: 8080) 内存使用: 345.6 MB CPU使用: 12.5% 启动时间: Dec 15 14:30 日志大小: 25.3M ======================================================
2. 系统资源监控
==================== 系统资源信息 ==================== CPU使用率: 15.2% 内存使用: 4.2G / 8.0G 磁盘使用: 25G / 50G (52%) Java进程: 3个运行中 ======================================================

这些监控信息帮助运维人员及时发现性能瓶颈和资源问题。

📝 智能日志管理

支持多种日志查看方式:

实时跟踪tail -f实时查看最新日志
历史查看:查看指定行数的历史日志
全文浏览:使用less命令浏览完整日志
日志轮转:自动管理日志文件大小

日志管理界面:

请选择查看方式: 1) 查看最后50行 2) 查看最后100行 3) 实时跟踪日志 4) 查看全部日志

🔧 批量操作支持

微服务架构下,批量操作必不可少:

==================== 批量操作菜单 ==================== 1) 启动所有服务 2) 停止所有服务 3) 重启所有服务 4) 查看所有服务状态 ======================================================

批量操作特别适用于:
系统重启后的服务恢复
版本发布时的服务更新
故障处理时的快速响应

自动化部署解决方案

除了服务管理,还提供了完整的自动化部署脚本:

🎯 一键部署流程

./deploy.sh deploy app-1.0.0.jar

部署流程包括:
1. 环境检查:验证部署环境和依赖
2. 版本备份:自动备份当前运行版本
3. 服务停止:优雅停止当前服务
4. 文件部署:复制新版本到部署目录
5. 服务启动:启动新版本服务
6. 健康检查:验证服务是否正常运行
7. 清理备份:保留最近5个版本备份

🔄 安全回滚机制

当部署出现问题时:

./deploy.sh rollback

回滚流程:

  • • 自动查找最新备份版本

  • • 停止问题版本服务

  • • 恢复备份文件

  • • 重启服务并验证

这种设计确保了部署过程的安全性,即使出现问题也能快速恢复。

实战应用场景

场景1:微服务集群管理

某电商公司有用户服务、订单服务、支付服务等10个微服务:

传统方式

  • • 需要登录到每台服务器

  • • 手动执行启停命令

  • • 分别查看各服务日志

  • • 耗时30分钟+

使用脚本后

  • • 一个界面管理所有服务

  • • 批量操作3分钟完成

  • • 状态监控一目了然

  • • 效率提升10倍

场景2:版本发布管理

发布前

# 查看当前所有服务状态 选择批量操作 → 查看所有服务状态

发布过程

# 逐个服务更新 ./deploy.sh deploy user-service-v2.0.jar ./deploy.sh deploy order-service-v2.0.jar

发布验证

# 健康检查和监控 ./deploy.sh health

场景3:故障应急处理

当生产环境出现问题:

1. 快速定位:通过状态监控快速识别问题服务
2. 日志分析:实时查看相关服务日志
3. 紧急处理:重启问题服务或快速回滚
4. 影响评估:查看系统资源使用情况

最佳实践建议

1. 配置管理

  • • 使用版本控制管理配置文件

  • • 不同环境使用不同的配置

  • • 定期备份配置文件

2. 监控告警

  • • 配合监控系统使用

  • • 设置关键指标告警

  • • 建立故障处理流程

3. 安全考虑

  • • 限制脚本执行权限

  • • 使用非root用户运行

  • • 定期清理敏感日志

4. 性能优化

  • • 合理配置JVM参数

  • • 监控服务资源使用

  • • 定期优化配置参数

总结

这套基于SHELL的SpringBoot服务管理解决方案通过可视化界面、智能管理机制、资源监控和自动化部署,可以极大提供服务管理效率。

它不仅大大提升了运维效率,还降低了操作风险,特别适合单机多服务和小规模微服务架构的部署场景。

如果你也在为SpringBoot应用的部署和管理而烦恼,不妨试试这套解决方案。相信它会让你的运维工作变得更加轻松高效!

脚本附录

springboot-service-manager

#!/bin/bash # SpringBoot服务管理脚本 - 可视化版本 # 支持多个服务的启动、停止、重启、状态查看等功能 # 配置目录 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CONFIG_FILE="$SCRIPT_DIR/services.conf" LOG_DIR="$SCRIPT_DIR/logs" # 创建必要目录 mkdir -p "$LOG_DIR" # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' WHITE='\033[1;37m' NC='\033[0m' # No Color # 加载服务配置 load_services() { if [[ ! -f "$CONFIG_FILE" ]]; then echo -e "${RED}配置文件不存在: $CONFIG_FILE${NC}" echo "请先创建配置文件,参考 services.conf.example" exit 1 fi # 清空服务数组 unset SERVICE_NAMES unset SERVICE_PATHS unset SERVICE_PORTS unset SERVICE_PROFILES unset SERVICE_JVM_OPTS declare -g -a SERVICE_NAMES=() declare -g -a SERVICE_PATHS=() declare -g -a SERVICE_PORTS=() declare -g -a SERVICE_PROFILES=() declare -g -a SERVICE_JVM_OPTS=() # 读取配置文件 while IFS='|' read -r name path port profile jvm_opts; do # 跳过注释和空行 [[ $name =~ ^#.*$ ]] && continue [[ -z "$name" ]] && continue SERVICE_NAMES+=("$name") SERVICE_PATHS+=("$path") SERVICE_PORTS+=("$port") SERVICE_PROFILES+=("$profile") SERVICE_JVM_OPTS+=("$jvm_opts") done < "$CONFIG_FILE" } # 获取服务PID get_service_pid() { local service_name=$1 local port=$2 # 先通过端口查找 if [[ -n "$port" ]]; then pid=$(lsof -ti:$port 2>/dev/null) if [[ -n "$pid" ]]; then echo $pid return fi fi # 通过jar文件名查找 pid=$(ps aux | grep java | grep -v grep | grep "$service_name" | awk '{print $2}') echo $pid } # 检查服务状态 check_service_status() { local index=$1 local service_name=${SERVICE_NAMES[$index]} local port=${SERVICE_PORTS[$index]} local pid=$(get_service_pid "$service_name" "$port") if [[ -n "$pid" ]]; then # 检查端口是否可访问 if [[ -n "$port" ]] && nc -z localhost $port 2>/dev/null; then echo -e "${GREEN}运行中${NC} (PID: $pid, Port: $port)" else echo -e "${YELLOW}启动中${NC} (PID: $pid)" fi return 0 else echo -e "${RED}已停止${NC}" return 1 fi } # 启动服务 start_service() { local index=$1 local service_name=${SERVICE_NAMES[$index]} local jar_path=${SERVICE_PATHS[$index]} local port=${SERVICE_PORTS[$index]} local profile=${SERVICE_PROFILES[$index]} local jvm_opts=${SERVICE_JVM_OPTS[$index]} echo -e "${BLUE}正在启动服务: $service_name${NC}" # 检查jar文件是否存在 if [[ ! -f "$jar_path" ]]; then echo -e "${RED}错误: JAR文件不存在 - $jar_path${NC}" return 1 fi # 检查服务是否已经运行 local pid=$(get_service_pid "$service_name" "$port") if [[ -n "$pid" ]]; then echo -e "${YELLOW}服务已经在运行中 (PID: $pid)${NC}" return 0 fi # 构建启动命令 local cmd="java" [[ -n "$jvm_opts" ]] && cmd="$cmd $jvm_opts" [[ -n "$profile" ]] && cmd="$cmd -Dspring.profiles.active=$profile" cmd="$cmd -jar $jar_path" # 启动服务 local log_file="$LOG_DIR/${service_name}.log" nohup $cmd > "$log_file" 2>&1 & local new_pid=$! echo "启动命令: $cmd" >> "$log_file" echo "启动时间: $(date)" >> "$log_file" echo "进程PID: $new_pid" >> "$log_file" echo "----------------------------------------" >> "$log_file" # 等待服务启动 echo -n "等待服务启动" for i in {1..30}; do sleep 1 echo -n "." if [[ -n "$port" ]] && nc -z localhost $port 2>/dev/null; then echo echo -e "${GREEN}服务启动成功!${NC} (PID: $new_pid, Port: $port)" return 0 fi done echo echo -e "${YELLOW}服务已启动,但端口检查超时${NC} (PID: $new_pid)" echo "请查看日志文件: $log_file" return 0 } # 停止服务 stop_service() { local index=$1 local service_name=${SERVICE_NAMES[$index]} local port=${SERVICE_PORTS[$index]} echo -e "${BLUE}正在停止服务: $service_name${NC}" local pid=$(get_service_pid "$service_name" "$port") if [[ -z "$pid" ]]; then echo -e "${YELLOW}服务未运行${NC}" return 0 fi # 优雅停止 echo "发送TERM信号..." kill -TERM $pid # 等待服务停止 echo -n "等待服务停止" for i in {1..15}; do sleep 1 echo -n "." if ! kill -0 $pid 2>/dev/null; then echo echo -e "${GREEN}服务已停止${NC}" return 0 fi done # 强制停止 echo echo "优雅停止超时,强制停止..." kill -KILL $pid 2>/dev/null sleep 2 if ! kill -0 $pid 2>/dev/null; then echo -e "${GREEN}服务已强制停止${NC}" return 0 else echo -e "${RED}服务停止失败${NC}" return 1 fi } # 重启服务 restart_service() { local index=$1 local service_name=${SERVICE_NAMES[$index]} echo -e "${BLUE}正在重启服务: $service_name${NC}" stop_service $index sleep 2 start_service $index } # 查看服务日志 view_service_log() { local index=$1 local service_name=${SERVICE_NAMES[$index]} local log_file="$LOG_DIR/${service_name}.log" if [[ ! -f "$log_file" ]]; then echo -e "${RED}日志文件不存在: $log_file${NC}" return 1 fi echo -e "${BLUE}查看服务日志: $service_name${NC}" echo "日志文件: $log_file" echo "----------------------------------------" # 选择查看方式 echo "请选择查看方式:" echo "1) 查看最后50行" echo "2) 查看最后100行" echo "3) 实时跟踪日志" echo "4) 查看全部日志" echo "0) 返回主菜单" read -p "请输入选择 [1-4]: " log_choice case $log_choice in 1) tail -50 "$log_file" ;; 2) tail -100 "$log_file" ;; 3) echo "按 Ctrl+C 退出实时跟踪" sleep 2 tail -f "$log_file" ;; 4) less "$log_file" ;; 0) return ;; *) echo -e "${RED}无效选择${NC}" ;; esac } # 显示服务详细信息 show_service_detail() { local index=$1 local service_name=${SERVICE_NAMES[$index]} local jar_path=${SERVICE_PATHS[$index]} local port=${SERVICE_PORTS[$index]} local profile=${SERVICE_PROFILES[$index]} local jvm_opts=${SERVICE_JVM_OPTS[$index]} clear echo -e "${CYAN}==================== 服务详细信息 ====================${NC}" echo -e "${WHITE}服务名称:${NC} $service_name" echo -e "${WHITE}JAR路径:${NC} $jar_path" echo -e "${WHITE}端口号:${NC} ${port:-未配置}" echo -e "${WHITE}环境配置:${NC} ${profile:-默认}" echo -e "${WHITE}JVM参数:${NC} ${jvm_opts:-默认}" local pid=$(get_service_pid "$service_name" "$port") echo -e "${WHITE}运行状态:${NC} $(check_service_status $index)" if [[ -n "$pid" ]]; then echo -e "${WHITE}进程PID:${NC} $pid" echo -e "${WHITE}内存使用:${NC} $(ps -p $pid -o rss= | awk '{printf "%.1f MB", $1/1024}')" echo -e "${WHITE}CPU使用:${NC} $(ps -p $pid -o %cpu= | awk '{print $1"%"}')" echo -e "${WHITE}启动时间:${NC} $(ps -p $pid -o lstart= | awk '{print $1" "$2" "$3" "$4}')" fi local log_file="$LOG_DIR/${service_name}.log" if [[ -f "$log_file" ]]; then echo -e "${WHITE}日志文件:${NC} $log_file" echo -e "${WHITE}日志大小:${NC} $(du -h "$log_file" | awk '{print $1}')" fi echo -e "${CYAN}======================================================${NC}" echo read -p "按回车键返回主菜单..." } # 显示系统资源使用情况 show_system_info() { clear echo -e "${CYAN}==================== 系统资源信息 ====================${NC}" # CPU使用率 cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | sed 's/%us,//') echo -e "${WHITE}CPU使用率:${NC} ${cpu_usage}%" # 内存使用情况 memory_info=$(free -h | grep Mem) total_mem=$(echo $memory_info | awk '{print $2}') used_mem=$(echo $memory_info | awk '{print $3}') echo -e "${WHITE}内存使用:${NC} $used_mem / $total_mem" # 磁盘使用情况 echo -e "${WHITE}磁盘使用:${NC}" df -h | grep -E '^/dev/' | awk '{printf " %s: %s / %s (%s)\n", $1, $3, $2, $5}' # Java进程信息 echo -e "${WHITE}Java进程:${NC}" ps aux | grep java | grep -v grep | while read line; do pid=$(echo $line | awk '{print $2}') mem=$(echo $line | awk '{print $4}') cmd=$(echo $line | awk '{for(i=11;i<=NF;i++) printf "%s ", $i; print ""}') echo " PID: $pid, MEM: ${mem}%, CMD: ${cmd:0:50}..." done echo -e "${CYAN}======================================================${NC}" echo read -p "按回车键返回主菜单..." } # 批量操作菜单 batch_operations_menu() { while true; do clear echo -e "${PURPLE}==================== 批量操作菜单 ====================${NC}" echo "1) 启动所有服务" echo "2) 停止所有服务" echo "3) 重启所有服务" echo "4) 查看所有服务状态" echo "0) 返回主菜单" echo -e "${PURPLE}======================================================${NC}" read -p "请输入选择 [0-4]: " batch_choice case $batch_choice in 1) echo -e "${BLUE}正在启动所有服务...${NC}" for ((i=0; i<${#SERVICE_NAMES[@]}; i++)); do start_service $i echo done read -p "按回车键继续..." ;; 2) echo -e "${BLUE}正在停止所有服务...${NC}" for ((i=0; i<${#SERVICE_NAMES[@]}; i++)); do stop_service $i echo done read -p "按回车键继续..." ;; 3) echo -e "${BLUE}正在重启所有服务...${NC}" for ((i=0; i<${#SERVICE_NAMES[@]}; i++)); do restart_service $i echo done read -p "按回车键继续..." ;; 4) clear echo -e "${CYAN}==================== 所有服务状态 ====================${NC}" printf "%-20s %-10s %-15s\n" "服务名称" "端口" "状态" echo "------------------------------------------------------" for ((i=0; i<${#SERVICE_NAMES[@]}; i++)); do status=$(check_service_status $i) printf "%-20s %-10s %s\n" "${SERVICE_NAMES[$i]}" "${SERVICE_PORTS[$i]}" "$status" done echo -e "${CYAN}======================================================${NC}" read -p "按回车键继续..." ;; 0) break ;; *) echo -e "${RED}无效选择,请重新输入${NC}" sleep 1 ;; esac done } # 服务管理菜单 service_management_menu() { local index=$1 local service_name=${SERVICE_NAMES[$index]} while true; do clear echo -e "${CYAN}==================== 服务管理: $service_name ====================${NC}" echo -e "当前状态: $(check_service_status $index)" echo echo "1) 启动服务" echo "2) 停止服务" echo "3) 重启服务" echo "4) 查看日志" echo "5) 服务详情" echo "0) 返回主菜单" echo -e "${CYAN}================================================================${NC}" read -p "请输入选择 [0-5]: " service_choice case $service_choice in 1) start_service $index read -p "按回车键继续..." ;; 2) stop_service $index read -p "按回车键继续..." ;; 3) restart_service $index read -p "按回车键继续..." ;; 4) view_service_log $index ;; 5) show_service_detail $index ;; 0) break ;; *) echo -e "${RED}无效选择,请重新输入${NC}" sleep 1 ;; esac done } # 主菜单 main_menu() { while true; do clear echo -e "${GREEN}#################### SpringBoot服务管理器 ####################${NC}" echo -e "${WHITE}当前时间: $(date '+%Y-%m-%d %H:%M:%S')${NC}" echo -e "${WHITE}配置文件: $CONFIG_FILE${NC}" echo -e "${WHITE}日志目录: $LOG_DIR${NC}" echo # 显示服务列表和状态 if [[ ${#SERVICE_NAMES[@]} -eq 0 ]]; then echo -e "${RED}未找到任何服务配置${NC}" else echo -e "${CYAN}================== 服务列表 ==================${NC}" printf "%-3s %-20s %-10s %-15s\n" "序号" "服务名称" "端口" "状态" echo "-----------------------------------------------" for ((i=0; i<${#SERVICE_NAMES[@]}; i++)); do status=$(check_service_status $i) printf "%-3s %-20s %-10s %s\n" "$((i+1))" "${SERVICE_NAMES[$i]}" "${SERVICE_PORTS[$i]}" "$status" done echo -e "${CYAN}===============================================${NC}" fi echo echo "操作选项:" echo "1-${#SERVICE_NAMES[@]}) 管理对应服务" echo "b) 批量操作" echo "s) 系统信息" echo "r) 重新加载配置" echo "q) 退出程序" echo -e "${GREEN}#########################################################${NC}" read -p "请输入选择: " main_choice case $main_choice in [1-9]|[1-9][0-9]) index=$((main_choice-1)) if [[ $index -ge 0 && $index -lt ${#SERVICE_NAMES[@]} ]]; then service_management_menu $index else echo -e "${RED}无效的服务序号${NC}" sleep 1 fi ;; b|B) batch_operations_menu ;; s|S) show_system_info ;; r|R) echo -e "${BLUE}重新加载配置文件...${NC}" load_services echo -e "${GREEN}配置加载完成${NC}" sleep 1 ;; q|Q) echo -e "${GREEN}感谢使用SpringBoot服务管理器!${NC}" exit 0 ;; *) echo -e "${RED}无效选择,请重新输入${NC}" sleep 1 ;; esac done } # 检查依赖命令 check_dependencies() { local missing_deps=() command -v java >/dev/null 2>&1 || missing_deps+=("java") command -v lsof >/dev/null 2>&1 || missing_deps+=("lsof") command -v nc >/dev/null 2>&1 || missing_deps+=("netcat") if [[ ${#missing_deps[@]} -ne 0 ]]; then echo -e "${RED}错误: 缺少必要的命令工具${NC}" echo "请安装以下工具: ${missing_deps[*]}" echo echo "Ubuntu/Debian: sudo apt-get install openjdk-8-jdk lsof netcat" echo "CentOS/RHEL: sudo yum install java-1.8.0-openjdk lsof nc" exit 1 fi } # 主程序入口 main() { # 检查依赖 check_dependencies # 加载服务配置 load_services # 显示欢迎信息 clear echo -e "${GREEN}" echo "########################################################" echo "# #" echo "# SpringBoot服务管理器 v1.0 #" echo "# #" echo "# 支持多服务管理、日志查看、状态监控 #" echo "# #" echo "########################################################" echo -e "${NC}" sleep 2 # 启动主菜单 main_menu } # 脚本执行入口 if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi

services.conf

# SpringBoot服务配置文件 # 格式: 服务名称|JAR文件路径|端口号|Profile环境|JVM参数 # 示例配置,请根据实际情况修改 # 测试服务 serveless-core|/opt/apps/serverless-core-1.0.0.jar|8080|prod|-Xms512m -Xmx1024m -XX:+UseG1GC # 注意事项: # 1. 每行一个服务配置 # 2. 使用 | 分隔各个字段 # 3. JAR文件路径必须是绝对路径 # 4. 端口号用于健康检查 # 5. Profile环境可以为空,默认使用default # 6. JVM参数可以为空,使用默认配置 # 7. 以#开头的行为注释行

deploy.sh

# SpringBoot服务部署脚本 # 自动化部署和管理SpringBoot应用 #!/bin/bash # 部署配置 APP_NAME="serverless-core" APP_VERSION="1.0.0" JAR_NAME="${APP_NAME}-${APP_VERSION}.jar" DEPLOY_DIR="/opt/apps" BACKUP_DIR="/opt/backups" SERVICE_PORT="8080" PROFILE="prod" # JVM参数配置 JVM_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200" JVM_OPTS="$JVM_OPTS -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps" JVM_OPTS="$JVM_OPTS -Xloggc:$DEPLOY_DIR/logs/gc.log -XX:+UseGCLogFileRotation" JVM_OPTS="$JVM_OPTS -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M" # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # 创建必要目录 setup_directories() { echo -e "${BLUE}创建部署目录...${NC}" mkdir -p "$DEPLOY_DIR" mkdir -p "$DEPLOY_DIR/logs" mkdir -p "$BACKUP_DIR" echo -e "${GREEN}目录创建完成${NC}" } # 备份当前版本 backup_current_version() { if [[ -f "$DEPLOY_DIR/$JAR_NAME" ]]; then echo -e "${BLUE}备份当前版本...${NC}" local backup_file="$BACKUP_DIR/${JAR_NAME}.$(date +%Y%m%d_%H%M%S).bak" cp "$DEPLOY_DIR/$JAR_NAME" "$backup_file" echo -e "${GREEN}备份完成: $backup_file${NC}" fi } # 部署新版本 deploy_new_version() { local jar_file=$1 if [[ ! -f "$jar_file" ]]; then echo -e "${RED}错误: JAR文件不存在 - $jar_file${NC}" return 1 fi echo -e "${BLUE}部署新版本...${NC}" # 停止当前服务 ./springboot-service-manager.sh stop "$APP_NAME" 2>/dev/null || true # 等待服务完全停止 sleep 3 # 复制新版本 cp "$jar_file" "$DEPLOY_DIR/$JAR_NAME" chmod +x "$DEPLOY_DIR/$JAR_NAME" echo -e "${GREEN}部署完成${NC}" } # 健康检查 health_check() { local max_attempts=30 local attempt=0 echo -e "${BLUE}进行健康检查...${NC}" while [[ $attempt -lt $max_attempts ]]; do if curl -s -f "http://localhost:$SERVICE_PORT/actuator/health" >/dev/null 2>&1; then echo -e "${GREEN}健康检查通过!${NC}" return 0 fi attempt=$((attempt + 1)) echo -n "." sleep 2 done echo echo -e "${RED}健康检查失败!${NC}" return 1 } # 回滚到上一版本 rollback() { echo -e "${YELLOW}开始回滚...${NC}" # 查找最新的备份文件 local latest_backup=$(ls -t "$BACKUP_DIR"/${JAR_NAME}.*.bak 2>/dev/null | head -1) if [[ -z "$latest_backup" ]]; then echo -e "${RED}没有找到备份文件${NC}" return 1 fi echo -e "${BLUE}回滚到: $latest_backup${NC}" # 停止当前服务 ./springboot-service-manager.sh stop "$APP_NAME" 2>/dev/null || true sleep 3 # 恢复备份 cp "$latest_backup" "$DEPLOY_DIR/$JAR_NAME" # 启动服务 ./springboot-service-manager.sh start "$APP_NAME" # 健康检查 if health_check; then echo -e "${GREEN}回滚成功!${NC}" else echo -e "${RED}回滚后健康检查失败${NC}" return 1 fi } # 完整部署流程 full_deploy() { local jar_file=$1 echo -e "${GREEN}开始部署 $APP_NAME${NC}" echo "JAR文件: $jar_file" echo "部署目录: $DEPLOY_DIR" echo "服务端口: $SERVICE_PORT" echo "环境配置: $PROFILE" echo "----------------------------------------" # 创建目录 setup_directories # 备份当前版本 backup_current_version # 部署新版本 if ! deploy_new_version "$jar_file"; then echo -e "${RED}部署失败${NC}" return 1 fi # 启动服务 echo -e "${BLUE}启动服务...${NC}" ./springboot-service-manager.sh start "$APP_NAME" # 健康检查 if health_check; then echo -e "${GREEN}部署成功!${NC}" # 清理旧备份(保留最近5个) echo -e "${BLUE}清理旧备份...${NC}" ls -t "$BACKUP_DIR"/${JAR_NAME}.*.bak 2>/dev/null | tail -n +6 | xargs rm -f echo -e "${GREEN}清理完成${NC}" else echo -e "${RED}部署失败,开始回滚...${NC}" rollback return 1 fi } # 显示使用帮助 show_help() { echo "SpringBoot应用部署脚本" echo echo "用法:" echo " $0 deploy <jar-file> - 部署新版本" echo " $0 rollback - 回滚到上一版本" echo " $0 health - 健康检查" echo " $0 setup - 初始化部署环境" echo echo "示例:" echo " $0 deploy app-1.0.0.jar" echo " $0 rollback" } # 主程序 main() { case "${1:-}" in deploy) if [[ -z "${2:-}" ]]; then echo -e "${RED}错误: 请指定JAR文件${NC}" show_help exit 1 fi full_deploy "$2" ;; rollback) rollback ;; health) health_check ;; setup) setup_directories ;; *) show_help ;; esac } main "$@"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1156495.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能体正在悄悄改变孩子们的游戏世界

元旦假期&#xff0c;带孩子回家。安抚孩子最快的方法是手机&#xff0c;但我又明令禁止&#xff0c;不要拿我手机看视频。莫莫说&#xff0c;那我和豆包聊天。我应允了&#xff0c;以为和以前一样&#xff0c;想和豆包做脑筋急转弯问答取乐。结果&#xff0c;她拿着我的手机&a…

如何通过AI提升电商广告投放效果

如何通过AI提升电商广告投放效果 关键词:AI、电商广告投放、效果提升、精准营销、数据分析 摘要:本文聚焦于如何利用AI技术提升电商广告投放效果。首先介绍了相关背景,包括目的范围、预期读者等内容。接着阐述了核心概念及联系,通过文本示意图和Mermaid流程图呈现。详细讲解…

JLink驱动开发入门必看:官方下载资源详解

JLink驱动开发入门必看&#xff1a;官方下载资源详解&#xff08;优化重写版&#xff09; 从“装不上”到“用得稳”&#xff1a;J-Link调试环境搭建的那些坑 你有没有遇到过这样的场景&#xff1f;新买了一块STM32开发板&#xff0c;兴冲冲插上J-Link仿真器&#xff0c;打开…

MCP应用:cursor+hexstrike-ai的安全实战

一、什么是 MCP&#xff1f;AI 的"操作系统接口" MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09;是一个标准化的通信协议&#xff0c;旨在解决 AI 模型与外部工具之间的交互难题。简单来说&#xff0c;它可以被理解为AI 的"操作…

51单片机(2)

一、GPIO&#xff1a;单片机与外界交互的“万能接口”GPIO&#xff0c;即General Purpose Input Output&#xff08;通用输入输出&#xff09;&#xff0c;是单片机最基础也是最核心的外设之一&#xff0c;堪称单片机与外部世界沟通的“桥梁”。其核心优势在于可独立配置&#…

3分钟完美解决键盘连击:智能防抖配置全攻略

3分钟完美解决键盘连击&#xff1a;智能防抖配置全攻略 【免费下载链接】KeyboardChatterBlocker A handy quick tool for blocking mechanical keyboard chatter. 项目地址: https://gitcode.com/gh_mirrors/ke/KeyboardChatterBlocker 还在为键盘连击问题而烦恼吗&…

ARM 的 A35 引领了近十年

今年在汇报工作的时候&#xff0c;提了一嘴 ARM cortex A35 &#xff0c;然后看了一下资料&#xff0c;这颗 IP核已经引领了近 10 年的SOC 市场&#xff0c;几乎覆盖了市面上主流的SOC 芯片。 看看 ARM cortex 核的发展「具体的可以看我的这篇文章」 尝试梳理下ARM处理器的发展…

WaveTools鸣潮工具箱:从游戏小白到高手的3个关键转折点

WaveTools鸣潮工具箱&#xff1a;从游戏小白到高手的3个关键转折点 【免费下载链接】WaveTools &#x1f9f0;鸣潮工具箱 项目地址: https://gitcode.com/gh_mirrors/wa/WaveTools 你是否曾经遇到过这样的困扰&#xff1a;精心调整的游戏画质设置&#xff0c;在实际战斗…

WaveTools鸣潮工具箱终极指南:从基础配置到深度优化

WaveTools鸣潮工具箱终极指南&#xff1a;从基础配置到深度优化 【免费下载链接】WaveTools &#x1f9f0;鸣潮工具箱 项目地址: https://gitcode.com/gh_mirrors/wa/WaveTools WaveTools鸣潮工具箱是专为《鸣潮》游戏玩家设计的综合性辅助工具&#xff0c;通过智能画质…

抹掉了精益敏捷devops的痕迹

企业在投入大量资源进行敏捷转型后&#xff0c;不仅未能达成预期效果&#xff0c;甚至完全退回旧模式&#xff0c;这种现象确实令人挫败。这通常不是单一原因造成的&#xff0c;而是多个关键环节的系统性失灵。下表梳理了导致转型失败并最终被放弃的常见原因及其典型表现。&…

5分钟学会使用《鸣潮》游戏优化工具:让卡顿彻底消失

5分钟学会使用《鸣潮》游戏优化工具&#xff1a;让卡顿彻底消失 【免费下载链接】WaveTools &#x1f9f0;鸣潮工具箱 项目地址: https://gitcode.com/gh_mirrors/wa/WaveTools 还在为《鸣潮》游戏卡顿而烦恼吗&#xff1f;这款游戏优化工具能够智能提升游戏性能&#x…

机器人学习!(二)ROS-基于Gazebo项目-YOLO(3)2026/01/13

项目二、基于ROSYOLO的目标检测与跟踪第一步、环境配置安装conda并换源# 1. 下载Miniconda&#xff08;国内镜像&#xff0c;速度快&#xff09; cd ~ wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh# 2. 安装&#xff08;静…

利用STM32 DAC模块生成波形:完整示例解析

用STM32 DAC打造嵌入式波形发生器&#xff1a;从原理到实战的完整指南你有没有遇到过这样的场景&#xff1f;需要一个正弦信号驱动传感器&#xff0c;或者想生成一段音频提示音&#xff0c;但手头又没有函数发生器。买一块专用芯片成本高、体积大&#xff0c;通信协议还麻烦——…

JLink烧录器使用教程:STM32 Flash编程操作指南

JLink烧录实战全指南&#xff1a;从零掌握STM32 Flash编程核心技巧你有没有遇到过这种情况——代码改了几十遍&#xff0c;每次用串口ISP下载都要等十几秒&#xff0c;开发效率被卡得死死的&#xff1f;或者产线批量烧录时&#xff0c;原厂工具速度慢、稳定性差&#xff0c;良率…

ESP32 SPI接口读写传感器:操作指南

ESP32驱动SPI传感器实战&#xff1a;从协议到代码的完整指南你有没有遇到过这样的场景&#xff1f;手里的BME280就是不回数据&#xff0c;串口打印全是0xFF&#xff1b;或者MPU6050读出来的加速度值疯狂跳变&#xff0c;像是在“跳舞”&#xff1b;又或者想挂两个SPI设备&#…

麦肯锡最新报告:人-AI-环境协同时代来了

麦肯锡最新报告揭示了一个颠覆性结论&#xff1a;AI并非取代人类劳动&#xff0c;而是通过重构人机协作模式释放生产力。到2030年&#xff0c;AI可能为美国经济贡献2.9万亿美元价值&#xff0c;但这一目标的实现不取决于技术本身&#xff0c;而在于人类如何与AI、环境形成共生关…

治疗心理疾病的良药:耕读,比如苏东坡、王阳明

近年来&#xff0c;一二线城市的青少年因学业、家庭等原因造成心理抑郁的有不少&#xff0c;而且有上升势头&#xff0c;昨天与几位朋友聊天&#xff0c;一位朋友提出了一个非常实用且有趣的思路&#xff1a;耕读&#xff01;不觉联想起一位在上海的师弟正在办的“农场”教育来…

Opensearch数据迁移:快照迁移数据全流程(下)

#作者&#xff1a;stackofumbrella 文章目录使用快照迁移数据注意事项在源集群注册快照仓库通过REST API注册快照仓库验证仓库是否注册成功在源集群创建快照文件创建快照查看同步状态在目标集群配置相同的快照仓库通过REST API注册相同名称的快照仓库验证仓库是否注册并导入成功…

STM32串口DMA实时性保障机制深度剖析

如何让STM32串口通信真正“零等待”&#xff1f;DMAIDLE机制实战全解析你有没有遇到过这样的场景&#xff1a;系统正在处理一个关键控制任务&#xff0c;突然蓝牙模块发来一串数据&#xff0c;结果因为串口中断太频繁&#xff0c;导致电机响应延迟&#xff1b;接收不定长JSON配…

OPC UA 服务端用户认证的底层逻辑:哈希与加盐应用详解

摘要在基于 Unified Automation SDK 开发 OPC UA 服务端时&#xff0c;用户认证&#xff08;User Authentication&#xff09;是安全体系的第一道防线。除了传输层的加密通道外&#xff0c;服务端如何安全地存储和验证用户信息至关重要。本文不涉及复杂的代码实现&#xff0c;而…