Shell脚本如何实现灰度发布策略

wen 实用脚本 24

本文目录导读:

Shell脚本如何实现灰度发布策略

  1. 基于Nginx的灰度发布
  2. 基于Consul的服务发现灰度
  3. 基于Kubernetes的灰度发布
  4. 使用注意事项

实现灰度发布策略的Shell脚本通常需要结合负载均衡器(如Nginx、HAProxy)或服务注册中心进行操作,以下是几种常见的实现方案及示例代码。

基于Nginx的灰度发布

通过修改upstream配置,动态调整灰度服务器权重。

脚本示例

#!/bin/bash
# 灰度发布脚本 - Nginx版本
NGINX_CONF="/etc/nginx/conf.d/upstream.conf"
NGINX_BINARY="/usr/sbin/nginx"
BACKUP_DIR="/tmp/nginx_backup"
# 服务节点配置
PRODUCTION_SERVERS=("192.168.1.10:8080" "192.168.1.11:8080" "192.168.1.12:8080")
GRAY_SERVERS=("192.168.1.100:8080")
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 函数:生成upstream配置
generate_upstream_conf() {
    local gray_weight=$1
    cat > "$NGINX_CONF" << EOF
upstream backend {
    # 生产服务器
EOF
    for server in "${PRODUCTION_SERVERS[@]}"; do
        echo "    server $server weight=10;" >> "$NGINX_CONF"
    done
    cat >> "$NGINX_CONF" << EOF
    # 灰度服务器
EOF
    for server in "${GRAY_SERVERS[@]}"; do
        if [ "$gray_weight" -gt 0 ] 2>/dev/null; then
            echo "    server $server weight=$gray_weight;" >> "$NGINX_CONF"
        fi
    done
    echo "}" >> "$NGINX_CONF"
}
# 函数:备份配置
backup_config() {
    mkdir -p "$BACKUP_DIR"
    local backup_file="$BACKUP_DIR/upstream.conf.$(date +%Y%m%d_%H%M%S)"
    cp "$NGINX_CONF" "$backup_file"
    echo -e "${GREEN}配置已备份到: $backup_file${NC}"
}
# 函数:检查Nginx配置
check_nginx() {
    $NGINX_BINARY -t 2>&1
    return $?
}
# 函数:重载Nginx
reload_nginx() {
    $NGINX_BINARY -s reload 2>&1
    return $?
}
# 函数:执行灰度发布
gray_deploy() {
    local weight=$1
    echo -e "${YELLOW}开始灰度发布...${NC}"
    # 备份当前配置
    backup_config
    # 生成新配置
    generate_upstream_conf "$weight"
    # 检查配置
    if check_nginx; then
        echo -e "${GREEN}Nginx配置检查通过${NC}"
        # 重载Nginx
        if reload_nginx; then
            echo -e "${GREEN}灰度发布完成${NC}"
            echo -e "灰度权重: ${weight}/10"
            return 0
        else
            echo -e "${RED}Nginx重载失败,回滚配置...${NC}"
            # 回滚配置
            latest_backup=$(ls -t "$BACKUP_DIR"/upstream.conf.* | head -1)
            if [ -n "$latest_backup" ]; then
                cp "$latest_backup" "$NGINX_CONF"
                reload_nginx
            fi
            return 1
        fi
    else
        echo -e "${RED}Nginx配置检查失败,保留配置供调试${NC}"
        return 1
    fi
}
# 主菜单
show_menu() {
    echo "=== 灰度发布管理脚本 ==="
    echo "1. 开始灰度发布 (10%流量)"
    echo "2. 增加灰度流量 (20%)"
    echo "3. 增加灰度流量 (50%)"
    echo "4. 全量发布"
    echo "5. 回滚到生产版本"
    echo "6. 查看当前状态"
    echo "0. 退出"
    echo "======================"
}
# 主逻辑
while true; do
    show_menu
    read -p "请选择操作: " choice
    case $choice in
        1) gray_deploy 1 ;;
        2) gray_deploy 2 ;;
        3) gray_deploy 5 ;;
        4) gray_deploy 10 ;;
        5) gray_deploy 0 ;;
        6) 
            echo -e "${YELLOW}当前配置状态:${NC}"
            cat "$NGINX_CONF"
            ;;
        0) 
            echo -e "${GREEN}退出脚本${NC}"
            exit 0
            ;;
        *) echo -e "${RED}无效选择${NC}" ;;
    esac
    echo ""
done

基于Consul的服务发现灰度

使用Consul的服务注册与健康检查实现灰度发布。

#!/bin/bash
# 灰度发布脚本 - Consul版本
CONSUL_BIN="/usr/local/bin/consul"
CONSUL_ADDR="http://localhost:8500"
# 服务配置
SERVICE_NAME="myapp"
TAG_PRODUCTION="production"
TAG_GRAY="gray"
REGION="us-east-1"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 函数:获取服务实例
get_service_instances() {
    local tag=$1
    $CONSUL_BIN catalog services \
        -http-addr="$CONSUL_ADDR" \
        -filter="ServiceName == \"$SERVICE_NAME\" and ServiceTags contains \"$tag\"" \
        | jq -r '.[] | .Address + ":" + (.ServicePort|tostring)'
}
# 函数:注册灰度服务
register_gray_service() {
    local instance_id=$1
    local address=$2
    local port=$3
    cat > /tmp/gray_service.json << EOF
{
    "ID": "$instance_id-gray",
    "Name": "$SERVICE_NAME",
    "Address": "$address",
    "Port": $port,
    "Tags": ["$TAG_GRAY", "$REGION"],
    "Check": {
        "HTTP": "http://$address:$port/health",
        "Interval": "10s",
        "Timeout": "5s",
        "DeregisterCriticalServiceAfter": "30s"
    }
}
EOF
    $CONSUL_BIN services register \
        -http-addr="$CONSUL_ADDR" \
        /tmp/gray_service.json
    echo -e "${GREEN}灰度服务 $instance_id-gray 注册成功${NC}"
}
# 函数:切换标签
switch_tags() {
    local instance_id=$1
    local to_tag=$2
    # 获取当前服务信息
    local service_info=$($CONSUL_BIN catalog service \
        -http-addr="$CONSUL_ADDR" \
        "$SERVICE_NAME-$instance_id" 2>/dev/null)
    if [ -n "$service_info" ]; then
        $CONSUL_BIN services deregister \
            -http-addr="$CONSUL_ADDR" \
            "id=$SERVICE_NAME-$instance_id"
    fi
    # 重新注册为新的tag
    cat > /tmp/service_update.json << EOF
{
    "ID": "$SERVICE_NAME-$instance_id",
    "Name": "$SERVICE_NAME",
    "Tags": ["$to_tag", "$REGION"]
}
EOF
    $CONSUL_BIN services register \
        -http-addr="$CONSUL_ADDR" \
        /tmp/service_update.json
    echo -e "${GREEN}服务 $instance_id 切换到 $to_tag${NC}"
}
# 函数:灰度策略 - 按比例
gray_deploy_by_percent() {
    local percent=$1
    local total_instances=$2
    local gray_instances=$(( total_instances * percent / 100 ))
    echo -e "${YELLOW}灰度发布 $percent% 流量...${NC}"
    # 获取所有生产实例
    local production_instances=($(get_service_instances "$TAG_PRODUCTION"))
    local count=0
    for instance in "${production_instances[@]}"; do
        if [ $count -lt $gray_instances ]; then
            # 切换到灰度标签
            switch_tags "$instance" "$TAG_GRAY"
            ((count++))
        else
            break
        fi
    done
    echo -e "${GREEN}灰度发布完成: $gray_instances/$total_instances 实例${NC}"
}
# 函数:灰度策略 - 按用户ID
gray_deploy_by_user_id() {
    local user_id_range=$1
    echo -e "${YELLOW}为特定用户ID范围 ($user_id_range%) 启用灰度...${NC}"
    # 注册灰度版本并设置用户ID过滤
    $CONSUL_BIN kv put \
        -http-addr="$CONSUL_ADDR" \
        "config/$SERVICE_NAME/gray/user_id_range" "$user_id_range"
    echo -e "${GREEN}灰度范围已设置: $user_id_range%${NC}"
}
# 函数:全量发布
full_release() {
    echo -e "${YELLOW}执行全量发布...${NC}"
    # 将所有灰度实例切回生产
    local gray_instances=($(get_service_instances "$TAG_GRAY"))
    for instance in "${gray_instances[@]}"; do
        switch_tags "$instance" "$TAG_PRODUCTION"
    done
    # 清除灰度配置
    $CONSUL_BIN kv delete \
        -http-addr="$CONSUL_ADDR" \
        "config/$SERVICE_NAME/gray/user_id_range" 2>/dev/null
    echo -e "${GREEN}全量发布完成${NC}"
}
# 函数:回滚
rollback() {
    echo -e "${YELLOW}回滚到上一个生产版本...${NC}"
    # 将灰度实例切回生产
    local gray_instances=($(get_service_instances "$TAG_GRAY"))
    for instance in "${gray_instances[@]}"; do
        switch_tags "$instance" "$TAG_PRODUCTION"
    done
    # 清除灰度配置
    $CONSUL_BIN kv delete \
        -http-addr="$CONSUL_ADDR" \
        "config/$SERVICE_NAME/gray/user_id_range" 2>/dev/null
    # 重新部署上一版本
    echo -e "${GREEN}回滚完成,重新部署上一版本...${NC}"
    # 这里可以调用部署脚本重新部署旧版本
}
# 主菜单
show_menu() {
    echo "=== 基于Consul的灰度发布管理 ==="
    echo "1. 灰度发布 (10% 实例)"
    echo "2. 灰度发布 (50% 实例)"
    echo "3. 按用户ID灰度 (10%)"
    echo "4. 按用户ID灰度 (50%)"
    echo "5. 全量发布"
    echo "6. 回滚"
    echo "7. 查看当前灰度状态"
    echo "0. 退出"
}
# 主逻辑
while true; do
    show_menu
    read -p "请选择操作: " choice
    case $choice in
        1) gray_deploy_by_percent 10 10 ;;
        2) gray_deploy_by_percent 50 10 ;;
        3) gray_deploy_by_user_id 10 ;;
        4) gray_deploy_by_user_id 50 ;;
        5) full_release ;;
        6) rollback ;;
        7)
            echo -e "${YELLOW}当前灰度状态:${NC}"
            echo "生产实例:"
            get_service_instances "$TAG_PRODUCTION" | while read line; do
                echo "  - $line"
            done
            echo "灰度实例:"
            get_service_instances "$TAG_GRAY" | while read line; do
                echo "  - $line"
            done
            echo "灰度配置:"
            $CONSUL_BIN kv get \
                -http-addr="$CONSUL_ADDR" \
                "config/$SERVICE_NAME/gray/user_id_range" 2>/dev/null || echo "  未设置"
            ;;
        0) exit 0 ;;
        *) echo -e "${RED}无效选择${NC}" ;;
    esac
    echo ""
done

基于Kubernetes的灰度发布

使用Kubernetes的Deployment和Service实现灰度发布。

#!/bin/bash
# 灰度发布脚本 - Kubernetes版本
NAMESPACE="production"
DEPLOYMENT_NAME="myapp"
SERVICE_NAME="myapp-svc"
IMAGE_NEW="myapp:2.0.0"
IMAGE_OLD="myapp:1.0.0"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 函数:创建灰度Deployment
create_gray_deployment() {
    local replicas=$1
    kubectl create deployment "$DEPLOYMENT_NAME-gray" \
        --namespace="$NAMESPACE" \
        --image="$IMAGE_NEW" \
        --replicas="$replicas" \
        --dry-run=client -o yaml > /tmp/gray-deploy.yaml
    # 添加标签和选择器
    sed -i 's/app: myapp/app: myapp-gray/g' /tmp/gray-deploy.yaml
    kubectl apply -f /tmp/gray-deploy.yaml
    echo -e "${GREEN}灰度Deployment已创建: $replicas 副本${NC}"
}
# 函数:更新Service选择器
update_service_selector() {
    local gray_weight=$1
    # 备份原Service
    kubectl get svc "$SERVICE_NAME" \
        --namespace="$NAMESPACE" \
        -o yaml > /tmp/svc-backup.yaml
    # 修改Service选择器包含灰度标签
    kubectl patch svc "$SERVICE_NAME" \
        --namespace="$NAMESPACE" \
        -p "{\"spec\":{\"selector\":{\"app\":\"myapp\",\"version\":\"${gray_weight}\"}}}"
    echo -e "${GREEN}Service选择器已更新${NC}"
}
# 函数:灰度发布
gray_deploy() {
    local percent=$1
    echo -e "${YELLOW}开始灰度发布 $percent%...${NC}"
    # 计算副本数
    local total_replicas=$(kubectl get deployment "$DEPLOYMENT_NAME" \
        --namespace="$NAMESPACE" \
        -o jsonpath='{.spec.replicas}')
    local gray_replicas=$(( total_replicas * percent / 100 ))
    # 创建灰度Deployment
    create_gray_deployment "$gray_replicas"
    # 等待灰度Deployment就绪
    kubectl rollout status deployment "$DEPLOYMENT_NAME-gray" \
        --namespace="$NAMESPACE" \
        --timeout=300s
    # 更新Service指向灰度版本
    update_service_selector "gray"
    echo -e "${GREEN}灰度发布完成: $percent% 流量${NC}"
}
# 函数:全量发布
full_release() {
    echo -e "${YELLOW}执行全量发布...${NC}"
    # 更新主Deployment
    kubectl set image deployment/"$DEPLOYMENT_NAME" \
        --namespace="$NAMESPACE" \
        "$DEPLOYMENT_NAME=$IMAGE_NEW"
    # 等待更新完成
    kubectl rollout status deployment/"$DEPLOYMENT_NAME" \
        --namespace="$NAMESPACE" \
        --timeout=300s
    # 删除灰度Deployment
    kubectl delete deployment "$DEPLOYMENT_NAME-gray" \
        --namespace="$NAMESPACE"
    # 恢复Service选择器
    kubectl patch svc "$SERVICE_NAME" \
        --namespace="$NAMESPACE" \
        -p "{\"spec\":{\"selector\":{\"app\":\"myapp\"}}}"
    echo -e "${GREEN}全量发布完成${NC}"
}
# 函数:回滚
rollback() {
    echo -e "${YELLOW}执行回滚...${NC}"
    # 回滚主Deployment
    kubectl rollout undo deployment/"$DEPLOYMENT_NAME" \
        --namespace="$NAMESPACE"
    # 删除灰度Deployment
    kubectl delete deployment "$DEPLOYMENT_NAME-gray" \
        --namespace="$NAMESPACE" 2>/dev/null
    # 恢复Service选择器
    kubectl patch svc "$SERVICE_NAME" \
        --namespace="$NAMESPACE" \
        -p "{\"spec\":{\"selector\":{\"app\":\"myapp\"}}}"
    echo -e "${GREEN}回滚完成${NC}"
}
# 主菜单
show_menu() {
    echo "=== Kubernetes灰度发布管理 ==="
    echo "1. 灰度发布 (10%)"
    echo "2. 灰度发布 (50%)"
    echo "3. 全量发布"
    echo "4. 回滚"
    echo "5. 查看当前状态"
    echo "0. 退出"
}
# 主逻辑
while true; do
    show_menu
    read -p "请选择操作: " choice
    case $choice in
        1) gray_deploy 10 ;;
        2) gray_deploy 50 ;;
        3) full_release ;;
        4) rollback ;;
        5)
            echo -e "${YELLOW}当前状态:${NC}"
            echo "主Deployment:"
            kubectl get deployment "$DEPLOYMENT_NAME" \
                --namespace="$NAMESPACE" \
                -o wide
            echo ""
            echo "灰度Deployment:"
            kubectl get deployment "$DEPLOYMENT_NAME-gray" \
                --namespace="$NAMESPACE" 2>/dev/null || echo "  未创建"
            echo ""
            echo "Service:"
            kubectl get svc "$SERVICE_NAME" \
                --namespace="$NAMESPACE" \
                -o wide
            ;;
        0) exit 0 ;;
        *) echo -e "${RED}无效选择${NC}" ;;
    esac
    echo ""
done

使用注意事项

  1. 安全性:所有脚本需要在具有适当权限的环境中运行
  2. 备份:每次操作前备份配置,保证可回滚
  3. 监控:灰度发布期间密切监控指标
  4. 自动化:考虑集成到CI/CD流水线中
  5. 超时处理:设置合理的超时时间,避免长时间等待

这些脚本提供了基础的灰度发布功能,可以根据实际场景进行调整和扩展。

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