You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Azure DevOps流水线实现两个Azure ServiceBus实例故障转移自动化?

Azure ServiceBus跨区域故障转移+队列清理的Azure DevOps YAML自动化实现

需求明确

我们有两个跨区域Azure ServiceBus实例(SB-A/区域1、SB-B/区域2),已启用手动故障转移,需要通过Azure DevOps YAML流水线实现双向故障转移全流程自动化,且关键操作节点支持人工决策触发。核心流程(以A→B为例):

  • 检查实例配对状态,未配对则用预设别名SB-PAIR-AB完成配对
  • 验证配对后执行故障转移,确认SB-B成为活动实例、SB-A变为被动
  • 人工确认后删除被动实例所有队列(需先断开配对,完成删除后重新配对)
  • B→A故障转移流程完全对称

YAML流水线实现(带人工审批)

以下流水线通过参数控制故障转移方向,嵌入manualValidation实现人工决策触发,覆盖所有需求节点:

parameters:
  - name: failoverDirection
    displayName: 故障转移方向
    type: string
    default: AtoB
    values:
      - AtoB
      - BtoA

variables:
  # 根据方向动态赋值资源信息,避免重复代码
  ${{ if eq(parameters.failoverDirection, 'AtoB') }}:
    activeNamespace: SB-B
    activeRG: SB-B-rg
    activeSub: B-subscription
    passiveNamespace: SB-A
    passiveRG: SB-A-rg
    passiveSub: A-Subscription
    partnerNamespaceId: "/subscriptions/xxxxxxxx/resourceGroups/SB-B-rg/providers/Microsoft.ServiceBus/namespaces/SB-B"
    sourceNamespace: SB-A
    sourceRG: SB-A-rg
  ${{ else }}:
    activeNamespace: SB-A
    activeRG: SB-A-rg
    activeSub: A-Subscription
    passiveNamespace: SB-B
    passiveRG: SB-B-rg
    passiveSub: B-subscription
    partnerNamespaceId: "/subscriptions/xxxxxx/resourceGroups/SB-A-rg/providers/Microsoft.ServiceBus/namespaces/SB-A"
    sourceNamespace: SB-B
    sourceRG: SB-B-rg
  aliasName: SB-PAIR-AB

jobs:
- job: Failover_Flow
  displayName: 跨区域故障转移全流程
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  # 1. 检查配对状态
  - script: |
      az login --service-principal -u $(servicePrincipalId) -p $(servicePrincipalKey) --tenant $(tenantId)
      # 检查别名是否存在
      aliasExists=$(az servicebus georecovery-alias show --alias $(aliasName) --resource-group $(sourceRG) --namespace-name $(sourceNamespace) --subscription $(passiveSub) --query "name" -o tsv || echo "NotFound")
      if [ "$aliasExists" == "NotFound" ]; then
        echo "##vso[task.setvariable variable=isPaired]false"
      else
        # 检查配对状态是否正常
        pairingStatus=$(az servicebus georecovery-alias show --alias $(aliasName) --resource-group $(sourceRG) --namespace-name $(sourceNamespace) --subscription $(passiveSub) --query "properties.provisioningState" -o tsv)
        if [ "$pairingStatus" == "Succeeded" ]; then
          echo "##vso[task.setvariable variable=isPaired]true"
        else
          echo "##vso[task.setvariable variable=isPaired]false"
        fi
      fi
    displayName: 检查ServiceBus实例配对状态
    env:
      servicePrincipalId: $(azureServicePrincipalId)
      servicePrincipalKey: $(azureServicePrincipalKey)
      tenantId: $(azureTenantId)

  # 2. 自动完成配对(未配对时执行)
  - script: |
      az servicebus georecovery-alias set \
        --alias $(aliasName) \
        --resource-group $(sourceRG) \
        --namespace-name $(sourceNamespace) \
        --partner-namespace $(partnerNamespaceId) \
        --subscription $(passiveSub)
      # 轮询等待配对完成(最多等待10分钟)
      for i in {1..20}; do
        status=$(az servicebus georecovery-alias show --alias $(aliasName) --resource-group $(sourceRG) --namespace-name $(sourceNamespace) --subscription $(passiveSub) --query "properties.provisioningState" -o tsv)
        if [ "$status" == "Succeeded" ]; then
          echo "配对完成"
          exit 0
        fi
        echo "等待配对完成,当前状态:$status"
        sleep 30
      done
      echo "配对超时"
      exit 1
    displayName: 执行ServiceBus实例配对
    condition: eq(variables.isPaired, 'false')

  # 3. 执行故障转移并验证活动实例
  - script: |
      # 触发故障转移
      az servicebus georecovery-alias fail-over \
        --alias $(aliasName) \
        --namespace-name $(activeNamespace) \
        --is-safe-failover y \
        --resource-group $(activeRG) \
        --subscription $(activeSub)
      # 验证活动实例
      activeStatus=$(az servicebus georecovery-alias show --alias $(aliasName) --resource-group $(activeRG) --namespace-name $(activeNamespace) --subscription $(activeSub) --query "properties.role" -o tsv)
      if [ "$activeStatus" != "Primary" ]; then
        echo "活动实例验证失败"
        exit 1
      fi
      passiveStatus=$(az servicebus georecovery-alias show --alias $(aliasName) --resource-group $(passiveRG) --namespace-name $(passiveNamespace) --subscription $(passiveSub) --query "properties.role" -o tsv)
      if [ "$passiveStatus" != "Secondary" ]; then
        echo "被动实例验证失败"
        exit 1
      fi
      echo "故障转移验证成功:$(activeNamespace)为活动实例,$(passiveNamespace)为被动实例"
    displayName: 执行故障转移并验证实例状态

  # 4. 人工决策:确认是否删除被动实例队列
  - task: manualValidation@0
    displayName: 人工确认是否删除被动实例队列
    inputs:
      notifyUsers: '运维团队邮箱列表'
      instructions: '确认当前被动实例为$(passiveNamespace),是否执行队列删除操作?'
      onTimeout: 'reject'

  # 5. 断开配对(必须操作,否则无法删除队列)
  - script: |
      az servicebus georecovery-alias delete \
        --alias $(aliasName) \
        --resource-group $(passiveRG) \
        --namespace-name $(passiveNamespace) \
        --subscription $(passiveSub) \
        --yes
      # 等待断开完成
      sleep 60
    displayName: 断开ServiceBus实例配对

  # 6. 批量删除被动实例所有队列
  - script: |
      # 获取所有队列名称
      queueNames=$(az servicebus queue list --resource-group $(passiveRG) --namespace-name $(passiveNamespace) --subscription $(passiveSub) --query "[].name" -o tsv)
      if [ -z "$queueNames" ]; then
        echo "被动实例无队列,无需删除"
        exit 0
      fi
      # 循环删除队列
      for queue in $queueNames; do
        echo "删除队列:$queue"
        az servicebus queue delete \
          --name $queue \
          --namespace-name $(passiveNamespace) \
          --resource-group $(passiveRG) \
          --subscription $(passiveSub)
      done
    displayName: 批量删除被动实例所有队列

  # 7. 重新发起配对
  - script: |
      az servicebus georecovery-alias set \
        --alias $(aliasName) \
        --resource-group $(sourceRG) \
        --namespace-name $(sourceNamespace) \
        --partner-namespace $(partnerNamespaceId) \
        --subscription $(passiveSub)
      # 轮询等待配对完成
      for i in {1..20}; do
        status=$(az servicebus georecovery-alias show --alias $(aliasName) --resource-group $(sourceRG) --namespace-name $(sourceNamespace) --subscription $(passiveSub) --query "properties.provisioningState" -o tsv)
        if [ "$status" == "Succeeded" ]; then
          echo "重新配对完成"
          exit 0
        fi
        echo "等待重新配对完成,当前状态:$status"
        sleep 30
      done
      echo "重新配对超时"
      exit 1
    displayName: 重新发起ServiceBus实例配对

关键命令优化说明

  1. 配对状态检查:新增az servicebus georecovery-alias show命令判断配对是否存在且状态正常,避免盲目执行配对操作
  2. 批量删除队列:通过az servicebus queue list动态获取所有队列名,实现批量删除,无需手动指定队列名称
  3. 断开配对命令:补充az servicebus georecovery-alias delete命令,解决配对状态下无法删除队列的问题
  4. 状态轮询验证:在配对、故障转移步骤中加入轮询逻辑,确保操作完成后再进入下一个节点,避免异步操作导致的流程错误

注意事项

  • 流水线需配置Azure服务连接(Service Principal),确保拥有ServiceBus实例的读写权限
  • manualValidation任务的notifyUsers需替换为实际运维人员邮箱,确保人工审批及时触发
  • 可根据实际需求调整轮询等待时间(当前为每30秒检查一次,最多等待10分钟)

内容的提问来源于stack exchange,提问作者Vowneee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 08:40:59