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

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

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

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

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

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

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

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

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

🎯 可视化操作界面

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

bash 复制代码
#################### 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. 配置驱动的服务管理

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

bash 复制代码
# 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. 智能启停机制

优雅启动流程:

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

安全停止流程:

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

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

📊 全方位监控功能

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

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

📝 智能日志管理

支持多种日志查看方式:

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

日志管理界面:

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

🔧 批量操作支持

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

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

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

自动化部署解决方案

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

🎯 一键部署流程

bash 复制代码
./deploy.sh deploy app-1.0.0.jar

部署流程包括:

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

🔄 安全回滚机制

当部署出现问题时:

bash 复制代码
./deploy.sh rollback

回滚流程:

  • 自动查找最新备份版本
  • 停止问题版本服务
  • 恢复备份文件
  • 重启服务并验证

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

实战应用场景

场景1:微服务集群管理

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

传统方式

  • 需要登录到每台服务器
  • 手动执行启停命令
  • 分别查看各服务日志
  • 耗时30分钟+

使用脚本后

  • 一个界面管理所有服务
  • 批量操作3分钟完成
  • 状态监控一目了然
  • 效率提升10倍

场景2:版本发布管理

发布前

bash 复制代码
# 查看当前所有服务状态
选择批量操作 → 查看所有服务状态

发布过程

bash 复制代码
# 逐个服务更新
./deploy.sh deploy user-service-v2.0.jar
./deploy.sh deploy order-service-v2.0.jar

发布验证

bash 复制代码
# 健康检查和监控
./deploy.sh health

场景3:故障应急处理

当生产环境出现问题:

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

最佳实践建议

1. 配置管理

  • 使用版本控制管理配置文件
  • 不同环境使用不同的配置
  • 定期备份配置文件

2. 监控告警

  • 配合监控系统使用
  • 设置关键指标告警
  • 建立故障处理流程

3. 安全考虑

  • 限制脚本执行权限
  • 使用非root用户运行
  • 定期清理敏感日志

4. 性能优化

  • 合理配置JVM参数
  • 监控服务资源使用
  • 定期优化配置参数

总结

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

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

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

脚本附录

springboot-service-manager

bash 复制代码
#!/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

ruby 复制代码
# 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

bash 复制代码
# 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 "$@"
相关推荐
2025年一定要上岸几秒前
【Django】-10- 单元测试和集成测试(下)
数据库·后端·python·单元测试·django·集成测试
程序员海军13 分钟前
这才是Coding该有的样子!重新定义编程显示器
前端·后端
_風箏15 分钟前
Shell【脚本 05】交互式Shell脚本编写及问题处理([: ==: unary operator expected)[: ==: 期待一元表达式
后端
Cache技术分享15 分钟前
151. Java Lambda 表达式 - 使用 Consumer 接口处理对象
前端·后端
用户5769053080116 分钟前
Python实现一个类似MybatisPlus的简易SQL注解
后端·python
hello早上好19 分钟前
Spring AOP静态与动态通知的协作原理
后端·架构
MacroZheng36 分钟前
狂揽9.3k star!号称终端版Postman项目,太炫酷了!
java·spring boot·后端
Lemon程序馆42 分钟前
Mysql 常见的性能分析手段
数据库·后端·mysql
东阳马生架构44 分钟前
Dubbo源码—1.服务发布的主要流程
后端
meiguiyulu1 小时前
深入理解 CountdownLatch:多线程同步的得力助手
后端