Azure Site Recovery para VMs Multi-Região

Azure Site Recovery para VMs Multi-Região

Azure Site Recovery para VMs Multi-Região

Azure Site Recovery para VMs Multi-Região

Neste artigo você vai configurar o Azure Site Recovery para VMs de Brazil South, replicando para East US com RPO de 5 minutos. O Azure Site Recovery para VMs usa o Recovery Services Vault criado com Terraform, definindo fabrics, protection containers, replication policy e network mapping — tudo versionado em código. Na sequência, scripts PowerShell habilitam a replicação por VM, verificam a saúde do RPO e executam um Test Failover sem impacto em produção.

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

Sumário

Por que usar Azure Site Recovery para DR de VMs

O Azure Backup protege contra corrupção de dados e deleção acidental, mas não protege contra falha de região. Se a região Brazil South ficar indisponível, os backups armazenados na mesma região ficam inacessíveis junto com as VMs. O Azure Site Recovery para VMs resolve esse problema replicando continuamente os discos para uma região secundária, mantendo snapshots consistentes que permitem um failover rápido para East US.

Característica Azure Backup Azure Site Recovery
Proteção contra falha de região Não (sem GRS para VM backups) Sim — réplica contínua em outra região
RPO típico 24h (1x ao dia) 5 minutos (crash-consistent)
RTO típico Horas (restore completo) Minutos (failover de réplica existente)
Consistência Crash-consistent ou app-consistent Crash-consistent a cada 5min + app-consistent a cada 4h
Custo adicional Storage de vault Replication + cache storage + compute na região alvo (apenas durante failover)

O ASR mantém a VM replicada desligada em East US — você só paga pelo armazenamento dos discos replicados. O compute em East US é ativado apenas durante um failover real ou um Test Failover.

Arquitetura do lab

O Recovery Services Vault fica em East US, na região de destino do failover. Esta é a boa prática do Azure Site Recovery para VMs: se Brazil South falhar completamente, o vault permanece acessível na região ativa. O fluxo de replicação passa por uma Storage Account de cache (também em East US) que armazena temporariamente os dados antes de gravá-los nos discos da réplica:

VM em Brazil South (origem)
    │
    ▼ replicação contínua (porta 443)
stblogcastilhocache (East US)  ← cache temporário de dados de replicação
    │
    ▼ gravação nos discos
Discos replicados em East US (desligados)
    │
    ▼ em caso de failover
rsv-blog-castilho-eastus → ativa a VM em vnet-spoke-blog-castilho-eastus
Recurso Tipo Região Resource Group
rsv-blog-castilho-eastus Recovery Services Vault East US rg-blog-castilho-network-eastus
fabric-brazilsouth ASR Fabric (origem) Brazil South no vault acima
fabric-eastus ASR Fabric (destino) East US no vault acima
policy-blog-castilho-5min Replication Policy no vault acima
stblogcastilhocache Storage Account (cache) East US rg-blog-castilho-network-eastus

O network mapping garante que, após um failover, as NICs das VMs que estavam em vnet-spoke-blog-castilho-brazilsouth sejam criadas em vnet-spoke-blog-castilho-eastus automaticamente — sem precisar reconfigurar endereçamento manualmente.

Pré-requisitos

  • Hub-Spoke Landing Zone implantada (Arts. 02-06) — as quatro VNets e DNS privado existentes
  • Terraform ≥ 1.5 e Azure CLI autenticado (az login)
  • Storage Account de remote state configurado (bootstrap do Art. 02)
  • Módulo Az do PowerShell instalado: Install-Module -Name Az -AllowClobber -Scope CurrentUser
  • Storage Account de cache (stblogcastilhocache) — deployado com o Art. 08

Dependência: Os Passos 1 e 2 (Terraform) podem ser executados agora. Os Passos 3-6 (PowerShell para replicar VMs individuais) requerem que a Storage Account de cache stblogcastilhocache já exista — ela é criada junto com o Art. 08. Execute o deploy do Art. 08 antes de habilitar a replicação de VMs.

Passo 1 — Código Terraform do Recovery Services Vault

O Terraform do Art. 07 cria toda a infraestrutura do Azure Site Recovery para VMs em um único apply: o RSV, dois fabrics (um por região), dois protection containers, a política de replicação, o mapeamento de containers e o network mapping. Veja o código completo do main.tf:

# Data sources — referências às VNets existentes
data "azurerm_resource_group" "this" {
  name = "rg-blog-castilho-network-eastus"
}

data "azurerm_virtual_network" "spoke_brazilsouth" {
  name                = "vnet-spoke-blog-castilho-brazilsouth"
  resource_group_name = "rg-blog-castilho-network-brazilsouth"
}

data "azurerm_virtual_network" "spoke_eastus" {
  name                = "vnet-spoke-blog-castilho-eastus"
  resource_group_name = "rg-blog-castilho-network-eastus"
}

# Recovery Services Vault na região de destino (East US)
resource "azurerm_recovery_services_vault" "this" {
  name                = "rsv-blog-castilho-eastus"
  resource_group_name = data.azurerm_resource_group.this.name
  location            = data.azurerm_resource_group.this.location
  sku                 = "Standard"
  tags                = var.tags
}

# Fabrics — representam cada região no contexto do ASR
resource "azurerm_site_recovery_fabric" "brazilsouth" {
  name                = "fabric-brazilsouth"
  resource_group_name = data.azurerm_resource_group.this.name
  recovery_vault_name = azurerm_recovery_services_vault.this.name
  location            = "brazilsouth"
}

resource "azurerm_site_recovery_fabric" "eastus" {
  name                = "fabric-eastus"
  resource_group_name = data.azurerm_resource_group.this.name
  recovery_vault_name = azurerm_recovery_services_vault.this.name
  location            = data.azurerm_resource_group.this.location
}

# Protection Containers — agrupam os itens protegidos por fabric
resource "azurerm_site_recovery_protection_container" "brazilsouth" {
  name                 = "container-brazilsouth"
  resource_group_name  = data.azurerm_resource_group.this.name
  recovery_vault_name  = azurerm_recovery_services_vault.this.name
  recovery_fabric_name = azurerm_site_recovery_fabric.brazilsouth.name
}

resource "azurerm_site_recovery_protection_container" "eastus" {
  name                 = "container-eastus"
  resource_group_name  = data.azurerm_resource_group.this.name
  recovery_vault_name  = azurerm_recovery_services_vault.this.name
  recovery_fabric_name = azurerm_site_recovery_fabric.eastus.name
}

# Replication Policy — define RPO e frequência de snapshots
resource "azurerm_site_recovery_replication_policy" "this" {
  name                                                 = "policy-blog-castilho-5min"
  resource_group_name                                  = data.azurerm_resource_group.this.name
  recovery_vault_name                                  = azurerm_recovery_services_vault.this.name
  recovery_point_retention_in_minutes                  = 1440   # 24h de histórico de recovery points
  application_consistent_snapshot_frequency_in_minutes = 240    # snapshot app-consistent a cada 4h
}

# Container Mapping — vincula origem e destino com a policy
resource "azurerm_site_recovery_protection_container_mapping" "this" {
  name                                      = "mapping-brazilsouth-to-eastus"
  resource_group_name                       = data.azurerm_resource_group.this.name
  recovery_vault_name                       = azurerm_recovery_services_vault.this.name
  recovery_fabric_name                      = azurerm_site_recovery_fabric.brazilsouth.name
  recovery_source_protection_container_name = azurerm_site_recovery_protection_container.brazilsouth.name
  recovery_target_protection_container_id   = azurerm_site_recovery_protection_container.eastus.id
  recovery_replication_policy_id            = azurerm_site_recovery_replication_policy.this.id
}

# Network Mapping — define VNet destino para as NICs após failover
resource "azurerm_site_recovery_network_mapping" "this" {
  name                        = "nm-brazilsouth-to-eastus"
  resource_group_name         = data.azurerm_resource_group.this.name
  recovery_vault_name         = azurerm_recovery_services_vault.this.name
  source_recovery_fabric_name = azurerm_site_recovery_fabric.brazilsouth.name
  target_recovery_fabric_name = azurerm_site_recovery_fabric.eastus.name
  source_network_id           = data.azurerm_virtual_network.spoke_brazilsouth.id
  target_network_id           = data.azurerm_virtual_network.spoke_eastus.id
}

Pontos importantes do código:

  • RSV em East US: o vault fica na região de destino, não na origem. Se Brazil South falhar, o vault ainda estará disponível em East US.
  • Fabrics representam regiões: um fabric por região define o contexto geográfico do ASR. Cada fabric contém um protection container que agrupa as VMs a replicar.
  • recovery_point_retention_in_minutes = 1440: mantém 24 horas de recovery points — o suficiente para escolher um ponto anterior em caso de corrupção de dados.
  • application_consistent_snapshot_frequency_in_minutes = 240: a cada 4 horas o ASR tira um snapshot com consistência de aplicação (VSS no Windows / freeze no Linux). Entre eles, snapshots crash-consistent a cada 5 minutos.
  • Network Mapping: garante que após o failover as NICs das VMs sejam conectadas à VNet Spoke de East US automaticamente.

Passo 2 — Deploy com Terraform

Use o script deploy-infra.sh da série para criar o RSV com todos os seus recursos de uma vez. O deploy leva aproximadamente 10-15 minutos porque o provisionamento dos fabrics exige que o Azure registre os endpoints de replicação em ambas as regiões:

# Deploy somente do Art. 07 (RSV + fabrics + policy + mappings)
cd scripts/
bash deploy-infra.sh art-07

# Output esperado:
# ═══ ONDA: Art-07 — Recovery Services Vault ════════════════
# [HH:MM:SS] START  rsv-blog-castilho-eastus
# [HH:MM:SS] OK     rsv-blog-castilho-eastus

# Verificar o vault criado
az resource show \
  --resource-group rg-blog-castilho-network-eastus \
  --resource-type "Microsoft.RecoveryServices/vaults" \
  --name rsv-blog-castilho-eastus \
  --query "{name:name, location:location, sku:sku.name, state:properties.provisioningState}" \
  --output table

# Verificar a replication policy criada (RPO 5 min, 24h de retention)
az rest \
  --method get \
  --url "https://management.azure.com/subscriptions/\$AZURE_SUBSCRIPTION_ID/resourceGroups/rg-blog-castilho-network-eastus/providers/Microsoft.RecoveryServices/vaults/rsv-blog-castilho-eastus/replicationPolicies?api-version=2023-06-01" \
  --query "value[].{name:name, rpo:properties.providerSpecificDetails.appConsistentFrequencyInMinutes, retention:properties.providerSpecificDetails.recoveryPointHistory}" \
  --output table

# Exemplo de output:
# Name                                          Rpo    Retention
# --------------------------------------------  -----  ---------
# policy-rsv-blog-castilho-eastus-1440min       5      1440

Após o deploy, o vault existe mas ainda não há VMs replicadas. Os próximos passos usam PowerShell para habilitar a replicação VM a VM.

Passo 3 — Habilitar replicação de uma VM

O script 01-configure-replication.ps1 recebe o nome de uma VM e configura sua replicação para East US. Ele lê os discos da VM e cria um AzureToAzureDiskReplicationConfig para cada disco, apontando para a Storage Account de cache e para o Resource Group de destino:

# Habilitar replicação de uma VM específica
# Requer: stblogcastilhocache já deployada (Art. 08)
./01-configure-replication.ps1 -VmName "vm-blog-castilho-01"

# O script executa os seguintes passos:
# 1. Obtém o contexto do vault rsv-blog-castilho-eastus
# 2. Busca fabrics, containers, policy e mapping já criados pelo Terraform
# 3. Para cada disco da VM, cria um DiskReplicationConfig com:
#    - LogStorageAccountId: stblogcastilhocache (cache temporário)
#    - RecoveryResourceGroupId: rg-blog-castilho-workload-eastus
#    - RecoveryReplicaDiskAccountType: Premium_LRS
# 4. Inicia o job de replicação assíncrono

# Output esperado:
# Replicação iniciada. Job ID: a1b2c3d4-...
# Acompanhe com: Get-AzRecoveryServicesAsrJob -Name a1b2c3d4-...

O script completo com os parâmetros aceitos:

param(
    [Parameter(Mandatory = $true)]
    [string]$VmName,

    [string]$SourceResourceGroup = "rg-blog-castilho-workload-brazilsouth",
    [string]$VaultResourceGroup  = "rg-blog-castilho-network-eastus",
    [string]$VaultName           = "rsv-blog-castilho-eastus",
    [string]$TargetResourceGroup = "rg-blog-castilho-workload-eastus",
    [string]$CacheStorageAccount = "stblogcastilhocache"
)

A sincronização inicial (initial replication) pode levar de minutos a horas dependendo do tamanho dos discos e da bandwidth disponível. Durante esse período, o status da VM será InitialReplicationInProgress. Somente após concluída, o RPO começa a ser calculado.

Passo 4 — Verificar saúde da replicação e RPO

Use o script 02-check-replication-health.ps1 para verificar o status de todas as VMs replicadas no container de Brazil South, incluindo o RPO atual em minutos:

./02-check-replication-health.ps1

# Exemplo de output (após sincronização inicial concluída):
# FriendlyName          ReplicationHealth  RPO (min)  Último sync
# --------------------  -----------------  ---------  ---------------------
# vm-blog-castilho-01   Normal             2.3        2026-06-03 15:42:18
# vm-blog-castilho-02   Normal             1.8        2026-06-03 15:42:05

O campo ReplicationHealth pode ter três valores:

Status Significado Ação
Normal Replicação saudável, RPO dentro do objetivo Nenhuma — monitoramento de rotina
Warning RPO acima do alvo mas replicação ativa Verificar conectividade e largura de banda entre as regiões
Critical Replicação parada ou RPO muito alto Verificar logs no portal e reiniciar o agente de mobilidade se necessário

Para acompanhar o progresso da sincronização inicial de uma VM específica:

# Verificar status do job de replicação (substitua pelo Job ID retornado no Passo 3)
Get-AzRecoveryServicesAsrJob -Name "" | Select-Object State, StateDescription, StartTime, EndTime

# Ou verificar diretamente o item protegido
$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"

Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $container |
  Where-Object { $_.FriendlyName -eq "vm-blog-castilho-01" } |
  Select-Object FriendlyName, ProtectionState, ProtectionStateDescription

Passo 5 — Executar Test Failover

O Test Failover cria uma cópia temporária da VM em East US em uma VNet de isolamento — sem impactar a VM de produção em Brazil South nem redirecionar tráfego real. É a forma recomendada de validar periodicamente que o DR funciona antes de precisar dele de verdade.

# Criar uma VNet de isolamento para o Test Failover (boa prática — não usar a VNet de produção)
az network vnet create \
  --resource-group rg-blog-castilho-workload-eastus \
  --name vnet-test-failover \
  --address-prefix 192.168.0.0/24 \
  --subnet-name snet-test \
  --subnet-prefix 192.168.0.0/24

# Obter o ID da VNet de teste
TEST_VNET_ID=$(az network vnet show \
  --resource-group rg-blog-castilho-workload-eastus \
  --name vnet-test-failover \
  --query id --output tsv)

# Executar o Test Failover
./03-test-failover.ps1 -VmName "vm-blog-castilho-01" -TestNetworkId $TEST_VNET_ID

# Output esperado:
# Iniciando Test Failover para vm-blog-castilho-01...
# Recovery Point: 2026-06-03 15:40:00
# Test Failover iniciado. Job: b2c3d4e5-...
# Após validar a VM em East US, execute: ./04-cleanup-test-failover.ps1 -VmName vm-blog-castilho-01

O script usa o recovery point mais recente disponível e inicia o job de Test Failover. Quando concluído (5 a 15 minutos), a VM de teste fica visível no portal com o sufixo -test no Resource Group rg-blog-castilho-workload-eastus. Valide que ela inicializou corretamente, que os serviços estão respondendo e que os dados estão íntegros antes de prosseguir para o cleanup.

# Acompanhar o job de Test Failover
$vault = Get-AzRecoveryServicesVault -ResourceGroupName "rg-blog-castilho-network-eastus" -Name "rsv-blog-castilho-eastus"
Set-AzRecoveryServicesAsrVaultContext -Vault $vault

Get-AzRecoveryServicesAsrJob -Name "" |
  Select-Object DisplayName, State, StartTime, EndTime

# Listar a VM criada pelo Test Failover
az vm list --resource-group rg-blog-castilho-workload-eastus \
  --query "[?contains(name,'-test')].{name:name, powerState:powerState}" \
  --show-details --output table

Passo 6 — Cleanup do Test Failover

Após validar a VM de teste, execute o cleanup para remover os recursos temporários criados pelo Test Failover. Esse passo é obrigatório — enquanto o Test Failover não for encerrado, não é possível executar um failover real ou um novo Test Failover para a mesma VM:

# Encerrar o Test Failover e remover recursos temporários
./04-cleanup-test-failover.ps1 -VmName "vm-blog-castilho-01"

# Output esperado:
# Cleanup do Test Failover iniciado. Job: c3d4e5f6-...

# Após o cleanup, verificar que não há Test Failover pendente
$fabric = Get-AzRecoveryServicesAsrFabric -Name "fabric-brazilsouth"
$container = Get-AzRecoveryServicesAsrProtectionContainer -Fabric $fabric -Name "container-brazilsouth"
Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $container |
  Where-Object { $_.FriendlyName -eq "vm-blog-castilho-01" } |
  Select-Object FriendlyName, ProtectionState, TestFailoverState

# ProtectionState deve ser "Protected" e TestFailoverState deve ser "None"

Lembre de remover também a VNet de isolamento criada para o teste, caso não vá reutilizá-la:

az network vnet delete \
  --resource-group rg-blog-castilho-workload-eastus \
  --name vnet-test-failover

Troubleshooting

Problema Causa Solução
Fabric demora mais de 30min para criar Provisionamento do endpoint de replicação na região Normal em Brazil South — aguardar. Verificar no portal: Recovery Services → Site Recovery Infrastructure → Fabrics
soft_delete_enabled = false falha no Terraform Provider azurerm v4+ não permite desabilitar soft delete Remover o argumento — soft delete é obrigatório no Azure por política de segurança
Erro ao habilitar replicação da VM: cache storage não encontrado stblogcastilhocache não foi deployado ainda Executar o deploy do Art. 08 primeiro: bash deploy-infra.sh art-08
RPO em Warning ou Critical Largura de banda insuficiente ou conectividade interrompida Verificar NSGs (porta 443 outbound liberada), Azure Monitor → Replication Health
Test Failover falha com erro de VNet VNet de isolamento não fornecida ou incorreta Criar VNet de isolamento específica (não usar VNet de produção) e passar o ID correto
Não é possível iniciar novo Test Failover Test Failover anterior não foi encerrado com cleanup Executar 04-cleanup-test-failover.ps1 para a VM em questão

Limpeza dos recursos

Antes de destruir o vault do Azure Site Recovery para VMs via Terraform, remova todos os itens de replicação protegidos. O Azure não permite deletar um vault com itens ativos:

# 1. Desabilitar replicação de cada VM (PowerShell)
$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"

# Para cada item protegido
$items = Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $container
foreach ($item in $items) {
    Remove-AzRecoveryServicesAsrReplicationProtectedItem -ReplicationProtectedItem $item -Force
}

# 2. Após remover todos os itens, destruir via Terraform
cd scripts/art-07-site-recovery/rsv-blog-castilho-eastus
terraform destroy -var subscription_id="$AZURE_SUBSCRIPTION_ID"
# Remove: vault, 2 fabrics, 2 containers, policy, container mapping, network mapping

Próximos passos

Com o Azure Site Recovery para VMs configurado e os fabrics provisionados, a infraestrutura de replicação está pronta. O próximo artigo da série cobre o Azure Storage com geo-replicação para DR: criação da Storage Account primária com RA-GZRS em Brazil South, Private Endpoints em ambas as regiões, e a Storage Account de cache (stblogcastilhocache) em East US — pré-requisito para habilitar a replicação de VMs deste artigo.

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 (este): 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: 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