Simular um DR no Azure sem Impacto em Produção

Simular um DR no Azure sem Impacto em Produção

Um plano de DR que nunca foi testado não é um plano — é uma hipótese. O Azure Site Recovery oferece o Test Failover, um mecanismo que replica as VMs para uma rede isolada na região de destino sem interromper a replicação em andamento e sem afetar os usuários em produção. Este artigo executa um drill de DR completo no lab: inicia o Test Failover para todas as VMs replicadas, valida conectividade e integridade dos dados, mede o RTO e RPO reais com scripts PowerShell e faz o cleanup dos recursos de teste ao final. O resultado é um relatório com os números reais do seu ambiente.

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: Runbooks de Failover no Azure Automation
  • ⚙️ Art. 12 (este): Simular um DR no Azure sem Impacto em Produção
  • 🔒 Art. 13: Monitoramento do DR no Azure com Azure Monitor

Sumário

Test Failover vs. Failover real

O Azure Site Recovery distingue três modos de failover com impactos completamente diferentes:

ModoImpacto em produçãoReplicação continua?Uso
Test FailoverNenhum — VMs de teste em rede isoladaSimDrills periódicos, validação de RTO/RPO
Planned FailoverVMs primárias são desligadasNão (replicação invertida)Manutenção planejada, migração de região
Unplanned FailoverVMs primárias podem estar inacessíveisNãoDesastre real, região primária indisponível

O Test Failover cria cópias das VMs replicadas em uma VNet de teste isolada — separada da VNet de produção da região secundária — usando o último recovery point disponível. As VMs de produção em Brazil South continuam rodando normalmente e a replicação não é interrompida. Após o drill, um comando de cleanup remove as VMs de teste e libera os recursos.

A frequência recomendada de drills pela Microsoft é pelo menos uma vez por ano, mas para ambientes críticos o recomendado é trimestral. Cada drill deve gerar um relatório documentando o RTO medido, o RPO medido e eventuais problemas encontrados — que devem ser corrigidos antes do próximo drill.

Checklist pré-drill

  • Comunicar o drill para as equipes relevantes (mesmo sem impacto, o Azure Monitor pode gerar alertas)
  • Verificar que a replicação ASR está com status Healthy para todas as VMs
  • Confirmar que o Storage Account tem geo-replication ativa (GeoReplicationStatus: Live)
  • Preparar uma VNet de teste isolada em East US (ou usar a VNet de spoke com uma subnet separada)
  • Ter os scripts 01 a 05 disponíveis e as credenciais configuradas no .env
  • Registrar o horário de início para cálculo do RTO

Pré-requisitos

  • Art. 07 deployado — RSV rsv-blog-castilho-eastus com VMs replicadas e status Healthy
  • Art. 08 deployado — Storage Account stblogcastilhobrazil com RA-GZRS ativo
  • Módulo Az.RecoveryServices instalado (Install-Module Az.RecoveryServices)
  • Azure CLI ou PowerShell autenticado com permissão de Contributor no RSV
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 — Iniciar o Test Failover

O script 01-start-test-failover.ps1 conecta ao RSV, obtém todos os itens protegidos no container de Brazil South e dispara o Test Failover em paralelo para todas as VMs. Diferente do Planned Failover, aqui os jobs são criados de forma assíncrona e monitorados em batch:

# Registrar horário de início do drill
$DrillStart = Get-Date
Write-Output "=== DRILL INICIADO — $($DrillStart.ToString('yyyy-MM-dd HH:mm:ss')) ==="

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

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

$protectedItems = Get-AzRecoveryServicesAsrReplicationProtectedItem `
    -ProtectionContainer $container

$jobs = @()
foreach ($item in $protectedItems) {
    Write-Output "Test Failover: $($item.FriendlyName)"
    $job = Start-AzRecoveryServicesAsrTestFailoverJob `
        -ReplicationProtectedItem $item `
        -Direction PrimaryToRecovery
    $jobs += [pscustomobject]@{ VM = $item.FriendlyName; Job = $job }
    Write-Output "  Job iniciado: $($job.Name)"
}

# Aguardar todos em paralelo
foreach ($entry in $jobs) {
    do {
        Start-Sleep -Seconds 30
        $j = Get-AzRecoveryServicesAsrJob -Job $entry.Job
        Write-Output "  $($entry.VM): $($j.State)"
    } while ($j.State -notin "Succeeded", "Failed", "Cancelled")
}

Write-Output ""
Write-Output "Test Failover concluído — VMs de teste rodando em East US (rede isolada)"

O parâmetro -TestNetworkId (opcional) especifica a VNet de teste isolada. Se omitido, o ASR usa uma VNet temporária criada automaticamente. Para um drill mais realista, passe o ID de uma VNet de teste pré-criada em East US que simule o ambiente de produção:

># Obter ID da VNet de teste (criada manualmente ou via Terraform)
TEST_VNET_ID=$(az network vnet show \
  --resource-group rg-blog-castilho-network-eastus \
  --name vnet-dr-test-eastus \
  --query id -o tsv)

# Passar o ID para o script
./01-start-test-failover.ps1 -TestNetworkId "$TEST_VNET_ID"

Passo 2 — Validar conectividade

Com as VMs de teste rodando, o 02-validate-connectivity.ps1 verifica o estado dos componentes principais da infraestrutura de DR na região East US. Cada verificação retorna OK ou FALHA e gera um resumo no final:

>Write-Output "=== VALIDAÇÃO DE CONECTIVIDADE — $(Get-Date -Format 'HH:mm:ss') ==="

$resultados = @()

function Test-AzResource {
    param([string]$Nome, [scriptblock]$Teste)
    try {
        $ok = & $Teste
        $resultados += [pscustomobject]@{
            Componente = $Nome
            Status     = if ($ok) { "OK" } else { "FALHA" }
        }
        Write-Output "  [$(if ($ok) { 'OK  ' } else { 'FAIL' })] $Nome"
    } catch {
        $resultados += [pscustomobject]@{ Componente = $Nome; Status = "ERRO" }
        Write-Output "  [ERRO] $Nome`: $_"
    }
}

Test-AzResource "AKS East US — API server" {
    $c = Get-AzAksCluster `
        -ResourceGroupName "rg-blog-castilho-workload-eastus" `
        -Name "aks-blog-castilho-eastus"
    $c.ProvisioningState -eq "Succeeded"
}

Test-AzResource "Storage Account — geo-replication" {
    $s = Get-AzStorageAccount `
        -ResourceGroupName "rg-blog-castilho-workload-brazilsouth" `
        -Name "stblogcastilhobrazil"
    ($s | Get-AzStorageAccountGeoReplicationStats).GeoReplicationStatus -eq "Live"
}

Test-AzResource "Traffic Manager — endpoint East US" {
    $ep = Get-AzTrafficManagerEndpoint `
        -ResourceGroupName "rg-blog-castilho-workload-brazilsouth" `
        -ProfileName "tm-blog-castilho" `
        -Type AzureEndpoints `
        -Name "endpoint-eastus"
    $ep.EndpointStatus -eq "Enabled"
}

Test-AzResource "Azure Firewall East US — provisionado" {
    $afw = Get-AzFirewall `
        -ResourceGroupName "rg-blog-castilho-network-eastus" `
        -Name "afw-blog-castilho-eastus"
    $afw.ProvisioningState -eq "Succeeded"
}

$resultados | Format-Table -AutoSize

A verificação do Firewall confirma que o afw-blog-castilho-eastus está provisionado e as regras de rede para o AKS (TCP 9000, UDP 1194, UDP 123 e o FQDN tag AzureKubernetesService) estão aplicadas — sem isso, os pods do AKS não conseguem alcançar a API do Azure para operações de autoscaling e certificados. A verificação do Traffic Manager confirma que o endpoint East US está habilitado e pronto para receber tráfego caso o endpoint primário seja desativado.

Passo 3 — Validar integridade dos dados

O 03-validate-data-integrity.ps1 verifica duas fontes de dados críticas: o lag de geo-replicação do Storage Account RA-GZRS e a idade dos Recovery Points do ASR. Ambos determinam o RPO real do ambiente:

>param([int]$MaxSyncLagMinutes = 5)

Write-Output "--- Storage Geo-Replication ---"
$storage = Get-AzStorageAccount `
    -ResourceGroupName "rg-blog-castilho-workload-brazilsouth" `
    -Name "stblogcastilhobrazil"
$stats = $storage | Get-AzStorageAccountGeoReplicationStats

$lagMinutes = [int]((Get-Date) - $stats.LastSyncTime.ToUniversalTime()).TotalMinutes

Write-Output "  Status      : $($stats.GeoReplicationStatus)"
Write-Output "  Último sync : $($stats.LastSyncTime)"
Write-Output "  Lag (min)   : $lagMinutes"

if ($lagMinutes -le $MaxSyncLagMinutes) {
    Write-Output "  Resultado   : OK (dentro do RPO de $MaxSyncLagMinutes min)"
} else {
    Write-Warning "  Resultado   : ALERTA — lag excede RPO de $MaxSyncLagMinutes min"
}

Write-Output ""
Write-Output "--- ASR — Recovery Points ---"
$vault     = Get-AzRecoveryServicesVault -ResourceGroupName "rg-blog-castilho-network-eastus" -Name "rsv-blog-castilho-eastus"
Set-AzRecoveryServicesAsrVaultContext -Vault $vault
$fabric    = Get-AzRecoveryServicesAsrFabric -Name "fabric-brazilsouth"
$container = Get-AzRecoveryServicesAsrProtectionContainer -Fabric $fabric -Name "container-brazilsouth"
$items     = Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $container

foreach ($item in $items) {
    $rp    = Get-AzRecoveryServicesAsrRecoveryPoint -ReplicationProtectedItem $item | Select-Object -Last 1
    $rpAge = [int]((Get-Date) - $rp.RecoveryPointTime.ToUniversalTime()).TotalMinutes
    Write-Output "  $($item.FriendlyName): RP $($rp.RecoveryPointTime) (${rpAge}min) — $(if ($rpAge -le $MaxSyncLagMinutes) { 'OK' } else { 'ALERTA' })"
}

O GeoReplicationStatus: Live do Storage Account indica que a réplica em East US está sincronizada em tempo real via RA-GZRS. O LastSyncTime mostra o timestamp do último dado confirmado na réplica — qualquer dado gravado após esse momento pode não estar disponível na região secundária em caso de falha catastrófica da região primária. Para o RPO de 5 minutos definido no Art. 01, o lag deve ser consistentemente abaixo desse valor.

Passo 4 — Medir RTO e RPO reais

O 04-measure-rto-rpo.ps1 recebe os horários de início e fim do drill e gera um relatório formatado com os valores de RTO e RPO medidos, comparados com os objetivos definidos no Art. 01:

># Executar com os horários reais do drill
./04-measure-rto-rpo.ps1 `
    -StartTime "2026-06-03 10:00:00" `
    -EndTime "2026-06-03 10:34:00" `
    -RtoObjetivoMin 60 `
    -RpoObjetivoMin 5

O script calcula:

  • RTO medido: diferença entre -StartTime e -EndTime — representa o tempo desde o início do incidente até os serviços estarem disponíveis na região secundária
  • RPO medido: obtido diretamente do LastSyncTime da Storage Account no momento da execução — representa o quanto de dados poderia ser perdido se a falha tivesse ocorrido naquele instante

Exemplo de saída do relatório:

>╔══════════════════════════════════════════════════╗
║         DR DRILL REPORT — blog-castilho          ║
╠══════════════════════════════════════════════════╣
║ Data/Hora Início : 2026-06-03 10:00:00
║ Data/Hora Fim    : 2026-06-03 10:34:00
╠══════════════════════════════════════════════════╣
║ RTO Objetivo : 60 minutos
║ RTO Medido   : 34 minutos
║ RTO Status   : DENTRO DO OBJETIVO
╠══════════════════════════════════════════════════╣
║ RPO Objetivo : 5 minutos
║ RPO Medido   : 2.3 minutos
║ RPO Status   : DENTRO DO OBJETIVO
╚══════════════════════════════════════════════════╝
Relatório salvo em: dr-drill-report-20260603-1034.txt

O RTO de 34 minutos neste exemplo é dominado pelo tempo do Planned Failover do ASR (15–30 min por VM) mais o scale-out do AKS (~5 min). Se o RTO medido exceder o objetivo, os pontos de melhoria mais comuns são: reduzir o número de VMs replicadas pelo ASR, usar instâncias pré-aquecidas na região secundária (warm standby) ou substituir VMs por containers no AKS que sobem em segundos.

Passo 5 — Cleanup do Test Failover

O cleanup é obrigatório após o drill. O 05-cleanup-test-failover.ps1 remove as VMs de teste criadas pelo ASR e retoma a replicação normal. Sem o cleanup, as VMs de teste continuam consumindo recursos (e custos) em East US:

>Write-Output "=== CLEANUP DO TEST FAILOVER — $(Get-Date -Format 'HH:mm:ss') ==="

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

$fabric    = Get-AzRecoveryServicesAsrFabric -Name "fabric-brazilsouth"
$container = Get-AzRecoveryServicesAsrProtectionContainer `
    -Fabric $fabric -Name "container-brazilsouth"
$items     = Get-AzRecoveryServicesAsrReplicationProtectedItem `
    -ProtectionContainer $container

foreach ($item in $items) {
    Write-Output "Removendo Test Failover: $($item.FriendlyName)"
    $job = Start-AzRecoveryServicesAsrTestFailoverCleanupJob `
        -ReplicationProtectedItem $item `
        -Comment "Cleanup pós DR Drill $(Get-Date -Format 'yyyy-MM-dd')"

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

    Write-Output "  $($item.FriendlyName): cleanup $($job.State)"
}

Write-Output ""
Write-Output "Cleanup concluído — ambiente de produção não foi afetado"

O parâmetro -Comment registra uma nota no histórico do job do ASR — útil para auditoria e relatórios de compliance. Após o cleanup, verifique no portal que o estado de replicação voltou a Healthy antes de encerrar o drill oficialmente.

Interpretando os resultados

ResultadoO que significaAção
RTO dentro do objetivoO processo de failover é suficientemente rápido para o SLA definidoDocumentar e agendar próximo drill
RTO excedidoO failover demora mais que o acordado com o negócioIdentificar o gargalo (ASR, AKS scale-out, DNS TTL) e otimizar
RPO dentro do objetivoA replicação está sincronizada dentro da janela aceitável de perda de dadosManter a configuração atual
RPO excedido (Storage lag alto)A geo-replicação do Storage está com lag acima do esperadoVerificar throttling na conta de storage, largura de banda disponível e alertas do Art. 13
Componente FALHA na validaçãoUm serviço crítico não está acessível na região secundáriaInvestigar antes de considerar o DR válido — o failover real falharia nesse ponto

O relatório do drill deve ser arquivado e revisado pelo time. Qualquer item com status FALHA ou ALERTA deve ter um plano de ação com prazo antes do próximo drill. Drills frequentes constroem confiança no processo e revelam problemas antes que um incidente real os exponha.

Troubleshooting

ProblemaCausaSolução
Test Failover falha com ReplicationNotHealthyA replicação ASR está com erro antes do drillResolver o problema de replicação primeiro. Ver: RSV → Itens Replicados → VM → Replication Health
GeoReplicationStatus: Bootstrap no StorageA geo-replicação ainda está sendo inicializadaAguardar até o status ficar Live. Pode levar horas na primeira configuração dependendo do volume de dados
VMs de teste criadas mas sem IP acessívelA VNet de teste não tem conectividade com o Bastion ou VPNUsar o Bastion da região East US para acessar as VMs de teste (Art. 04). O Bastion acessa qualquer VNet peerada na região
Cleanup falha com JobAlreadyRunningOutro job está rodando no ASR para o mesmo itemAguardar o job em andamento completar e tentar novamente. Ver jobs ativos: Get-AzRecoveryServicesAsrJob -State Running
RTO muito alto por causa do ASRMuitas VMs em failover sequencialO script processa VMs em paralelo (jobs assíncronos). Se ainda for lento, considerar reduzir o número de VMs protegidas pelo ASR e mover workloads stateless para o AKS
Velero BSL Unavailable — TLS handshake timeout para o Storage AccountDNS split-horizon ausente: a zona privatelink.blob.core.windows.net tinha um único A record apontando para o Private Endpoint da região errada. Pods do BrazilSouth tentavam conectar no PEP do EastUS (10.3.3.4) em vez do PEP local (10.2.3.4)Criar uma zona DNS privada por região. A zona BRS deve ter A record → IP do PEP BRS; a zona EastUS deve ter A record → IP do PEP EastUS. Linkar cada zona somente aos VNets da própria região (hub + spoke). Padrão documentado no Art. 06

Próximos passos

Com o drill documentado e os RTO/RPO reais em mãos, o Art. 13 fecha a série com a camada de observabilidade contínua do DR: Log Analytics Workspaces em ambas as regiões, alertas críticos para replicação ASR não saudável e lag de storage acima do RPO, além de Workbooks consolidando visibilidade de todos os componentes em um único painel — para que você saiba o estado do DR em tempo real, não apenas durante os drills.

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: Runbooks de Failover no Azure Automation
  • ⚙️ Art. 12 (este): 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

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

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

Continuar lendo