Shell脚本如何实现蓝绿部署策略

wen 实用脚本 26

本文目录导读:

Shell脚本如何实现蓝绿部署策略

  1. 蓝绿部署的基本原理
  2. 完整实现脚本
  3. 高级特性
  4. 使用建议

我来为你详细介绍Shell脚本实现蓝绿部署策略的方法。

蓝绿部署的基本原理

蓝绿部署维护两套完全相同的生产环境:蓝色(当前运行)和绿色(待部署),流量在两者之间切换,实现零停机部署。

完整实现脚本

基础配置脚本

#!/bin/bash
# 配置参数
APP_NAME="myapp"
BLUE_DIR="/www/${APP_NAME}/blue"
GREEN_DIR="/www/${APP_NAME}/green"
NGINX_CONF="/etc/nginx/conf.d/${APP_NAME}.conf"
BACKUP_DIR="/backup/${APP_NAME}"
# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 错误处理
error_exit() {
    log "ERROR: $1"
    exit 1
}

部署核心函数

# 获取当前活跃环境
get_active_env() {
    # 检查nginx指向哪个目录
    if grep -q "$BLUE_DIR" "$NGINX_CONF" 2>/dev/null; then
        echo "blue"
    elif grep -q "$GREEN_DIR" "$NGINX_CONF" 2>/dev/null; then
        echo "green"
    else
        echo "unknown"
    fi
}
# 构建新版本
build_new_version() {
    local target_dir=$1
    local version_tag=$2
    log "开始构建新版本到 $target_dir"
    # 创建部署目录
    mkdir -p "$target_dir"
    # 构建或复制应用代码
    # 示例:从git拉取代码
    # git clone -b $version_tag https://github.com/yourrepo/app.git "$target_dir"
    # 或者复制本地构建的代码
    cp -r /tmp/build/* "$target_dir/"
    # 执行构建命令
    cd "$target_dir" && npm install 2>&1 || {
        log "构建失败"
        return 1
    }
    log "版本构建完成"
    return 0
}
# 部署到非活跃环境
deploy_to_inactive() {
    local active_env=$(get_active_env)
    local deploy_dir
    if [ "$active_env" = "blue" ]; then
        deploy_dir="$GREEN_DIR"
    elif [ "$active_env" = "green" ]; then
        deploy_dir="$BLUE_DIR"
    else
        # 首次部署,默认部署到blue
        deploy_dir="$BLUE_DIR"
    fi
    log "部署到非活跃环境: $deploy_dir"
    # 构建新版本
    build_new_version "$deploy_dir" "v1.2.0" || {
        error_exit "构建失败"
    }
    # 运行测试
    run_health_check "$deploy_dir" || {
        log "健康检查失败,回滚部署"
        return 1
    }
    echo "$deploy_dir"
}

切换流量函数

# 切换Nginx配置
switch_nginx() {
    local new_env=$1
    local new_dir
    if [ "$new_env" = "blue" ]; then
        new_dir="$BLUE_DIR"
        new_color="blue"
    else
        new_dir="$GREEN_DIR"
        new_color="green"
    fi
    log "切换Nginx到 $new_color 环境"
    # 备份当前配置
    cp "$NGINX_CONF" "${NGINX_CONF}.backup.$(date +%Y%m%d%H%M%S)"
    # 生成新配置
    cat > "$NGINX_CONF" << EOF
upstream ${APP_NAME}_backend {
    server 127.0.0.1:8000;  # 修改为实际端口
}
server {
    listen 80;
    server_name ${APP_NAME}.example.com;
    root ${new_dir};
    index index.html index.php;
    location / {
        try_files \$uri \$uri/ /index.php?\$query_string;
    }
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME ${new_dir}\$fastcgi_script_name;
        include fastcgi_params;
    }
}
EOF
    # 测试配置
    nginx -t || {
        log "Nginx配置测试失败,恢复备份"
        cp "${NGINX_CONF}.backup"* "$NGINX_CONF"
        return 1
    }
    # 重载Nginx
    systemctl reload nginx || nginx -s reload || {
        log "Nginx重载失败"
        return 1
    }
    log "Nginx配置切换成功"
    return 0
}
# 优雅切换(使用upstream)
graceful_switch() {
    local target_env=$1
    log "执行优雅切换到 $target_env"
    # 创建或更新upstream配置
    cat > "/etc/nginx/conf.d/${APP_NAME}_upstream.conf" << EOF
upstream ${APP_NAME}_backend {
    server 127.0.0.1:8001;  # 蓝环境
    server 127.0.0.1:8002;  # 绿环境
}
EOF
    # 根据目标环境调整权重
    if [ "$target_env" = "blue" ]; then
        # 逐渐将流量导向蓝环境
        for i in 10 30 50 70 90 100; do
            sed -i "s/server 127.0.0.1:8001 weight=[0-9]*/server 127.0.0.1:8001 weight=$i/" "/etc/nginx/conf.d/${APP_NAME}_upstream.conf"
            sed -i "s/server 127.0.0.1:8002 weight=[0-9]*/server 127.0.0.1:8002 weight=$((100-i))/" "/etc/nginx/conf.d/${APP_NAME}_upstream.conf"
            nginx -s reload
            sleep 5
        done
    fi
}

健康检查函数

# 健康检查
run_health_check() {
    local check_dir=$1
    local check_url="http://localhost:8080/health"
    log "执行健康检查..."
    # 检查进程是否运行
    if ! pgrep -f "node.*server.js" >/dev/null; then
        log "应用进程未运行"
        return 1
    fi
    # HTTP健康检查
    for i in {1..5}; do
        if curl -sf "$check_url" >/dev/null 2>&1; then
            log "健康检查通过"
            return 0
        fi
        sleep 2
    done
    log "健康检查失败"
    return 1
}
# 验证部署成功
verify_deployment() {
    local verify_url=$1
    local expected_content=$2
    log "验证部署..."
    # 发送测试请求
    response=$(curl -s "$verify_url")
    if echo "$response" | grep -q "$expected_content"; then
        log "部署验证通过"
        return 0
    else
        log "部署验证失败"
        return 1
    fi
}

回滚函数

# 回滚部署
rollback() {
    local previous_env=$1
    log "执行回滚到 $previous_env 环境"
    # 直接切换回之前的活跃环境
    switch_nginx "$previous_env" || {
        error_exit "回滚失败"
    }
    # 停止新环境
    stop_env "$(get_inactive_env)"
    log "回滚完成"
}
# 停止环境
stop_env() {
    local env_dir=$1
    local env_name=$(basename "$env_dir")
    log "停止 $env_name 环境"
    # 停止应用服务
    if [ -f "$env_dir/scripts/stop.sh" ]; then
        bash "$env_dir/scripts/stop.sh"
    fi
    # 清理进程
    pkill -f "$env_dir" 2>/dev/null || true
}

主部署流程

# 主部署函数
blue_green_deploy() {
    log "开始蓝绿部署..."
    # 1. 获取当前活跃环境
    local active_env=$(get_active_env)
    log "当前活跃环境: $active_env"
    # 2. 备份当前版本
    local backup_file="${BACKUP_DIR}/${APP_NAME}_${active_env}_$(date +%Y%m%d%H%M%S).tar.gz"
    tar -czf "$backup_file" -C "/www/${APP_NAME}/" "$active_env" 2>/dev/null || {
        log "备份失败,继续部署"
    }
    # 3. 部署到非活跃环境
    local deploy_dir=$(deploy_to_inactive)
    [ $? -eq 0 ] || {
        log "部署到非活跃环境失败"
        return 1
    }
    # 4. 预检查(可选)
    if [ -f "pre_check.sh" ]; then
        bash pre_check.sh "$deploy_dir" || {
            log "预检查失败"
            rollback "$active_env"
            return 1
        }
    fi
    # 5. 切换流量
    local new_env=$(basename "$deploy_dir")
    switch_nginx "$new_env" || {
        log "流量切换失败"
        rollback "$active_env"
        return 1
    }
    # 6. 验证新环境
    verify_deployment "http://test.example.com/health" "OK" || {
        log "新环境验证失败,执行回滚"
        rollback "$active_env"
        return 1
    }
    # 7. 保持旧环境一段时间(便于快速回滚)
    log "保持旧环境运行30分钟..."
    (sleep 1800 && clean_old_env "$active_env") &
    log "蓝绿部署成功完成!"
    return 0
}
# 清理旧环境
clean_old_env() {
    local old_env=$1
    local old_dir="/www/${APP_NAME}/$old_env"
    log "清理旧环境: $old_dir"
    # 询问确认
    read -p "确认删除旧环境? (y/n) " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        rm -rf "$old_dir"
        log "旧环境已清理"
    else
        log "保留旧环境"
    fi
}

使用示例

#!/bin/bash
# 加载部署脚本
source ./blue_green_deploy.sh
# 显示帮助信息
show_help() {
    echo "蓝绿部署管理脚本"
    echo "Usage:"
    echo "  ./deploy.sh deploy    - 执行蓝绿部署"
    echo "  ./deploy.sh status    - 查看部署状态"
    echo "  ./deploy.sh rollback  - 回滚到上一版本"
    echo "  ./deploy.sh clean     - 清理旧版本"
}
# 显示状态
show_status() {
    local active_env=$(get_active_env)
    echo "=================================="
    echo "应用状态:"
    echo "  活跃环境: $active_env"
    echo "  蓝环境: $([ -d "$BLUE_DIR" ] && echo '运行中' || echo '未部署')"
    echo "  绿环境: $([ -d "$GREEN_DIR" ] && echo '运行中' || echo '未部署')"
    echo ""
    echo "最后部署时间: $(stat -c %y "$BLUE_DIR" 2>/dev/null || echo 'N/A')"
    echo "=================================="
}
# 主程序
case "${1:-help}" in
    deploy)
        blue_green_deploy
        ;;
    status)
        show_status
        ;;
    rollback)
        local prev_env=$(get_inactive_env)
        rollback "$prev_env"
        ;;
    clean)
        local inactive_env=$(get_inactive_env)
        clean_old_env "$inactive_env"
        ;;
    help|*)
        show_help
        ;;
esac

高级特性

灰度发布扩展

# 灰度发布(渐进式切换)
canary_deploy() {
    local percentage=$1  # 10-90
    # 逐步增加新环境的流量比例
    for step in $(seq 10 $percentage 10); do
        log "设置流量比例: 新环境 $step%"
        set_traffic_weight $((100-step)) $step
        sleep 10
        # 监控错误率
        check_error_rate || {
            log "错误率异常,执行回滚"
            return 1
        }
    done
    return 0
}

数据库兼容性检查

# 数据库迁移检查
check_db_migration() {
    local new_version=$1
    # 检查数据库迁移脚本是否存在
    if [ -f "migrations/${new_version}.sql" ]; then
        log "发现数据库迁移,需先执行"
        # 只读模式检查
        mysql -e "SELECT 1" || {
            error_exit "数据库连接失败"
        }
        return 0
    fi
}

使用建议

  1. 测试环境验证:先在测试环境验证脚本
  2. 监控告警:配置关键指标的监控告警
  3. 回滚计划:始终准备好回滚方案
  4. 数据一致性:确保数据库迁移的向后兼容性
  5. 日志记录:详细记录部署过程中的所有操作

这个脚本提供了完整的蓝绿部署实现,你可以根据具体的技术栈和业务需求进行调整和扩展。

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