Runbooks de Failover no Azure Automation

Runbooks de Failover no Azure Automation

Runbooks de Failover no Azure Automation

Runbooks de Failover no Azure Automation

Este artigo fecha o ciclo operacional da série com os Runbooks de Failover no Azure Automation. Até aqui você construiu toda a infraestrutura de DR — Landing Zone Hub-Spoke (Art. 02), Firewall e NSGs (Art. 03), Bastion (Art. 04), Front Door e Traffic Manager (Art. 05), DNS Privado (Art. 06), Site Recovery (Art. 07), Storage geo-replicado (Art. 08), AKS multi-região (Art. 09) e backup Velero (Art. 10). Agora o Azure Automation vai orquestrar tudo isso em um único runbook PowerShell que executa o failover completo com um webhook — sem acesso manual ao portal Azure durante o incidente. O artigo cobre a criação da Automation Account via Terraform com identidade gerenciada, os cinco scripts de failover sequencial e a configuração do webhook de acionamento.

Série: DR Azure e Landing Zone
  • 📖 Art. 01: Planejamento de DR Azure e Landing Zone
  • 📖 Art. 02: Hub-Spoke Landing Zone com Terraform
  • 📖 Art. 03: Azure Firewall e NSGs na Landing Zone
  • 📖 Art. 04: Azure Bastion na Landing Zone sem IP Público
  • 📖 Art. 05: Azure Front Door e Traffic Manager para Failover
  • 📖 Art. 06: DNS Privado Multi-Região no Azure
  • 📖 Art. 07: Azure Site Recovery para VMs Multi-Região
  • 📖 Art. 08: Azure Storage com Geo-Replicação para DR
  • 📖 Art. 09: AKS Multi-Região com Failover no Azure
  • 📖 Art. 10: Velero no AKS para Backup e Restore Cross-Region
  • ⚙️ Art. 11 (este): Runbooks de Failover no Azure Automation
  • 🔒 Art. 12: Simular um DR no Azure sem Impacto em Produção
  • 🔒 Art. 13: Monitoramento do DR no Azure com Azure Monitor

Sumário

Azure Automation e sua função no DR

Os Runbooks de Failover no Azure Automation executam scripts PowerShell e Python de forma gerenciada. O Azure Automation é um serviço que orquestra esses Runbooks — processos gerenciados com histórico de execução, logs e integração nativa com outros serviços Azure via identidade gerenciada. No contexto de DR, ele resolve um problema crítico: durante um incidente real, nenhum operador deve precisar executar comandos manualmente em sequência enquanto a pressão do tempo aumenta. O risco de erro humano nesse momento é altíssimo.

A estratégia dos Runbooks de Failover no Azure é concentrar toda a lógica em um único runbook orquestrador (failover-orchestrator) que chama os scripts individuais em ordem, aguarda cada etapa e mede o RTO ao final. O acionamento pode ser feito via webhook — uma URL gerada pela Automation Account que dispara o runbook com uma chamada HTTP POST. Isso permite integrar o failover a sistemas de monitoramento (como Azure Monitor Alerts ou PagerDuty) sem expor credenciais Azure.

A Automation Account dos Runbooks de Failover no Azure usa System-Assigned Managed Identity com o papel Contributor na subscription. Isso elimina a necessidade de credenciais hardcoded — o runbook se autentica automaticamente via Connect-AzAccount -Identity e tem acesso a todos os recursos do lab.

Arquitetura do lab

Componente Valor
Automation Account aa-blog-castilho
Resource Group rg-blog-castilho-workload-brazilsouth
SKU Basic
Identidade System-Assigned Managed Identity
Role assignment Contributor na subscription
Runbook principal failover-orchestrator (PowerShell)
Webhook webhook-failover (validade 2027-12-31)
Key Vault kv-blog-castilho — URI: https://kv-blog-castilho.vault.azure.net/
Scripts auxiliares 01-failover-network, 02-failover-asr, 03-failover-aks-scaleout, 04-failover-traffic-manager, 05-failover-dns, notify-teams

A sequência dos Runbooks de Failover no Azure é sempre a mesma: primeiro verificar os NSGs da região secundária, depois disparar o failover das VMs no ASR, em seguida escalar o cluster AKS de East US, depois desativar o endpoint primário no Traffic Manager, e por último verificar os registros DNS privados. Essa ordem garante que a rede esteja pronta antes das VMs chegarem e que o tráfego só seja redirecionado após os serviços estarem operacionais.

Pré-requisitos

  • Arts. 02–10 deployados — toda a infraestrutura do lab deve estar operacional
  • Azure CLI autenticado com permissões para criar Automation Accounts
  • Terraform ≥ 1.5 configurado com o backend Azure Storage (Art. 02)
  • Módulos Az PowerShell disponíveis na Automation Account (importados automaticamente no SKU Basic)
Segurança: Os comandos deste artigo utilizam variáveis de ambiente para credenciais. Nunca insira IDs de subscription, senhas ou chaves diretamente nos comandos. Use um arquivo .env local (não versionado) ou o Azure Key Vault para armazenar segredos.

Passo 1 — Criar a Automation Account com Terraform

O Terraform do scripts/art-11-runbooks-failover/aa-blog-castilho/ cria toda a infraestrutura dos Runbooks de Failover no Azure: Automation Account com identidade gerenciada, atribui o papel Contributor na subscription e registra o runbook orquestrador com um link para o script no repositório. O webhook é criado sem TTL de token no código — a URL com token é gerada pelo Azure e nunca commitada:

resource "azurerm_automation_account" "this" {
  name                = "aa-blog-castilho"
  resource_group_name = data.azurerm_resource_group.this.name
  location            = data.azurerm_resource_group.this.location
  sku_name            = "Basic"
  tags                = var.tags

  identity {
    type = "SystemAssigned"
  }
}

resource "azurerm_role_assignment" "contributor" {
  scope                = "/subscriptions/${var.subscription_id}"
  role_definition_name = "Contributor"
  principal_id         = azurerm_automation_account.this.identity[0].principal_id
}

resource "azurerm_automation_runbook" "orchestrator" {
  name                    = "failover-orchestrator"
  resource_group_name     = data.azurerm_resource_group.this.name
  location                = data.azurerm_resource_group.this.location
  automation_account_name = azurerm_automation_account.this.name
  log_verbose             = false
  log_progress            = true
  runbook_type            = "PowerShell"
  tags                    = var.tags

  publish_content_link {
    uri = "https://raw.githubusercontent.com/placeholder/runbooks/main/00-failover-orchestrator.ps1"
  }
}

resource "azurerm_automation_webhook" "failover" {
  name                    = "webhook-failover"
  resource_group_name     = data.azurerm_resource_group.this.name
  automation_account_name = azurerm_automation_account.this.name
  expiry_time             = "2027-12-31T00:00:00Z"
  enabled                 = true
  runbook_name            = azurerm_automation_runbook.orchestrator.name
}

Para aplicar:

SUBSCRIPTION_ID=""

cd scripts/art-11-runbooks-failover/aa-blog-castilho
terraform init -backend-config=backend.hcl
terraform apply -var="subscription_id=$SUBSCRIPTION_ID"

Após o apply, confirme os recursos criados:

# Verificar Automation Account
az automation account show \
  --resource-group rg-blog-castilho-workload-brazilsouth \
  --automation-account-name aa-blog-castilho \
  --query "{name:name, state:properties.state}" -o table

# Verificar Key Vault
az keyvault show \
  --name kv-blog-castilho \
  --query "{name:name, uri:properties.vaultUri, state:properties.provisioningState}" -o table

# Output esperado:
# Name               Uri                                        State
# -----------------  -----------------------------------------  ---------
# kv-blog-castilho   https://kv-blog-castilho.vault.azure.net/  Succeeded

Após o apply, obtenha a URL do webhook no portal Azure: Automation Account → Runbooks → failover-orchestrator → Webhooks. Salve a URL completa (com o token) no seu .env local — ela não pode ser recuperada depois:

# Salvar no .env (nunca commitar)
AUTOMATION_WEBHOOK_URI="https://s4abc123.azure-automation.net/webhooks?token="

Passo 2 — Runbook orquestrador

O script 00-failover-orchestrator.ps1 é o ponto de entrada do failover. Ele autentica com a identidade gerenciada da Automation Account, executa os cinco passos em sequência e mede o RTO total ao final:

param(
    [Parameter(Mandatory = $false)]
    [object]$WebhookData
)

$SubscriptionId = $env:AZURE_SUBSCRIPTION_ID

Connect-AzAccount -Identity
Set-AzContext -SubscriptionId $SubscriptionId

$StartTime = Get-Date
Write-Output "[$(Get-Date -Format 'HH:mm:ss')] Failover iniciado"

function Invoke-Step {
    param([string]$Nome, [scriptblock]$Acao)
    $t = Get-Date
    Write-Output "[$(Get-Date -Format 'HH:mm:ss')] STEP: $Nome"
    try {
        & $Acao
        Write-Output "[$(Get-Date -Format 'HH:mm:ss')] OK: $Nome ($([int]((Get-Date) - $t).TotalSeconds)s)"
    } catch {
        Write-Error "FALHA em $Nome`: $_"
        throw
    }
}

Invoke-Step "1. NSGs — liberar tráfego na região secundária" {
    & "$PSScriptRoot/01-failover-network.ps1"
}
Invoke-Step "2. ASR — failover das VMs" {
    & "$PSScriptRoot/02-failover-asr.ps1"
}
Invoke-Step "3. AKS East US — scale-out" {
    & "$PSScriptRoot/03-failover-aks-scaleout.ps1"
}
Invoke-Step "4. Traffic Manager — desativar endpoint primário" {
    & "$PSScriptRoot/04-failover-traffic-manager.ps1"
}
Invoke-Step "5. DNS privado — verificar registros" {
    & "$PSScriptRoot/05-failover-dns.ps1"
}

$RTO = [int]((Get-Date) - $StartTime).TotalMinutes
Write-Output "=== FAILOVER CONCLUÍDO — RTO: $RTO minutos ==="

& "$PSScriptRoot/notify-teams.ps1" -Mensagem "Failover concluído em $RTO minutos"

O parâmetro $WebhookData recebe o payload JSON enviado pelo webhook — útil para passar metadados como o nome do incidente ou o ambiente de destino quando o disparo vem de um sistema de monitoramento. Quando executado manualmente no portal ou via Azure CLI, $WebhookData é nulo e o runbook funciona normalmente.

Nos Runbooks de Failover no Azure, a função Invoke-Step encapsula cada etapa com logging de tempo e tratamento de erro: se qualquer passo falhar, o throw interrompe o runbook e o Azure Automation registra o job com status Failed — o que pode disparar um alerta (ver Art. 13). Isso é preferível a continuar com um failover parcialmente incompleto.

Passo 3 — Script de rede (NSGs)

O 01-failover-network.ps1 verifica os NSGs da região East US. No modelo deste lab, os NSGs foram configurados desde o Art. 03 com as regras corretas — o script confirma que nenhuma regra de bloqueio temporário foi adicionada durante a operação normal e que o tráfego pode fluir para a região secundária:

param(
    [string]$ResourceGroupEastUs = "rg-blog-castilho-workload-eastus"
)

$nsgs = @(
    "nsg-frontend-eastus",
    "nsg-backend-eastus",
    "nsg-data-eastus",
    "nsg-aks-eastus"
)

foreach ($nsgName in $nsgs) {
    $nsg = Get-AzNetworkSecurityGroup `
        -ResourceGroupName $ResourceGroupEastUs `
        -Name $nsgName

    $regra = $nsg.SecurityRules | Where-Object { $_.Name -eq "deny-all-inbound" }
    if ($regra) {
        Write-Output "  Regra deny-all-inbound presente — nenhuma alteração necessária"
    }
    Write-Output "  OK: $nsgName"
}
Write-Output "NSGs verificados na região East US"

Em um ambiente de produção mais complexo, este script poderia ser expandido para remover regras de bloqueio temporário ou adicionar regras de permissão específicas para a região de destino. Neste lab, a verificação é suficiente porque os NSGs já estão configurados para aceitar tráfego em ambas as regiões desde o Art. 03.

Passo 4 — Script de ASR (Planned Failover)

O 02-failover-asr.ps1 é o coração do failover de VMs. Ele conecta ao Recovery Services Vault rsv-blog-castilho-eastus, obtém todos os itens protegidos no container de Brazil South e dispara o Planned Failover para cada VM. O Planned Failover (diferente do Unplanned) requer que a VM primária esteja acessível e sincronizada — é usado em failovers planejados ou drills. O script aguarda cada job individualmente para garantir a ordem:

$vault = Get-AzRecoveryServicesVault `
    -ResourceGroupName "rg-blog-castilho-network-eastus" `
    -Name "rsv-blog-castilho-eastus"
Set-AzRecoveryServicesAsrVaultContext -Vault $vault

$fabricBrazilsouth = Get-AzRecoveryServicesAsrFabric -Name "fabric-brazilsouth"
$container = Get-AzRecoveryServicesAsrProtectionContainer `
    -Fabric $fabricBrazilsouth -Name "container-brazilsouth"

$protectedItems = Get-AzRecoveryServicesAsrReplicationProtectedItem `
    -ProtectionContainer $container

foreach ($item in $protectedItems) {
    Write-Output "Iniciando failover: $($item.FriendlyName)"
    $job = Start-AzRecoveryServicesAsrPlannedFailoverJob `
        -ReplicationProtectedItem $item `
        -Direction PrimaryToRecovery

    do {
        Start-Sleep -Seconds 30
        $job = Get-AzRecoveryServicesAsrJob -Job $job
        Write-Output "  Status: $($job.State)"
    } while ($job.State -notin "Succeeded", "Failed", "Cancelled")

    if ($job.State -ne "Succeeded") {
        throw "Failover falhou para $($item.FriendlyName): $($job.State)"
    }
    Write-Output "  Failover concluído: $($item.FriendlyName)"
}

O loop do..while com polling de 30 segundos é necessário porque os jobs do ASR são assíncronos — o Start-AzRecoveryServicesAsrPlannedFailoverJob retorna imediatamente com um objeto de job, e o script precisa aguardar a conclusão antes de avançar. O tempo médio de failover de uma VM no ASR é de 15 a 30 minutos, dependendo do tamanho do disco e da largura de banda de replicação disponível.

Passo 5 — Script de AKS (scale-out)

O 03-failover-aks-scaleout.ps1 escala o node pool system do cluster East US de 2 para 3 nós. Durante a operação normal, o cluster secundário pode rodar com capacidade reduzida para economizar custos — no failover, ele precisa absorver toda a carga de produção:

param(
    [string]$ResourceGroup = "rg-blog-castilho-workload-eastus",
    [string]$ClusterName   = "aks-blog-castilho-eastus",
    [string]$NodePoolName  = "system",
    [int]$NodeCount        = 3
)

Write-Output "Escalando $ClusterName — pool: $NodePoolName → $NodeCount nós"

$job = Update-AzAksNodePool `
    -ResourceGroupName $ResourceGroup `
    -ClusterName $ClusterName `
    -Name $NodePoolName `
    -Count $NodeCount `
    -AsJob

$job | Wait-Job | Receive-Job

$cluster = Get-AzAksCluster -ResourceGroupName $ResourceGroup -Name $ClusterName
$pool = $cluster.AgentPoolProfiles | Where-Object { $_.Name -eq $NodePoolName }
Write-Output "Node pool '$NodePoolName': $($pool.Count) nós — $($pool.VmSize)"

O -AsJob executa o scale-out em background, liberando o runbook para continuar monitorando enquanto o Azure provisiona o nó adicional. O Wait-Job | Receive-Job bloqueia até a conclusão e captura erros. O scale-out de um nó D2s_v3 no Azure leva tipicamente 3 a 5 minutos — tempo suficiente para os passos anteriores do ASR completarem enquanto o cluster sobe.

Passo 6 — Script de Traffic Manager

O 04-failover-traffic-manager.ps1 desativa o endpoint endpoint-brazilsouth no perfil tm-blog-castilho. Com o endpoint primário desativado, o Traffic Manager passa a rotear 100% do tráfego para o endpoint secundário (East US). O script loga o estado antes e depois para confirmar a mudança:

$endpoint = Get-AzTrafficManagerEndpoint `
    -ResourceGroupName "rg-blog-castilho-workload-brazilsouth" `
    -ProfileName "tm-blog-castilho" `
    -Type AzureEndpoints `
    -Name "endpoint-brazilsouth"

Disable-AzTrafficManagerEndpoint -TrafficManagerEndpoint $endpoint -Force
Write-Output "Endpoint 'endpoint-brazilsouth' desativado"

$profile = Get-AzTrafficManagerProfile `
    -ResourceGroupName "rg-blog-castilho-workload-brazilsouth" `
    -Name "tm-blog-castilho"
foreach ($ep in $profile.Endpoints) {
    Write-Output "  $($ep.Name): $($ep.EndpointStatus)"
}

O Traffic Manager tem um TTL de DNS padrão de 60 segundos — após desativar o endpoint, clientes que fizeram resolução DNS recente ainda podem enviar tráfego para Brazil South por até 60 segundos. Para failovers críticos, reduza o TTL para 10–30 segundos no Art. 05 antes de um drill. Em produção, o Front Door (Art. 05) oferece failover mais rápido que o Traffic Manager por operar na camada HTTP com health probes a cada 30 segundos.

Passo 7 — Script de DNS Privado

O 05-failover-dns.ps1 verifica os registros A nas zonas de DNS privado para confirmar que os Private Endpoints dos serviços PaaS apontam para os IPs corretos. No failover, os registros DNS privados normalmente não mudam — o DNS privado multi-região do Art. 06 já tem os registros das duas regiões. O script serve como verificação de sanidade final antes de considerar o failover concluído:

$zonas = @(
    "privatelink.blob.core.windows.net",
    "privatelink.azurecr.io",
    "privatelink.azurewebsites.net"
)

foreach ($zona in $zonas) {
    Write-Output "=== $zona ==="
    $records = Get-AzPrivateDnsRecordSet `
        -ResourceGroupName "rg-blog-castilho-network-brazilsouth" `
        -ZoneName $zona `
        -RecordType A
    foreach ($r in $records) {
        $ips = $r.Records | ForEach-Object { $_.Ipv4Address }
        Write-Output "  $($r.Name): $($ips -join ', ')"
    }
}
Write-Output "Verificação de DNS privado concluída"

O script verifica as três zonas mais críticas: privatelink.blob.core.windows.net (Storage Account com backups Velero e dados da aplicação), privatelink.azurecr.io (ACR geo-replicado) e privatelink.azurewebsites.net (serviços Web se houver). Adicione outras zonas conforme os serviços PaaS do seu ambiente real.

Passo 8 — Testar o webhook

Com a Automation Account criada e os runbooks carregados, teste o webhook com uma chamada HTTP POST simples. O Azure Automation aceita qualquer body JSON e o repassa para o parâmetro $WebhookData do runbook:

# Carregar URL do webhook do .env
source .env

# Disparar o failover via webhook
curl -s -X POST "$AUTOMATION_WEBHOOK_URI" \
  -H "Content-Type: application/json" \
  -d '{"incidente": "INC-2026-001", "origem": "azure-monitor-alert"}'

# Saída esperada:
# {"JobIds":["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"]}

O webhook retorna o JobId do runbook disparado. Use esse ID para acompanhar o progresso no portal ou via CLI:

<code">JOB_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
AA_RG="rg-blog-castilho-workload-brazilsouth"
AA_NAME="aa-blog-castilho"

# Verificar status do job
az automation job show \
  --resource-group $AA_RG \
  --automation-account-name $AA_NAME \
  --job-name $JOB_ID \
  --query "{status:status, startTime:startTime, endTime:endTime}" \
  -o table

# Ver output do runbook em tempo real
az automation job stream list \
  --resource-group $AA_RG \
  --automation-account-name $AA_NAME \
  --job-name $JOB_ID \
  --query "[].{time:time, text:value}" \
  -o table

Para configurar o disparo automático via Azure Monitor, crie um Action Group (Art. 13) com uma ação do tipo Automation Runbook apontando para o failover-orchestrator. Assim, quando um alerta crítico de replicação ASR for disparado, o failover começa automaticamente sem intervenção humana.

Troubleshooting

Problema Causa Solução
Job com status Failed no passo Connect-AzAccount -Identity A Managed Identity da Automation Account não tem permissão ou o módulo Az ainda está sendo importado Verificar o role assignment Contributor no portal. Aguardar 5–10 minutos após o apply do Terraform — o Azure leva tempo para propagar o IAM
Erro Module 'Az.RecoveryServices' not found O módulo Az não está importado na Automation Account Importar manualmente: Automation Account → Módulos → Procurar galeria → Az.RecoveryServices → Importar. Repetir para Az.Aks, Az.Network, Az.TrafficManager
Webhook retorna 400 Bad Request Webhook expirado ou URL inválida Verificar a data de expiração (expiry_time = "2027-12-31") e se a URL inclui o token completo
Job fica em Running indefinidamente no passo ASR O ASR está em estado de sincronização (Synchronizing) e o Planned Failover não pode iniciar Verificar a saúde da replicação no portal: RSV → Itens Replicados → VM → Estado de Replicação. Aguardar a sincronização completar antes de tentar novamente
notify-teams.ps1 com aviso TEAMS_WEBHOOK_URI não configurado Variável de ambiente não definida na Automation Account Adicionar a variável em: Automation Account → Variáveis → + Adicionar variável → nome: TEAMS_WEBHOOK_URI, valor: URL do webhook do Teams

Próximos passos

Com os Runbooks de Failover no Azure configurados, o failover completo da infraestrutura pode ser disparado com uma única chamada HTTP. O Art. 12 usa essa mesma infraestrutura para executar um drill de DR sem impacto em produção — o Azure Site Recovery oferece o modo Test Failover que replica as VMs para uma rede isolada em East US, permitindo validar o RTO e RPO reais do seu ambiente sem afetar os usuários.

Série: DR Azure e Landing Zone
  • 📖 Art. 01: Planejamento de DR Azure e Landing Zone
  • 📖 Art. 02: Hub-Spoke Landing Zone com Terraform
  • 📖 Art. 03: Azure Firewall e NSGs na Landing Zone
  • 📖 Art. 04: Azure Bastion na Landing Zone sem IP Público
  • 📖 Art. 05: Azure Front Door e Traffic Manager para Failover
  • 📖 Art. 06: DNS Privado Multi-Região no Azure
  • 📖 Art. 07: Azure Site Recovery para VMs Multi-Região
  • 📖 Art. 08: Azure Storage com Geo-Replicação para DR
  • 📖 Art. 09: AKS Multi-Região com Failover no Azure
  • 📖 Art. 10: Velero no AKS para Backup e Restore Cross-Region
  • ⚙️ Art. 11 (este): Runbooks de Failover no Azure Automation
  • 🔒 Art. 12: Simular um DR no Azure sem Impacto em Produção
  • 🔒 Art. 13: Monitoramento do DR no Azure com Azure Monitor

Interessado em saber mais sobre artigos relacionados ao Microsoft Azure CLIQUE AQUI

🚀 Vamos nos conectar?

Não perca nenhuma oportunidade! Cadastre-se nas minhas redes e no canal do YouTube para receber conteúdos de TI, Cloud, Azure, Kubernetes e DevOps em primeira mão.

Dica: No Facebook, todos os artigos do blog são publicados automaticamente. Vale a pena curtir!


💬 Dúvidas ou Problemas?

Com o intuito de ajudar a comunidade, caso você tenha dúvidas ou encontre problemas na execução dos comandos deste artigo, deixe um comentário abaixo. Responderei o mais breve possível!

Muito obrigado pela visita e até o próximo post!

Jefferson Castilho Especialista em Cloud & DevOps.

Este guia técnico é exclusivo do Blog do Castilho. Explore nossa para mais conteúdos sobre IA e Cloud.

 

Deixe uma resposta

Rolar para cima

Descubra mais sobre Blog do Castilho - Tecnologia | FinOps | DevOps | Cloud

Assine agora mesmo para continuar lendo e ter acesso ao arquivo completo.

Continue reading