Shell脚本如何实现自动化回滚策略

wen 实用脚本 29

本文目录导读:

Shell脚本如何实现自动化回滚策略

  1. 基础回滚脚本框架
  2. 集成部署脚本
  3. 配置文件和钩子函数
  4. 使用示例
  5. 高级特性

使用Shell脚本实现自动化回滚策略,主要涉及备份机制、版本管理和回滚触发条件,下面提供一个完整的实现方案。

基础回滚脚本框架

#!/bin/bash
# 配置变量
APP_NAME="myapp"
DEPLOY_DIR="/var/www/$APP_NAME"
BACKUP_DIR="/backups/$APP_NAME"
CURRENT_LINK="$DEPLOY_DIR/current"
ROLLBACK_POINTS=5  # 保留最近5个回滚点
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() {
    echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
error() {
    echo -e "${RED}[ERROR]${NC} $1"
    exit 1
}
# 创建备份
create_backup() {
    local version=$1
    local backup_path="$BACKUP_DIR/$version"
    log "创建备份: $version"
    # 创建备份目录
    mkdir -p "$backup_path"
    # 备份当前部署(排除日志和缓存)
    rsync -a --exclude='logs/' --exclude='cache/' \
        "$CURRENT_LINK/" "$backup_path/"
    # 备份数据库(如果需要)
    if [ -f "$DEPLOY_DIR/db_config.sh" ]; then
        source "$DEPLOY_DIR/db_config.sh"
        mysqldump -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" > \
            "$backup_path/database.sql"
    fi
    # 记录备份元数据
    cat > "$backup_path/backup_meta.txt" << EOF
Backup Time: $(date '+%Y-%m-%d %H:%M:%S')
Version: $version
Previous Version: $(readlink -f "$CURRENT_LINK" 2>/dev/null || echo "initial")
EOF
    # 清理旧备份
    clean_old_backups
}
# 执行回滚
rollback() {
    local target_version=$1
    if [ ! -d "$BACKUP_DIR/$target_version" ]; then
        error "回滚版本 $target_version 不存在"
    fi
    log "开始回滚到版本: $target_version"
    # 停止服务
    systemctl stop "$APP_NAME"
    # 备份当前版本(以防需要再次回滚)
    current_version=$(get_current_version)
    create_backup "pre_rollback_$(date '+%Y%m%d_%H%M%S')"
    # 执行回滚
    rm -rf "$CURRENT_LINK"
    ln -sf "$BACKUP_DIR/$target_version" "$CURRENT_LINK"
    # 恢复数据库(如果需要)
    if [ -f "$BACKUP_DIR/$target_version/database.sql" ]; then
        log "恢复数据库..."
        source "$DEPLOY_DIR/db_config.sh"
        mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" < \
            "$BACKUP_DIR/$target_version/database.sql"
    fi
    # 执行回调钩子
    if [ -f "$DEPLOY_DIR/rollback_hooks.sh" ]; then
        source "$DEPLOY_DIR/rollback_hooks.sh"
        post_rollback "$target_version" "$current_version"
    fi
    # 启动服务
    systemctl start "$APP_NAME"
    # 健康检查
    if health_check; then
        log "回滚成功!当前版本: $target_version"
    else
        error "回滚后健康检查失败,请手动排查"
    fi
}
# 健康检查
health_check() {
    local max_attempts=30
    local attempt=0
    while [ $attempt -lt $max_attempts ]; do
        if curl -s -f "http://localhost/health" > /dev/null 2>&1; then
            return 0
        fi
        attempt=$((attempt + 1))
        sleep 1
    done
    return 1
}
# 清理旧备份
clean_old_backups() {
    local backup_list=$(ls -1t "$BACKUP_DIR")
    local count=0
    for backup in $backup_list; do
        count=$((count + 1))
        if [ $count -gt $ROLLBACK_POINTS ]; then
            rm -rf "$BACKUP_DIR/$backup"
            log "删除旧备份: $backup"
        fi
    done
}
# 获取当前版本
get_current_version() {
    readlink -f "$CURRENT_LINK" | awk -F'/' '{print $NF}'
}
# 显示版本列表
list_versions() {
    echo -e "${YELLOW}可用回滚版本:${NC}"
    ls -1t "$BACKUP_DIR" 2>/dev/null || echo "无可用备份"
}
# 自动回滚(部署失败时触发)
auto_rollback() {
    local deploy_version=$1
    log "自动回滚部署版本: $deploy_version"
    # 查找部署前的版本
    local previous_version=$(cat "$BACKUP_DIR/$deploy_version/backup_meta.txt" | \
        grep "Previous Version" | awk -F': ' '{print $2}')
    if [ -n "$previous_version" ] && [ -d "$BACKUP_DIR/$previous_version" ]; then
        rollback "$previous_version"
    else
        # 如果没有找到前一个版本,使用最后一个稳定版本
        local last_stable=$(ls -1t "$BACKUP_DIR" | head -2 | tail -1)
        if [ -n "$last_stable" ]; then
            rollback "$last_stable"
        else
            error "无法找到可回滚的版本"
        fi
    fi
}
# 主函数
main() {
    case "$1" in
        create)
            create_backup "$2"
            ;;
        rollback)
            rollback "$2"
            ;;
        auto)
            auto_rollback "$2"
            ;;
        list)
            list_versions
            ;;
        *)
            echo "用法: $0 {create|rollback|auto|list} [version]"
            exit 1
            ;;
    esac
}
main "$@"

集成部署脚本

#!/bin/bash
# deploy_with_rollback.sh - 带自动回滚的部署脚本
source "$(dirname "$0")/rollback.sh"
DEPLOY_VERSION="v$(date '+%Y%m%d_%H%M%S')"
SOURCE_DIR="/tmp/$APP_NAME-$DEPLOY_VERSION"
deploy() {
    log "开始部署版本: $DEPLOY_VERSION"
    # 1. 创建新版本目录
    mkdir -p "$SOURCE_DIR"
    # 2. 拉取代码(示例)
    git clone -b main "$REPO_URL" "$SOURCE_DIR" 2>/dev/null || error "git clone 失败"
    # 3. 安装依赖
    cd "$SOURCE_DIR"
    npm install 2>/dev/null || { auto_rollback "$DEPLOY_VERSION"; exit 1; }
    npm run build 2>/dev/null || { auto_rollback "$DEPLOY_VERSION"; exit 1; }
    # 4. 备份当前版本
    create_backup "$DEPLOY_VERSION"
    # 5. 切换版本
    rm -f "$CURRENT_LINK"
    ln -sf "$SOURCE_DIR" "$CURRENT_LINK"
    # 6. 重启服务
    systemctl restart "$APP_NAME"
    # 7. 健康检查
    if ! health_check; then
        log "部署后健康检查失败,触发自动回滚"
        auto_rollback "$DEPLOY_VERSION"
        exit 1
    fi
    log "部署成功! 版本: $DEPLOY_VERSION"
}
deploy

配置文件和钩子函数

# rollback_config.sh - 配置文件
# 应用配置
APP_NAME="myapp"
DEPLOY_DIR="/var/www/$APP_NAME"
BACKUP_DIR="/backups/$APP_NAME"
REPO_URL="https://github.com/user/repo.git"
# 保留最近的回滚点数量
ROLLBACK_POINTS=5
# 健康检查配置
HEALTH_CHECK_URL="http://localhost/health"
HEALTH_CHECK_TIMEOUT=30
HEALTH_CHECK_RETRY_INTERVAL=2
# 数据库配置
DB_HOST="localhost"
DB_NAME="myapp_db"
DB_USER="db_user"
DB_PASS="db_password"
# 通知配置
ENABLE_NOTIFICATIONS=true
NOTIFICATION_EMAIL="admin@example.com"
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/xxx"
# rollback_hooks.sh - 回滚钩子函数
post_rollback() {
    local target_version=$1
    local previous_version=$2
    log "执行回滚后钩子函数"
    # 清理缓存
    if [ -d "$CURRENT_LINK/var/cache" ]; then
        rm -rf "$CURRENT_LINK/var/cache/*"
        log "清理应用缓存"
    fi
    # 重启队列服务
    if systemctl list-units --type=service | grep -q "$APP_NAME-worker"; then
        systemctl restart "$APP_NAME-worker"
        log "重启队列服务"
    fi
    # 发送通知
    if [ "$ENABLE_NOTIFICATIONS" = true ]; then
        send_notification "回滚完成" "版本从 $previous_version 回滚到 $target_version"
    fi
}
send_notification() {
    local subject=$1
    local message=$2
    # 邮件通知
    echo "$message" | mail -s "[$APP_NAME] $subject" "$NOTIFICATION_EMAIL"
    # Slack通知
    if [ -n "$SLACK_WEBHOOK_URL" ]; then
        curl -s -X POST -H 'Content-type: application/json' \
            --data "{\"text\":\"[$APP_NAME] $subject: $message\"}" \
            "$SLACK_WEBHOOK_URL" > /dev/null 2>&1
    fi
}

使用示例

# 1. 创建备份
./rollback.sh create "v20240301"
# 2. 手动回滚到指定版本
./rollback.sh rollback "v20240301"
# 3. 查看可用版本
./rollback.sh list
# 4. 自动化部署(含自动回滚)
./deploy_with_rollback.sh
# 5. 自动回滚到上一个版本
./rollback.sh auto "v20240301"

高级特性

灰度发布支持

# canary_deploy.sh - 金丝雀发布
CANARY_RATIO=10  # 10%的流量
canary_deploy() {
    local new_version=$1
    # 部署到金丝雀服务器
    create_backup "$new_version"
    # 配置负载均衡器将10%流量导向新版本
    configure_load_balancer "canary" $CANARY_RATIO
    # 监控一段时间
    sleep 300
    # 如果监控无异常,全量发布
    if ! check_canary_metrics; then
        auto_rollback "$new_version"
        return 1
    fi
    # 全量发布
    rollback_to_canary "$new_version"
}

数据库版本管理

# db_migration.sh - 数据库迁移管理
rollback_database() {
    local target_version=$1
    local migration_dir="$BACKUP_DIR/$target_version/migrations"
    if [ -d "$migration_dir" ]; then
        # 按时间逆序执行回滚脚本
        for migration in $(ls -1r "$migration_dir"/*.sql); do
            log "执行数据库回滚: $(basename $migration)"
            mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$migration"
        done
    fi
}

这个方案提供了完整的回滚功能,包括备份管理、自动回滚、健康检查、通知告警等特性,可以根据具体需求进行定制和扩展。

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