Shell脚本如何实现批量回滚策略

wen 实用脚本 23

本文目录导读:

Shell脚本如何实现批量回滚策略

  1. 基础版本:文件版本管理回滚
  2. 进阶版本:带状态检查和回滚策略
  3. Git版本回滚方案
  4. Docker容器回滚
  5. 完整的批量回滚管理器
  6. 使用示例

我来详细介绍几种Shell脚本实现批量回滚策略的方法。

基础版本:文件版本管理回滚

#!/bin/bash
# 配置
BACKUP_DIR="/backup/app"
APP_DIR="/opt/myapp"
BACKUP_PREFIX="app_backup"
# 显示可用的备份列表
list_backups() {
    echo "可用的备份版本:"
    ls -1t $BACKUP_DIR/${BACKUP_PREFIX}_*.tar.gz 2>/dev/null | awk -F'_' '{print $NF}' | sed 's/\.tar\.gz//'
}
# 回滚到指定版本
rollback_to_version() {
    local version=$1
    local backup_file="${BACKUP_DIR}/${BACKUP_PREFIX}_${version}.tar.gz"
    if [ ! -f "$backup_file" ]; then
        echo "错误:备份文件不存在: $backup_file"
        return 1
    fi
    echo "开始回滚到版本: $version"
    # 停止应用
    systemctl stop myapp 2>/dev/null || killall myapp 2>/dev/null
    # 备份当前版本(可选)
    if [ "$2" != "--no-backup" ]; then
        tar -czf "${BACKUP_DIR}/pre_rollback_$(date +%Y%m%d_%H%M%S).tar.gz" $APP_DIR 2>/dev/null
    fi
    # 恢复指定版本
    rm -rf $APP_DIR/*
    tar -xzf "$backup_file" -C $APP_DIR
    # 设置权限
    chmod -R 755 $APP_DIR
    # 启动应用
    systemctl start myapp 2>/dev/null || nohup $APP_DIR/bin/start.sh &
    echo "回滚完成"
}
# 批量回滚(多个服务)
batch_rollback() {
    local services=("$@")
    local version=${services[0]}
    unset services[0]
    for service in "${services[@]}"; do
        echo "正在处理服务: $service"
        # 设置不同的应用目录
        local app_dir="/opt/$service"
        local backup_file="${BACKUP_DIR}/${service}_${version}.tar.gz"
        if [ -f "$backup_file" ]; then
            tar -xzf "$backup_file" -C $app_dir
            echo "服务 $service 回滚完成"
        else
            echo "警告:服务 $service 的备份文件不存在"
        fi
    done
}
# 主函数
case "$1" in
    list)
        list_backups
        ;;
    rollback)
        if [ -z "$2" ]; then
            echo "请指定版本号"
            exit 1
        fi
        rollback_to_version "$2" "$3"
        ;;
    batch)
        shift
        batch_rollback "$@"
        ;;
    *)
        echo "用法: $0 {list|rollback <version> [--no-backup]|batch <version> <service1> [service2...]}"
        ;;
esac

进阶版本:带状态检查和回滚策略

#!/bin/bash
# 配置文件
CONFIG_FILE="/etc/rollback.conf"
LOG_FILE="/var/log/rollback.log"
# 初始化日志
init_log() {
    exec 1>>$LOG_FILE 2>&1
    echo "=== $(date '+%Y-%m-%d %H:%M:%S') 开始回滚操作 ==="
}
# 读取配置文件
load_config() {
    if [ -f "$CONFIG_FILE" ]; then
        source "$CONFIG_FILE"
    else
        echo "配置文件 $CONFIG_FILE 不存在,使用默认配置"
        # 默认配置
        ROLLBACK_TIMEOUT=300
        MAX_RETRIES=3
        HEALTH_CHECK_URL="http://localhost:8080/health"
    fi
}
# 健康检查函数
health_check() {
    local url=${1:-$HEALTH_CHECK_URL}
    local timeout=${2:-30}
    for i in $(seq 1 $timeout); do
        if curl -s -f "$url" > /dev/null 2>&1; then
            echo "健康检查通过"
            return 0
        fi
        echo "等待服务启动... ($i/$timeout)"
        sleep 1
    done
    echo "健康检查失败"
    return 1
}
# 回滚前检查
pre_rollback_check() {
    local service=$1
    local app_dir=$2
    # 检查目录是否存在
    if [ ! -d "$app_dir" ]; then
        echo "错误:应用目录 $app_dir 不存在"
        return 1
    fi
    # 检查备份文件
    local backup_file="${BACKUP_DIR}/${service}_latest.tar.gz"
    if [ ! -f "$backup_file" ]; then
        echo "错误:备份文件 $backup_file 不存在"
        return 1
    fi
    return 0
}
# 执行回滚
execute_rollback() {
    local service=$1
    local version=$2
    local retry_count=0
    while [ $retry_count -lt $MAX_RETRIES ]; do
        echo "第 $((retry_count + 1)) 次尝试回滚 $service 到版本 $version"
        # 停止服务
        systemctl stop $service 2>/dev/null
        sleep 2
        # 恢复备份
        local backup_file="${BACKUP_DIR}/${service}_${version}.tar.gz"
        local app_dir=$(get_app_dir $service)
        # 备份当前版本
        tar -czf "${BACKUP_DIR}/${service}_current_backup.tar.gz" -C $app_dir . 2>/dev/null
        # 执行回滚
        rm -rf $app_dir/*
        tar -xzf "$backup_file" -C $app_dir
        # 启动服务
        systemctl start $service 2>/dev/null
        # 等待并检查健康状态
        sleep 5
        if health_check; then
            echo "服务 $service 回滚成功"
            return 0
        fi
        # 如果回滚失败,自动恢复
        echo "回滚失败,正在恢复..."
        tar -xzf "${BACKUP_DIR}/${service}_current_backup.tar.gz" -C $app_dir
        systemctl restart $service
        sleep 5
        ((retry_count++))
    done
    echo "服务 $service 回滚失败,已超过最大重试次数"
    return 1
}
# 批量回滚策略
batch_rollback_strategy() {
    local strategy=$1
    shift
    local services=("$@")
    local version=$1
    case $strategy in
        "sequential")
            # 顺序回滚
            for service in "${services[@]}"; do
                if ! execute_rollback "$service" "$version"; then
                    echo "顺序回滚在 $service 失败,停止后续回滚"
                    return 1
                fi
            done
            ;;
        "parallel")
            # 并行回滚
            for service in "${services[@]}"; do
                execute_rollback "$service" "$version" &
            done
            wait
            ;;
        "canary")
            # 金丝雀发布策略(先部分回滚)
            if [ ${#services[@]} -ge 2 ]; then
                # 先回滚一个实例验证
                echo "金丝雀回滚:先回滚 ${services[0]}"
                if execute_rollback "${services[0]}" "$version"; then
                    echo "金丝雀验证通过,继续回滚其他服务"
                    for ((i=1; i<${#services[@]}; i++)); do
                        execute_rollback "${services[$i]}" "$version"
                    done
                else
                    echo "金丝雀回滚失败,停止回滚"
                    return 1
                fi
            fi
            ;;
        "rolling")
            # 滚动回滚(逐个回滚,保持服务可用)
            local success_count=0
            local total=${#services[@]}
            for service in "${services[@]}"; do
                echo "滚动回滚:[$((success_count+1))/$total] $service"
                if execute_rollback "$service" "$version"; then
                    ((success_count++))
                else
                    echo "滚动回滚在 $service 失败"
                    # 可以选择继续或停止
                    # return 1
                fi
            done
            echo "滚动回滚完成:$success_count/$total 成功"
            ;;
        *)
            echo "不支持的策略: $strategy"
            echo "支持: sequential, parallel, canary, rolling"
            return 1
            ;;
    esac
}
# 获取应用目录(根据服务名)
get_app_dir() {
    local service=$1
    # 可以根据实际配置调整
    if [[ $service == *"app"* ]]; then
        echo "/opt/$service"
    else
        echo "/opt/$service"
    fi
}
# 主函数
main() {
    init_log
    load_config
    local command=$1
    shift
    case $command in
        "rollback")
            # 用法: rollback <version> <service> [--force]
            local version=$1
            local service=$2
            local force=$3
            if [ "$force" == "--force" ]; then
                echo "强制执行回滚..."
            fi
            if pre_rollback_check "$service" "$(get_app_dir $service)" || [ "$force" == "--force" ]; then
                execute_rollback "$service" "$version"
            else
                echo "回滚前检查失败"
                exit 1
            fi
            ;;
        "batch")
            # 用法: batch <strategy> <version> <service1> [service2...]
            local strategy=$1
            local version=$2
            shift 2
            batch_rollback_strategy "$strategy" "$version" "$@"
            ;;
        *)
            echo "用法: $0 {rollback|batch}"
            echo "  rollback <version> <service> [--force]"
            echo "  batch <strategy> <version> <service1> [service2...]"
            echo ""
            echo "策略说明:"
            echo "  sequential - 顺序回滚"
            echo "  parallel - 并行回滚"
            echo "  canary - 金丝雀回滚"
            echo "  rolling - 滚动回滚"
            ;;
    esac
}
# 执行主函数
main "$@"

Git版本回滚方案

#!/bin/bash
# Git仓库批量回滚
git_batch_rollback() {
    local repos=("$1")  # 仓库列表
    local target_commit=$2
    local branch=${3:-"master"}
    for repo in "${repos[@]}"; do
        echo "处理仓库: $repo"
        cd "$repo" || {
            echo "无法进入目录: $repo"
            continue
        }
        # 保存当前状态
        current_branch=$(git rev-parse --abbrev-ref HEAD)
        # 创建回滚分支
        rollback_branch="rollback/$(date +%Y%m%d_%H%M%S)"
        git branch "$rollback_branch"
        # 执行回滚
        git checkout "$branch"
        git pull origin "$branch"
        git reset --hard "$target_commit"
        # 强制推送(小心使用)
        git push origin "$branch" --force
        if [ $? -eq 0 ]; then
            echo "仓库 $repo 回滚到 $target_commit 成功"
        else
            echo "仓库 $repo 回滚失败"
            # 回滚到之前的状态
            git checkout "$current_branch"
        fi
    done
}
# 使用示例
# git_batch_rollback "/var/www/project1 /var/www/project2" "abc123def" "main"

Docker容器回滚

#!/bin/bash
# Docker容器批量回滚
docker_batch_rollback() {
    local services=($1)
    local image_tag=$2
    local registry=${3:-"registry.example.com"}
    for service in "${services[@]}"; do
        echo "回滚服务: $service"
        # 获取当前版本
        current_version=$(docker inspect --format '{{.Config.Image}}' $service 2>/dev/null)
        # 拉取旧版本镜像
        docker pull "${registry}/${service}:${image_tag}"
        # 停止并移除容器
        docker stop "$service" 2>/dev/null
        docker rm "$service" 2>/dev/null
        # 启动旧版本
        docker run -d \
            --name "$service" \
            --restart always \
            "${registry}/${service}:${image_tag}"
        # 检查运行状态
        sleep 3
        if docker ps --filter "name=$service" --filter "status=running" | grep -q "$service"; then
            echo "服务 $service 回滚成功"
        else
            echo "服务 $service 回滚失败,检查日志..."
            docker logs "$service" --tail 20
        fi
    done
}
# Kubernetes版本回滚
k8s_rollback() {
    local deployments=($1)
    local revision=$2
    for deploy in "${deployments[@]}"; do
        echo "回滚 deployment: $deploy"
        # 查看可用版本
        kubectl rollout history deployment "$deploy"
        # 执行回滚
        if [ -n "$revision" ]; then
            kubectl rollout undo deployment "$deploy" --to-revision="$revision"
        else
            kubectl rollout undo deployment "$deploy"
        fi
        # 等待回滚完成
        kubectl rollout status deployment "$deploy" --timeout=300s
        if [ $? -eq 0 ]; then
            echo "Deployment $deploy 回滚成功"
        else
            echo "Deployment $deploy 回滚失败"
        fi
    done
}

完整的批量回滚管理器

#!/bin/bash
# 配置文件
ROLLBACK_CONFIG="rollback.conf"
SERVICE_LIST="services.txt"
# 创建示例配置文件
create_config() {
    cat > "$ROLLBACK_CONFIG" << 'EOF'
# 回滚配置
BACKUP_DIR="/backup"
ROLLBACK_TIMEOUT=300
HEALTH_CHECK_INTERVAL=5
MAX_RETRY=3
NOTIFY_EMAIL="admin@example.com"
EOF
    cat > "$SERVICE_LIST" << 'EOF'
# 服务名 应用目录 启动命令 健康检查URL
myapp /opt/myapp "systemctl start myapp" http://localhost:8080/health
api-gateway /opt/gateway "systemctl start gateway" http://localhost:9090/health
auth-service /opt/auth "systemctl start auth" http://localhost:8081/health
EOF
}
# 批量回滚管理器
rollback_manager() {
    local action=$1
    local version=$2
    # 加载服务列表
    while IFS=' ' read -r service_name app_dir start_cmd health_url; do
        # 跳过注释和空行
        [[ $service_name =~ ^#.*$ || -z $service_name ]] && continue
        echo "========================"
        echo "处理服务: $service_name"
        echo "目录: $app_dir"
        echo "========================="
        case $action in
            "rollback")
                # 执行回滚
                backup_file="${BACKUP_DIR}/${service_name}_${version}.tar.gz"
                if [ ! -f "$backup_file" ]; then
                    echo "备份文件不存在: $backup_file"
                    send_notification "$service_name" "失败" "备份文件不存在"
                    continue
                fi
                # 停止服务
                eval "$start_cmd stop" 2>/dev/null
                # 备份当前版本
                tar -czf "${BACKUP_DIR}/${service_name}_pre_rollback.tar.gz" -C "$app_dir" . 2>/dev/null
                # 恢复指定版本
                rm -rf "$app_dir"/*
                tar -xzf "$backup_file" -C "$app_dir"
                # 启动服务
                eval "$start_cmd start" 2>/dev/null
                # 健康检查
                sleep $HEALTH_CHECK_INTERVAL
                if curl -s -f "$health_url" > /dev/null 2>&1; then
                    echo "服务 $service_name 回滚成功"
                    send_notification "$service_name" "成功" "已回滚到版本 $version"
                else
                    echo "服务 $service_name 健康检查失败,执行回滚恢复"
                    # 恢复之前的版本
                    tar -xzf "${BACKUP_DIR}/${service_name}_pre_rollback.tar.gz" -C "$app_dir"
                    eval "$start_cmd restart"
                    send_notification "$service_name" "失败" "健康检查失败,已自动恢复"
                fi
                ;;
            "list")
                echo "可用备份:"
                ls -1 ${BACKUP_DIR}/${service_name}_*.tar.gz 2>/dev/null | awk -F'/' '{print $NF}'
                ;;
        esac
    done < "$SERVICE_LIST"
}
# 发送通知
send_notification() {
    local service=$1
    local status=$2
    local message=$3
    echo "[NOTIFICATION] Service: $service, Status: $status, Message: $message"
    # 实际可以添加邮件、钉钉等通知
    # mail -s "Rollback Report" "$NOTIFY_EMAIL" <<< "$message"
}
# 主程序
main() {
    # 检查配置
    if [ ! -f "$ROLLBACK_CONFIG" ]; then
        echo "配置文件不存在,创建默认配置..."
        create_config
    fi
    source "$ROLLBACK_CONFIG"
    # 检查参数
    if [ $# -lt 1 ]; then
        echo "用法: $0 {create-config|list|rollback <version>}"
        echo "  create-config  - 创建示例配置文件"
        echo "  list          - 列出所有备份"
        echo "  rollback      - 执行批量回滚"
        exit 1
    fi
    case $1 in
        "create-config")
            create_config
            echo "配置文件已创建: $ROLLBACK_CONFIG, $SERVICE_LIST"
            ;;
        "list")
            rollback_manager "list"
            ;;
        "rollback")
            if [ -z "$2" ]; then
                echo "请指定回滚版本"
                exit 1
            fi
            rollback_manager "rollback" "$2"
            ;;
        *)
            echo "未知命令: $1"
            exit 1
            ;;
    esac
}
# 执行
main "$@"

使用示例

# 1. 创建配置
./rollback.sh create-config
# 2. 列出可用备份
./rollback.sh list
# 3. 批量回滚到指定版本
./rollback.sh rollback "20231201_120000"
# 4. 高级用法:使用不同策略
./rollback_manager.sh batch rolling "v1.2.1" service1 service2 service3
./rollback_manager.sh batch canary "v1.2.1" service1 service2 service3

这些脚本提供了从简单到复杂的批量回滚策略,可以根据实际需求选择合适的版本,记住在生产环境中使用前一定要充分测试!

抱歉,评论功能暂时关闭!