Shell脚本如何实现条件回滚策略

wen 实用脚本 24

本文目录导读:

Shell脚本如何实现条件回滚策略

  1. 基本回滚模式
  2. 使用函数实现回滚
  3. 带状态检查的回滚
  4. 事务型回滚模式
  5. 实用的部署回滚脚本
  6. 关键原则

在Shell脚本中实现条件回滚策略,通常用于处理复杂的操作序列,确保在某个步骤失败时能够安全地恢复到初始状态,以下是几种常见的实现方法:

基本回滚模式

#!/bin/bash
set -e  # 遇到错误立即退出
# 记录已执行的操作
declare -a executed_steps=()
declare -a rollback_commands=()
# 注册回滚命令
register_rollback() {
    rollback_commands+=("$1")
}
# 执行回滚
rollback() {
    echo "=== 开始回滚 ==="
    for (( i=${#rollback_commands[@]}-1; i>=0; i-- )); do
        echo "回滚步骤 $i: ${rollback_commands[$i]}"
        eval "${rollback_commands[$i]}" || echo "回滚步骤 $i 失败: ${rollback_commands[$i]}"
    done
    echo "=== 回滚完成 ==="
}
# 主流程
main() {
    # 步骤1: 创建文件
    echo "步骤1: 创建临时文件"
    touch /tmp/test_1.txt
    register_rollback "rm -f /tmp/test_1.txt"
    # 步骤2: 修改配置文件
    echo "步骤2: 修改配置"
    cp /etc/config /etc/config.backup
    register_rollback "cp /etc/config.backup /etc/config"
    # 步骤3: 执行可能失败的操作
    echo "步骤3: 执行关键操作"
    if ! some_command; then
        echo "步骤3 失败,开始回滚"
        rollback
        exit 1
    fi
    echo "所有步骤成功完成"
}
# 捕获退出信号
trap rollback EXIT
main

使用函数实现回滚

#!/bin/bash
# 回滚堆栈
ROLLBACK_STACK=()
# 压入回滚函数
push_rollback() {
    ROLLBACK_STACK+=("$1")
}
# 执行所有回滚
execute_rollback() {
    local total=${#ROLLBACK_STACK[@]}
    echo "执行 $total 个回滚操作"
    for (( i=total-1; i>=0; i-- )); do
        echo "执行回滚 #$i"
        eval "${ROLLBACK_STACK[$i]}"
    done
    ROLLBACK_STACK=()  # 清空堆栈
}
# 示例操作函数
create_file() {
    local file=$1
    echo "创建文件: $file"
    touch "$file" || return 1
    # 注册回滚
    local rollback_cmd="rm -f $file"
    push_rollback "$rollback_cmd"
}
copy_config() {
    local src=$1 dst=$2
    echo "复制配置: $src -> $dst"
    cp "$src" "$dst" || return 1
    # 注册回滚
    local rollback_cmd="cp $dst $src"
    push_rollback "$rollback_cmd"
}
start_service() {
    local service=$1
    echo "启动服务: $service"
    systemctl start "$service" || return 1
    # 注册回滚
    local rollback_cmd="systemctl stop $service"
    push_rollback "$rollback_cmd"
}
# 主函数
main() {
    # 执行操作序列
    create_file "/tmp/backup.tar.gz" || return 1
    copy_config "/etc/nginx/nginx.conf" "/tmp/nginx.conf.backup" || return 1
    start_service "nginx" || return 1
    echo "所有操作成功完成"
    return 0
}
# 执行并处理错误
if ! main; then
    echo "操作失败,执行回滚"
    execute_rollback
    exit 1
fi

带状态检查的回滚

#!/bin/bash
# 状态管理
STATE_FILE="/tmp/deploy_state.txt"
ROLLBACK_FILE="/tmp/rollback_commands.txt"
init_state() {
    > "$STATE_FILE"
    > "$ROLLBACK_FILE"
}
record_step() {
    local step=$1
    echo "$step" >> "$STATE_FILE"
}
record_rollback() {
    local command=$1
    echo "$command" >> "$ROLLBACK_FILE"
}
execute_rollback() {
    echo "=== 执行条件回滚 ==="
    # 读取状态文件
    local states=()
    while IFS= read -r line; do
        states+=("$line")
    done < "$ROLLBACK_FILE"
    # 逆序执行回滚
    for (( i=${#states[@]}-1; i>=0; i-- )); do
        local cmd="${states[$i]}"
        echo "执行回滚命令: $cmd"
        eval "$cmd" || {
            echo "回滚命令失败: $cmd"
            # 继续执行其他回滚
        }
    done
    # 清理状态文件
    rm -f "$STATE_FILE" "$ROLLBACK_FILE"
}
# 带条件的回滚
conditional_rollback() {
    local condition=$1
    local rollback_cmd=$2
    if [ "$condition" = "true" ]; then
        eval "$rollback_cmd"
        echo "条件回滚执行: $rollback_cmd"
    fi
}
# 示例使用
main() {
    init_state
    # 步骤1: 创建目录
    echo "步骤1: 创建应用目录"
    mkdir -p /var/www/new_app
    record_step "create_dir"
    record_rollback "rm -rf /var/www/new_app"
    # 步骤2: 复制文件
    echo "步骤2: 复制应用文件"
    cp -r /tmp/app/* /var/www/new_app/
    record_step "copy_files"
    record_rollback "rm -rf /var/www/new_app"
    # 步骤3: 设置权限
    echo "步骤3: 设置文件权限"
    chmod -R 755 /var/www/new_app
    record_step "set_permissions"
    # 检查磁盘空间
    available_space=$(df /var/www/new_app | awk 'NR==2 {print $4}')
    if [ "$available_space" -lt 1000000 ]; then
        echo "磁盘空间不足 (可用: $available_space KB)"
        execute_rollback
        exit 1
    fi
    echo "所有步骤完成"
}
# 执行主函数
main

事务型回滚模式

#!/bin/bash
# 事务管理器
TRANSACTION_LOG="/tmp/transaction.log"
ROLLBACK_LOG="/tmp/rollback.log"
begin_transaction() {
    echo "开始事务: $(date)" > "$TRANSACTION_LOG"
    echo "" > "$ROLLBACK_LOG"
}
commit_transaction() {
    echo "提交事务: $(date)" >> "$TRANSACTION_LOG"
    rm -f "$TRANSACTION_LOG" "$ROLLBACK_LOG"
}
rollback_transaction() {
    echo "回滚事务: $(date)" >> "$TRANSACTION_LOG"
    if [ -f "$ROLLBACK_LOG" ]; then
        echo "开始执行回滚..."
        while IFS= read -r line; do
            echo "回滚: $line"
            eval "$line" || echo "回滚失败: $line"
        done < "$ROLLBACK_LOG"
    fi
    # 清理
    rm -f "$TRANSACTION_LOG" "$ROLLBACK_LOG"
}
add_operation() {
    local description=$1
    local action=$2
    local rollback=$3
    echo "执行: $description"
    eval "$action" || {
        echo "操作失败: $description"
        rollback_transaction
        return 1
    }
    # 记录回滚命令
    echo "$rollback" >> "$ROLLBACK_LOG"
}
# 示例
main() {
    begin_transaction
    # 添加操作
    add_operation "创建备份" \
        "cp /etc/config /etc/config.bak" \
        "cp /etc/config.bak /etc/config" || exit 1
    add_operation "修改配置" \
        "echo 'new_config' > /etc/config" \
        "cp /etc/config.bak /etc/config" || exit 1
    add_operation "重启服务" \
        "systemctl restart nginx" \
        "systemctl restart nginx_old" || exit 1
    # 所有操作成功
    commit_transaction
    echo "所有操作成功完成"
}
main

实用的部署回滚脚本

#!/bin/bash
# 定义版本和回滚点
DEPLOY_DIR="/var/www/app"
BACKUP_DIR="/var/backups/app"
VERSION_FILE="$DEPLOY_DIR/version.txt"
# 创建备份点
create_checkpoint() {
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local checkpoint_dir="$BACKUP_DIR/checkpoint_$timestamp"
    echo "创建检查点: $checkpoint_dir"
    mkdir -p "$checkpoint_dir"
    cp -r "$DEPLOY_DIR"/* "$checkpoint_dir/"
    echo "$checkpoint_dir" > /tmp/current_checkpoint
    echo "$timestamp" > "$VERSION_FILE"
}
# 回滚到检查点
rollback_to_checkpoint() {
    local checkpoint=$(cat /tmp/current_checkpoint 2>/dev/null)
    if [ -z "$checkpoint" ] || [ ! -d "$checkpoint" ]; then
        echo "错误: 没有可用的检查点"
        return 1
    fi
    echo "回滚到: $checkpoint"
    # 停止服务
    systemctl stop nginx 2>/dev/null
    # 回滚文件
    rm -rf "$DEPLOY_DIR"/*
    cp -r "$checkpoint"/* "$DEPLOY_DIR/"
    # 启动服务
    systemctl start nginx 2>/dev/null
    echo "回滚完成"
}
# 带条件的部署
deploy() {
    local version=$1
    echo "开始部署版本: $version"
    # 条件检查
    if [ ! -f "/tmp/app_$version.tar.gz" ]; then
        echo "错误: 版本包不存在"
        return 1
    fi
    # 创建备份点
    create_checkpoint
    # 解压新版本
    tar -xzf "/tmp/app_$version.tar.gz" -C "$DEPLOY_DIR" || {
        echo "解压失败,执行回滚"
        rollback_to_checkpoint
        return 1
    }
    # 检查配置文件
    if [ ! -f "$DEPLOY_DIR/config/app.conf" ]; then
        echo "配置文件缺失,回滚"
        rollback_to_checkpoint
        return 1
    fi
    # 重启服务
    systemctl restart nginx || {
        echo "服务重启失败,回滚"
        rollback_to_checkpoint
        return 1
    }
    echo "部署成功"
}
# 主菜单
case "${1:-help}" in
    deploy)
        deploy "$2"
        ;;
    rollback)
        rollback_to_checkpoint
        ;;
    check)
        echo "当前版本: $(cat $VERSION_FILE 2>/dev/null || echo 'unknown')"
        ;;
    *)
        echo "用法: $0 {deploy|rollback|check} [version]"
        ;;
esac

关键原则

  1. 原子性: 确保操作要么全部成功,要么全部回滚
  2. 幂等性: 回滚操作应该是可重复执行的
  3. 状态记录: 使用文件或变量记录已执行的操作
  4. 错误处理: 捕获所有可能的失败场景
  5. 资源清理: 确保在脚本退出时清理临时资源

选择哪种模式取决于你的具体需求:

  • 简单操作:使用基本回滚模式
  • 复杂操作:使用函数或事务模式
  • 生产部署:使用检查点模式

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