找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2531

积分

1

好友

352

主题
发表于 14 小时前 | 查看: 4| 回复: 0

在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. 配置驱动的服务管理

所有服务通过一个简单的配置文件进行集中管理,大大提升了Java应用栈的配置效率。

# 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 命令实时查看最新日志。
  • 历史查看:查看指定行数(如最后50或100行)的历史日志。
  • 全文浏览:使用 less 命令浏览完整的日志文件。
  • 日志轮转:可结合外部工具实现日志文件的自动轮转与管理。

日志管理界面交互友好:

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

🔧 批量操作支持

在微服务架构下,批量操作是提升运维/DevOps/SRE效率的关键。脚本提供了直观的批量操作菜单。

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

批量操作特别适用于以下场景:

  • 系统重启后的服务恢复
  • 版本发布时的服务更新
  • 故障处理时的快速响应

自动化部署解决方案

除了日常的服务管理,一套完整的自动化部署流程也必不可少。下面是一个配套的部署脚本示例。

🎯 一键部署流程

通过一个简单的命令即可完成整个部署流程:./deploy.sh deploy app-1.0.0.jar

部署流程严谨而全面:

  1. 环境检查:验证部署环境和必要的依赖。
  2. 版本备份:自动备份当前正在运行的版本。
  3. 服务停止:优雅停止当前服务。
  4. 文件部署:复制新版本JAR包到部署目录。
  5. 服务启动:启动新版本的服务。
  6. 健康检查:通过HTTP端点验证服务是否正常运行。
  7. 清理备份:智能保留最近5个版本备份,清理更旧的备份。

🔄 安全回滚机制

当新版本部署后出现问题,可以快速、安全地回滚到上一个稳定版本。

执行命令:./deploy.sh rollback

回滚流程自动完成:

  • 自动查找最新的备份版本文件。
  • 停止当前的问题版本服务。
  • 将备份文件恢复至部署目录。
  • 重启服务并进行健康验证。

这种设计确保了部署过程的安全性,即使新版本出现问题,也能在几分钟内快速恢复业务。

实战应用场景

场景1:微服务集群管理

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

  • 传统方式:需要登录每台服务器手动操作,分别查看日志,整个过程耗时超过30分钟。
  • 使用脚本后:在一个可视化界面中即可管理所有服务状态,批量操作(如重启所有服务)可在3分钟内完成,运维效率提升超过10倍。

场景2:版本发布管理

发布前:通过脚本查看所有服务的当前状态,确保发布基线稳定。
发布过程:使用部署脚本逐个或批量更新服务。
发布验证:利用脚本的健康检查功能或直接查看服务监控状态,快速确认发布结果。

场景3:故障应急处理

当生产环境突发故障时:

  1. 快速定位:通过脚本的状态监控界面,快速识别出异常服务(如状态为“已停止”或资源异常)。
  2. 日志分析:立即进入故障服务的日志查看界面,实时追踪或检索错误信息。
  3. 紧急处理:根据日志分析结果,选择重启问题服务或执行快速回滚。
  4. 影响评估:查看系统资源监控信息,评估故障的潜在影响范围。

最佳实践建议

为了更安全、高效地使用此类管理脚本,可以参考以下最佳实践:

1. 配置管理

  • services.conf 等配置文件纳入版本控制系统(如Git)进行管理。
  • 为开发、测试、生产等不同环境维护独立的配置文件。
  • 定期备份重要的配置文件。

2. 监控告警

  • 将此脚本作为基础监控的补充,与专业的监控系统(如Prometheus, Zabbix)配合使用。
  • 基于脚本获取的关键指标(如端口不可用、内存激增)设置告警。
  • 建立标准化的故障处理流程(Runbook)。

3. 安全考虑

  • 严格控制脚本的执行权限,遵循最小权限原则。
  • 使用专门的、非root的应用程序用户来运行SpringBoot服务。
  • 定期审查和清理日志文件中的敏感信息。

4. 性能优化

  • 在配置文件中根据服务特点合理配置JVM参数(堆内存、GC算法等)。
  • 利用脚本的监控功能,持续观察服务资源使用趋势,作为优化的依据。
  • 定期回顾和优化服务配置与部署参数。

总结

这套基于Bash Shell开发的SpringBoot服务管理解决方案,通过可视化界面降低了操作门槛,通过智能管理机制保障了操作可靠性,通过资源监控增强了运维可见性,并通过自动化部署提升了发布效率。它不仅极大地提升了运维效率,还显著降低了因手动操作失误带来的风险,特别适合单机多服务和小规模微服务集群的部署与管理场景。

如果你正在为SpringBoot应用的部署和日常管理寻找一个轻量级、高效率的解决方案,不妨尝试实现或借鉴文中的思路。完整的脚本代码已附在文末,可供参考和使用。希望这篇来自云栈社区的分享能帮助你让运维工作变得更加轻松、可控。

脚本附录

springboot-service-manager.sh

#!/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参数
    # 示例配置,请根据实际情况修改
    
    # 测试服务
    serverless-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 "$@"



    上一篇:前端开发中File与Blob的深度解析与应用实战
    下一篇:GitHub Trending 2026开年解析:Rust全栈、数据爬虫与Claude Code插件的三大技术趋势
    您需要登录后才可以回帖 登录 | 立即注册

    手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

    GMT+8, 2026-1-14 18:39 , Processed in 0.389013 second(s), 40 queries , Gzip On.

    Powered by Discuz! X3.5

    © 2025-2025 云栈社区.

    快速回复 返回顶部 返回列表