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.
- 📖 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
- Arquitetura do lab
- Pré-requisitos
- Passo 1 — Código Terraform do Recovery Services Vault
- Passo 2 — Deploy com Terraform
- Passo 3 — Habilitar replicação de uma VM
- Passo 4 — Verificar saúde da replicação e RPO
- Passo 5 — Executar Test Failover
- Passo 6 — Cleanup do Test Failover
- Troubleshooting
- Limpeza dos recursos
- Próximos passos
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.
- 📖 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.


