Настройка отработки отказа виртуальной машины между виртуальными сетями
Важно!
Поддержка этой версии Virtual Machine Manager (VMM) завершена. Рекомендуется выполнить обновление до VMM 2022.
В этой статье описываются способы репликации и отработки отказа виртуальных машин в System Center Virtual Machine Manager (VMM) между виртуальными сетями, если вы не используете службу Azure Site Recovery для управления процессами аварийного восстановления.
- Для репликации виртуальных машин мы рекомендуем использовать Azure Site Recovery. VMM не поддерживает управление репликами Hyper-V без Site Recovery, и для автоматизации операций c репликой Hyper-V вам нужно использовать командлеты PowerShell для реплики Hyper-V.
- Для аварийного восстановления мы рекомендуем разделить основную и дополнительную виртуальные сети. Основные виртуальные машины следует подключить к основной сети, а виртуальные машины реплики — к дополнительной. Так вы обеспечите возможность одновременного подключения к сети двух типов виртуальных машин.
- Если у вас одна виртуальная сеть, используйте Site Recovery для автоматизации управления сетью с помощью функции сетевого сопоставления. Если вы не используете Site Recovery, тщательно проверьте все предварительные требования и порядок подключения виртуальных машин к сети. В частности, виртуальная машина реплики и основная виртуальная машина не должны подключаться к одной виртуальной сети одновременно. В противном случае записи CA-PA могут быть удалены в VMM и привести к потере сетевого подключения.
Пример решения
В этом примере решения описана следующая среда.
- Один сервер VMM управляет основным и дополнительным сайтами.
- Основная виртуальная машина и виртуальная машина реплики размещаются в одной виртуальной сети Hyper-V.
- Вам нужно выполнить плановую отработку отказа и сохранить IP-адрес виртуальной машины после отработки отказа.
- Виртуальные машины имеют адреса IPv4.
Перед началом работы
Убедитесь, что параметры виртуального коммутатора и логического коммутатора являются допустимыми и совпадают в структуре VMM. В противном случае операция подключения к сети после отработки отказа может завершиться неудачей.
Основная виртуальная машина должна быть подключена к виртуальной сети.
Виртуальная машина реплики не должна быть подключена к сети.
Каждому сетевому адаптеру основной виртуальной машины должен быть назначен только один IP-адрес. Выполните следующую команду, чтобы проверить это. Если к виртуальной машине подключено больше одного сетевого адаптера, запустите команду для каждого адаптера, изменяя индекс массива.
$VMOnPD = Get-SCVirtualMachine -Name "VM Name" | where {$_.IsPrimaryVM -eq $true} Get-SCIPAddress –GrantToObjectId $VMOnPD.VirtualNetworkAdapters[0].ID``
Убедитесь, что IP-адрес, назначенный виртуальной машине операционной системой, совпадает с IP-адресом, показанным выше. Войдите на виртуальную машину и запустите ipconfig, чтобы проверка это.
Убедитесь, что таблицы подстановки правильно заданы в основном и реплика. Для этого выполните следующую команду на каждом сервере и убедитесь, что есть запись, соответствующая возвращенному выше IP-адресу:
Get-NetVirtualizationLookupRecord
Убедитесь, что IP-адрес имеет формат IPv4, а не IPv6.
Перед запуском скриптов убедитесь, что обе виртуальные машины отключены.
Убедитесь, что состояние репликации включено на обеих виртуальных машинах.
Запустите скрипт плановой отработки отказа.
Этот скрипт выполняет следующее.
- Сохраняет IP-адрес, сеть и пул IP-адресов для каждого сетевого адаптера на основной виртуальной машине.
- Отменяет все IP-адреса для каждого сетевого адаптера на основной и дополнительной виртуальных машинах.
- Отключает все сетевые адаптеры.
- Выполняет отработку отказа для основной и дополнительной виртуальных машин.
- При необходимости запускает обратную репликацию.
- Присваивает виртуальной машине реплики те же IP-адреса, которые использовались на каждом из сетевых адаптеров.
- Присоединяет каждый сетевой адаптер виртуальной машины реплики к тем сетям, которые были сохранены на шаге 1.
Выполнение скрипта
Скрипт принимает два параметра.
- $VMName — это имя виртуальной машины.
- $ReverseRep — логический аргумент, указывающий, следует ли выполнять обратную репликацию.
- Если $true передается, обратная репликация запускается немедленно, и вы не сможете отменить отработку отказа позже.
- После успешного выполнение скрипта со значением $true для параметра $ReverseRep:
- основная виртуальная машина будет иметь статус репликации Подготовлено к плановой отработке отказа;
- виртуальная машина реплики будет иметь статус репликации Отработка отказа завершена.
- Если передается значение $false, обратная репликация не выполняется. ReverseRepORCancelFO.ps1 можно использовать для выполнения обратной репликации или отмены отработки отказа.
- После успешного выполнение скрипта со значением $false для параметра $ReverseRep:
- основная виртуальная машина будет иметь статус репликации Подготовлено к плановой отработке отказа;
- виртуальная машина реплики будет иметь статус репликации Отработка отказа завершена.
Если скрипт не выполняет ни одно из этих действий, вам нужно выполнить это действие вручную, а затем вернуться в окно PowerShell. Шаги сценария включают отработку отказа основной виртуальной машины, отработку отказа виртуальной машины реплика и при необходимости обратную репликацию.
Выполните скрипт:
Param(
[Parameter(Mandatory=$True)]
[string]$VMName,
[Parameter(Mandatory=$true)]
[boolean]$ReverseRep
)
# the script running on system with SCVMM Console/PowerShell installed. Also, requires Hyper-V powershell module.``
Import-Module hyper-v
## Refresh VM configuration and initialize
Write-Host -ForegroundColor Green (Get-Date) ".....Refreshing the VMs..."
Get-SCVirtualMachine -Name $VMName | Read-SCVirtualMachine
$VMOnPD = Get-SCVirtualMachine -Name $VMName | where {$_.IsPrimaryVM -eq $true}
$VMOnDR = Get-SCVirtualMachine -Name $VMName | where {$_.IsPrimaryVM -eq $false}
if ($VMOnPD.StatusString -ne "Stopped")
{
write-host -ForegroundColor Red (Get-Date) "....VM is not in stopped state. Actual State " $VMOnPD.StatusString
write-host -ForegroundColor Red (Get-Date) "....Exiting"
exit 1
}
$error.Clear()
$VMRepConfig = Get-VMReplication -ComputerName $VMOnPD.HostName -VMName $VMOnPD.Name
$VMRepConfig = Get-VMReplication -ComputerName $VMOnDR.HostName -VMName $VMOnPD.Name
if ($error -ne 0)
{
$temp = $VMOnPD.HostName.Split(".")
$primaryHostName = $temp[0]
$temp = $VMOnDR.HostName.Split(".")
$recoveryHostName = $temp[0]
write-host -ForegroundColor Red (Get-Date) "....Error in getting VM Replication state using FQDN, switching to Hostname"
write-host -ForegroundColor Yellow (Get-Date) "....Primary Hostname: " $primaryHostName " Replica Hostname: " $recoveryHostName
$error.Clear()
$VMRepConfig = Get-VMReplication -ComputerName $primaryHostName -VMName $VMOnPD.Name
$VMRepConfig = Get-VMReplication -ComputerName $recoveryHostName -VMName $VMOnPD.Name
if ($error -ne 0)
{
write-host -ForegroundColor Red (Get-Date) "....Error in getting VM Replication state using Hostname"
write-host -ForegroundColor Red (Get-Date) "....Exiting"
exit 1
}
write-host -ForegroundColor Green (Get-Date) "....Successful in getting VM Replication state using Hostname"
}
else
{
$primaryHostName = $VMOnPD.HostName
$recoveryHostName = $VMOnDR.HostName
}
$VMOnPDAdapter = Get-SCVirtualNetworkAdapter -VM $VMonPD
$VMOnDRAdapter = Get-SCVirtualNetworkAdapter -VM $VMonDR
$fileName = $VMName + (Get-Date).ToString() + ".txt"
$fileName = $fileName.Replace("/","_")
$fileName = $fileName.Replace(":","_")
Write-Host -ForegroundColor Yellow (Get-Date) "....Dumping network information for $VMName to file $fileName"
Write-Host -ForegroundColor Yellow (Get-Date) "....Number of Network adapters found: " $VMOnPDAdapter.count
$VMNetwork = @()
$VMSubnet = @()
$Pools = @()
$counter = 0
foreach($vmAdapter in $VMOnPDAdapter)
{
if ($vmAdapter.VMNetwork -eq $null)
{
$VMNetwork = $VMNetwork + $null
$VMSubnet = $VMSubnet + $null
$Pools = $Pools + $null
$counter = $counter + 1
continue
}
$VMNetwork = $VMNetwork + (Get-SCVMNetwork -Name $vmAdapter.VMNetwork.Name -ID $vmAdapter.VMNetwork.ID)
$VMSubnet = $VMSubnet + (Get-SCVMSubnet -Name $vmAdapter.VMSubnet.Name | where {$_.VMNetwork.ID -eq $vmAdapter.VMNetwork.ID})
#$PortClassification = Get-SCPortClassification | where {$_.Name -eq "Guest Dynamic IP"}
$Pools = $Pools + (Get-SCStaticIPAddressPool -IPv4 | where {$_.VMsubnet.name -eq $vmAdapter.VMSubnet.Name})
Out-File -FilePath $fileName -InputObject $VMNetwork[$counter] -Append
Out-File -FilePath $fileName -InputObject $VMSubnet[$counter] -Append
Out-File -FilePath $fileName -InputObject $Pools[$counter] -Append
$counter = $counter + 1
}
if ($error.Count -ne 0)
{
write-host -ForegroundColor Red (Get-Date) "....Error is gathering information for $VMName. No changes made"
write-host -ForegroundColor Red (Get-Date) "....Exiting"
exit 1
}
$IP = @()
$counter = 0
foreach($vmAdapter in $VMOnPDAdapter)
{
if ($VMNetwork[$counter] -eq $null)
{
Write-Host -ForegroundColor Yellow (Get-Date) ".....Network Adapter '" $counter "' not connected"
$IP = $IP + $null
$counter = $counter + 1
continue
}
## Revoke IP
$error.Clear()
$IP = $IP +(Get-SCIPAddress –GrantToObjectId $VMOnPD.VirtualNetworkAdapters[$counter].ID)
Write-Host -ForegroundColor Yellow (Get-Date) "....Revoking IP " $IP[$counter] "from Primary VM"
Revoke-SCIPAddress $IP[$counter]
if ($error.count -eq 0)
{
Write-Host -ForegroundColor Green (Get-Date) "....." $IP[$counter] "revoke completed"
}
## Disconnect Primary VM
Write-Host -ForegroundColor Yellow (Get-Date) "....Disconnecting Primary VM from Network " $VMNetwork[$counter]
Set-SCVirtualNetworkAdapter -VirtualNetworkAdapter $VMOnPD.VirtualNetworkAdapters[$counter] -NoLogicalNetwork -NoConnection -NoPortClassification
Write-Host -ForegroundColor Green (Get-Date) "....Network Adapter '" $counter "' of Primary VM Disconnected"
$counter = $counter + 1
}
## Start failover
Write-Host -ForegroundColor Yellow (Get-Date) ".....We are going to Failover " $VMName " from " $primaryHostName " to " $recoveryHostName
$error.Clear()
Start-VMFailover -ComputerName $primaryHostName -VMName $VMOnPD.Name -Prepare -Confirm:$false
start-sleep 5
Write-Host -ForegroundColor Yellow (Get-Date) ".....Completing Failover on Replica site..."
Start-VMFailover -ComputerName $recoveryHostName -VMName $VMOnDR.Name -Confirm:$false
if ($ReverseRep)
{
write-host -ForegroundColor Green (Get-Date) ".....Starting Reverse Replication..."
Set-VMReplication -ComputerName $recoveryHostName -reverse -VMName $VMOnDR.Name
}
if ($error -ne 0)
{
write-host -ForegroundColor Red (Get-Date) ".....Error occured during Planned Failover for VM $VMName"
write-host -ForegroundColor Red (Get-Date) ".....Please manually complete Failover before continuing"
Write-Host -ForegroundColor Red (Get-Date) ".....Press any key to continue..."
$ignoreKey = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
Write-Host -ForegroundColor Green (Get-Date) ".....Connecting Network(s) to Failed-over VM"
$counter = 0
foreach($vmAdapter in $VMOnPDAdapter)
{
if ($VMNetwork[$counter] -eq $null)
{
Write-Host -ForegroundColor Yellow (Get-Date) ".....Network Adapter '" $counter "' not connected"
$counter = $counter + 1
continue
}
Write-Host -ForegroundColor Yellow (Get-Date) "Granting " $IP[$counter] "to Failed-over VM"
Grant-SCIPAddress -GrantToObjectType "VirtualNetworkAdapter" -GrantToObjectID $VMOnDRAdapter[$counter].ID -StaticIPAddressPool $Pools[$counter] –IPAddress $IP[$counter]
Write-Host -ForegroundColor Green (Get-Date) "Granting IP completed"
Write-Host -ForegroundColor Yellow (Get-Date) "Connecting Replica VM to " $VMNetwork[$counter]
Set-SCVirtualNetworkAdapter -VirtualNetworkAdapter $VMOnDRAdapter[$counter] -IPv4AddressType static -VMNetwork $VMNetwork[$counter] -VMSubnet $VMSubnet[$counter]
Write-Host -ForegroundColor Green (Get-Date) "Network Adapter '" $counter "' of Failed-over VM connected to " $VMNetwork[$counter]
$counter = $counter + 1
}
Запуск скрипта для обратной репликации или отмены
Этот скрипт выполняет следующее.
- Если скрипт перехода на другой ресурс выполнялся без применения обратной репликации, вы можете использовать этот скрипт для выполнения обратной репликации или отмены отработки отказа.
- При отмене сценарий отменяет действия сети и восстанавливает подключения к основной виртуальной машине после отключения реплика сетей виртуальных машин.
Выполнение скрипта
Этот скрипт должен выполняться, если скрипт отработки отказа запущен со значением $false для параметра $ReverseRep. Этот скрипт принимает три аргумента:
- $VMName — имя виртуальной машины.
- $ReverseRep — логический аргумент, который указывает, нужно ли выполнять обратную репликацию. Значение $true обозначает, что обратная репликация выполняется.
- $CancelFO — логический аргумент, который указывает, нужно ли отменять отработку отказа. Значение $true обозначает, что выполняется отмена на основном и резервном сайтах.
Параметры $ReverseRep и $CancelFO не могут одновременно иметь значения $true. После успешного выполнения скрипта на обеих виртуальных машинах должно быть установлено состояние Репликация включена.
Выполните скрипт:
Param(
[Parameter(Mandatory=$True)]
[string]$VMName,
[Parameter(Mandatory=$true)]
[boolean]$ReverseRep,
[Parameter(Mandatory=$true)]
[boolean]$CancelFO
)
# the script running on system with SCVMM Console/PowerShell installed. Also, requires Hyper-V powershell module.
Import-Module hyper-v
if ($ReverseRep -eq $CancelFO)
{
write-host -ForegroundColor Red (Get-Date) "....Please ensure that one and only one of the parameters -ReverseRep and -CancelFO is passed as $True"
write-host -ForegroundColor Red (Get-Date) "....Exiting"
exit 1
}
## Refresh VM configuration and initialize
Write-Host -ForegroundColor Green (Get-Date) ".....Refreshing the VMs..."
Get-SCVirtualMachine -Name $VMName | Read-SCVirtualMachine
$VMOnPD = Get-SCVirtualMachine -Name $VMName | where {$_.IsPrimaryVM -eq $true}
$VMOnDR = Get-SCVirtualMachine -Name $VMName | where {$_.IsPrimaryVM -eq $false}
$error.Clear()
$VMRepConfig = Get-VMReplication -ComputerName $VMOnPD.HostName -VMName $VMOnPD.Name
$VMRepConfig = Get-VMReplication -ComputerName $VMOnDR.HostName -VMName $VMOnPD.Name
if ($error -ne 0)
{
$temp = $VMOnPD.HostName.Split(".")
$primaryHostName = $temp[0]
$temp = $VMOnDR.HostName.Split(".")
$recoveryHostName = $temp[0]
write-host -ForegroundColor Red (Get-Date) "....Error in getting VM Replication state using FQDN, switching to Hostname"
write-host -ForegroundColor Yellow (Get-Date) "....Primary Hostname: " $primaryHostName " Replica Hostname: " $recoveryHostName
$error.Clear()
$VMRepConfig = Get-VMReplication -ComputerName $primaryHostName -VMName $VMOnPD.Name
$VMRepConfig = Get-VMReplication -ComputerName $recoveryHostName -VMName $VMOnPD.Name
if ($error -ne 0)
{
write-host -ForegroundColor Red (Get-Date) "....Error in getting VM Replication state using Hostname"
write-host -ForegroundColor Red (Get-Date) "....Exiting"
exit 1
}
write-host -ForegroundColor Green (Get-Date) "....Successful in getting VM Replication state using Hostname"
}
else
{
$primaryHostName = $VMOnPD.HostName
$recoveryHostName = $VMOnDR.HostName
}
if ($VMOnDR.ReplicationStatus.ReplicationState -ne "Recovered")
{
write-host -ForegroundColor Red (Get-Date) "....Replica VM is not in Failed over state. Actual State " $VMOnDR.ReplicationStatus.ReplicationState
write-host -ForegroundColor Red (Get-Date) "....Exiting"
exit 1
}
$error.Clear()
if ($ReverseRep -eq $true)
{
write-host -ForegroundColor Green (Get-Date) ".....Starting Reverse Replication..."
Set-VMReplication -ComputerName $recoveryHostName -reverse -VMName $VMOnDR.Name
if ($error -ne 0)
{
write-host -ForegroundColor Red (Get-Date) ".....Error occured during Reverse Replication for VM $VMName"
write-host -ForegroundColor Red (Get-Date) ".....Please manually complete Reverse replication"
exit 1
}
write-host -ForegroundColor Green (Get-Date) ".....Reverse Replication completed..."
exit 0
}
if ($VMOnDR.StatusString -ne "Stopped")
{
write-host -ForegroundColor Red (Get-Date) "....VM is not in stopped state. Actual State " $VMOnDR.StatusString
write-host -ForegroundColor Red (Get-Date) "....Exiting"
exit 1
}
$VMOnPDAdapter = Get-SCVirtualNetworkAdapter -VM $VMonPD
$VMOnDRAdapter = Get-SCVirtualNetworkAdapter -VM $VMonDR
$fileName = $VMName + (Get-Date).ToString() + ".txt"
$fileName = $fileName.Replace("/","_")
$fileName = $fileName.Replace(":","_")
Write-Host -ForegroundColor Yellow (Get-Date) "....Dumping network information for $VMName to file $fileName"
Write-Host -ForegroundColor Yellow (Get-Date) "....Number of Network adapters found on Failed-over VM: " $VMOnDRAdapter.count
$VMNetwork = @()
$VMSubnet = @()
$Pools = @()
$counter = 0
foreach($vmAdapter in $VMOnDRAdapter)
{
if ($vmAdapter.VMNetwork -eq $null)
{
$VMNetwork = $VMNetwork + $null
$VMSubnet = $VMSubnet + $null
$Pools = $Pools + $null
$counter = $counter + 1
continue
}
$VMNetwork = $VMNetwork + (Get-SCVMNetwork -Name $vmAdapter.VMNetwork.Name -ID $vmAdapter.VMNetwork.ID)
$VMSubnet = $VMSubnet + (Get-SCVMSubnet -Name $vmAdapter.VMSubnet.Name | where {$_.VMNetwork.ID -eq $vmAdapter.VMNetwork.ID})
#$PortClassification = Get-SCPortClassification | where {$_.Name -eq "Guest Dynamic IP"}
$Pools = $Pools + (Get-SCStaticIPAddressPool -IPv4 | where {$_.VMsubnet.name -eq $vmAdapter.VMSubnet.Name})
Out-File -FilePath $fileName -InputObject $VMNetwork[$counter] -Append
Out-File -FilePath $fileName -InputObject $VMSubnet[$counter] -Append
Out-File -FilePath $fileName -InputObject $Pools[$counter] -Append
$counter = $counter + 1
}
if ($error.Count -ne 0)
{
write-host -ForegroundColor Red (Get-Date) "....Error is gathering information for $VMName. No changes made"
write-host -ForegroundColor Red (Get-Date) "....Exiting"
exit 1
}
$IP = @()
$counter = 0
foreach($vmAdapter in $VMOnDRAdapter)
{
if ($VMNetwork[$counter] -eq $null)
{
Write-Host -ForegroundColor Yellow (Get-Date) ".....Network Adapter '" $counter "' not connected"
$IP = $IP + $null
$counter = $counter + 1
continue
}
## Revoke IP
$error.Clear()
$IP = $IP +(Get-SCIPAddress –GrantToObjectId $VMOnDR.VirtualNetworkAdapters[$counter].ID)
Write-Host -ForegroundColor Yellow (Get-Date) "....Revoking IP " $IP[$counter] "from Replica VM"
Revoke-SCIPAddress $IP[$counter]
if ($error.count -eq 0)
{
Write-Host -ForegroundColor Green (Get-Date) "....." $IP[$counter] "revoke completed"
}
## Disconnect Replica VM
Write-Host -ForegroundColor Yellow (Get-Date) "....Disconnecting Replica VM from Network " $VMNetwork[$counter]
Set-SCVirtualNetworkAdapter -VirtualNetworkAdapter $VMOnDR.VirtualNetworkAdapters[$counter] -NoLogicalNetwork -NoConnection -NoPortClassification
Write-Host -ForegroundColor Green (Get-Date) "....Network Adapter '" $counter "' of Replica VM Disconnected"
$counter = $counter + 1
}
## Cancel failover
Write-Host -ForegroundColor Yellow (Get-Date) ".....We are going to Cancel Failover " $VMName " on both " $primaryHostName " and " $recoveryHostName
$error.Clear()
Stop-VMFailover -ComputerName $recoveryHostName -VMName $VMName
Start-Sleep -Seconds 10
Stop-VMFailover -ComputerName $primaryHostName -VMName $VMName
if ($error -ne 0)
{
write-host -ForegroundColor Red (Get-Date) ".....Error occured during Cancel Failover for VM $VMName"
write-host -ForegroundColor Red (Get-Date) ".....Please manually Cancel Failover on both Primary and Recovery Server"
Write-Host -ForegroundColor Red (Get-Date) ".....Press any key to continue..."
$ignoreKey = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
}
Write-Host -ForegroundColor Yellow (Get-Date) ".....Connecting Network(s) back to the Primary VM"
$counter = 0
foreach($vmAdapter in $VMOnDRAdapter)
{
if ($VMNetwork[$counter] -eq $null)
{
Write-Host -ForegroundColor Yellow (Get-Date) ".....Network Adapter '" $counter "' not connected"
$counter = $counter + 1
continue
}
Write-Host -ForegroundColor Yellow (Get-Date) "Granting " $IP[$counter] "to Primary VM"
Grant-SCIPAddress -GrantToObjectType "VirtualNetworkAdapter" -GrantToObjectID $VMOnPDAdapter[$counter].ID -StaticIPAddressPool $Pools[$counter] –IPAddress $IP[$counter]
Write-Host -ForegroundColor Green (Get-Date) "Granting IP completed"
Write-Host -ForegroundColor Yellow (Get-Date) "Connecting Primary VM to " $VMNetwork[$counter]
Set-SCVirtualNetworkAdapter -VirtualNetworkAdapter $VMOnPDAdapter[$counter] -IPv4AddressType static -VMNetwork $VMNetwork[$counter] -VMSubnet $VMSubnet[$counter]
Write-Host -ForegroundColor Green (Get-Date) "Network Adapter '" $counter "' of Primary VM connected to " $VMNetwork[$counter]
$counter = $counter + 1
}
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по