Azure ARM模式下建立的虛拟機隻有一次機會加入可用性集,也就是在這台虛拟機新建立的時候,建立完成後,就不能變更可用性集的設定了。
而偏偏可用性集又與負載均衡等功能密切相關,隻有加入同一可用性集的虛拟機才能配置負載均衡等功能,是以這就尴尬了,隻能删除虛拟機保留磁盤,然後再重建虛拟機将其加入可用性集。
下面的腳本可以幫助自動完成這個過程,首先腳本會收集目前虛拟機的資訊(基本資訊,磁盤,網絡等),然後将目前虛拟機删除,然後根據收集到的資訊重新将虛拟機建立出來。
注意:虛拟機的擴充和診斷設定目前不能在重建過程中恢複,腳本适用于非托管磁盤的虛拟機(托管磁盤虛拟機的腳本以後會給出),腳本不會保留虛拟機的IP位址,是以如果有需要,請将IP位址設定為靜态。
腳本如下(有一些注釋掉的内容可以自行删除):
param(
[Parameter(Mandatory = $true)]
[string]$SubscriptionName,
[Parameter(Mandatory = $true)]
[string]$ResourceGroupName,
[Parameter(Mandatory = $true)]
[string]$VMName,
[Parameter(Mandatory = $true)]
[string]$AvailabilitySetName
)
#Function GetResourceNameFromResourceId($resourceId)
#{
# return $resourceId.Substring($resourceId.LastIndexOf('/') + 1);
#}
#Function GetResourcePropertyFromResourceId($resourceId, $propertyName)
#{
# $propertyName = $propertyName + "/";
# $rgName = $resourceId.Substring($resourceId.IndexOf($propertyName) + $propertyName.Length);
# return $rgName.Substring(0, $rgName.IndexOf("/"));
#}
Function CollectVMInformation($rgName, $vmName, $avaSetName)
{
$vmInfo = @{};
$vmInfo.Add("ResourceGroup", $rgName);
$vmInfo.Add("Name", $vmName);
$vm = Get-AzureRmVM -ResourceGroupName $rgName -Name $vmName -ErrorAction Ignore -WarningAction Ignore;
if ($vm -eq $null)
{
return $null;
}
$vmInfo.Add("Size", $vm.HardwareProfile.VmSize);
$vmInfo.Add("Location", $vm.Location);
if (!(CreateAvailabilitySet $rgName $avaSetName $vm.Location))
{
return $null;
}
$avaSet = Get-AzureRmAvailabilitySet -ResourceGroupName $rgName -Name $avaSetName;
$vmInfo.Add("AvailabilitySet", $avaSet.Id);
$vmInfo.Add("OSType", $vm.StorageProfile.OsDisk.OsType.ToString());
#network properties
$nicId = ($vm.NetworkProfile.NetworkInterfaces | where {$_.Primary -eq $true}).Id;
if ($nicId -eq $null -and $vm.NetworkProfile.NetworkInterfaces.Count -eq 1)
{
$nicId = $vm.NetworkProfile.NetworkInterfaces[0].Id;
}
#$nicName = GetResourceNameFromResourceId $nicId;
#$nic = Get-AzureRmNetworkInterface -Name $nicName -ResourceGroupName $rgName;
#$subnetId = $nic.IpConfigurations[0].Subnet.Id;
#$subnetName = GetResourceNameFromResourceId $subnetId;
#$vnetName = GetResourcePropertyFromResourceId $subnetId "virtualNetworks";
#$vmInfo.Add("VirtualNetwork", $vnetName);
#$vmInfo.Add("Subnet", $subnetName);
$vmInfo.Add("PrimaryNetworkInterfaceId", $nicId);
$secondaryNics = @($vm.NetworkProfile.NetworkInterfaces | where {$_.Primary -eq $false});
$vmInfo.Add("SecondaryNetworkInterfaces", $secondaryNics);
#$vnet = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName;
#$subnet01 = Get-AzureRmVirtualNetworkSubnetConfig -Name $subnetName -VirtualNetwork $vnet;
#disk
$vmInfo.Add("OSDisk", $vm.StorageProfile.OsDisk);
$vmInfo.Add("DataDisks", @($vm.StorageProfile.DataDisks));
return $vmInfo;
}
Function DeleteOldVM($rgName, $vmName)
{
[void](Remove-AzureRmVM -ResourceGroupName $rgName -Name $vmName -Force);
#if lease is not broken, we need to sleep for some time
#sleep 10
}
Function CreateAvailabilitySet($rgName, $avaSetName, $location)
{
$avaSet = Get-AzureRmAvailabilitySet -ResourceGroupName $rgName -Name $avaSetName -ErrorAction Ignore;
if ($avaSet -eq $null)
{
$avaSet = New-AzureRmAvailabilitySet -ResourceGroupName $rgName -Name $avaSetName -Location $location;
return $true;
}
elseif ($avaSet.Sku -ne "Classic")
{
Write-Host "There's an existing availability set whose sku is not Classic, conflict!";
return $false;
} else {
return $true;
}
}
Function RebuildVM($vmInfo)
{
#basic information
$rgName = $vmInfo["ResourceGroup"];
$vmName = $vmInfo["Name"];
$vmSize = $vmInfo["Size"];
$location = $vmInfo["Location"];
$osType = $vmInfo["OSType"];
#network
#$vnetName = $vmInfo["VirtualNetwork"];
#$subnetName = $vmInfo["Subnet"];
$primaryNicId = $vmInfo["PrimaryNetworkInterfaceId"];
$secondaryNics = $vmInfo["SecondaryNetworkInterfaces"];
#disk
$osDisk = $vmInfo["OSDisk"];
$dataDisks = $vmInfo["DataDisks"];
$avaSetId = $vmInfo["AvailabilitySet"];
$vmconfig = New-AzureRmVMConfig -VMName $vmName -VMSize $vmSize -AvailabilitySetId $avaSetId;
$vmconfig = $vmconfig | Set-AzureRmVMBootDiagnostics -Disable;
if ($osType -eq "Windows")
{
$vmconfig = $vmconfig | Set-AzureRmVMOSDisk –Name $osDisk.Name -VhdUri $osDisk.Vhd.Uri -Caching $osDisk.Caching -CreateOption attach -Windows;
} else {
$vmconfig = $vmconfig | Set-AzureRmVMOSDisk –Name $osDisk.Name -VhdUri $osDisk.Vhd.Uri -Caching $osDisk.Caching -CreateOption attach -Linux;
}
$vmconfig.StorageProfile.ImageReference = $null;
foreach ($dataDisk in $dataDisks)
{
$vmconfig = $vmconfig | Add-AzureRmVMDataDisk -Name $dataDisk.Name -VhdUri $dataDisk.Vhd.Uri -Lun $dataDisk.Lun -Caching $dataDisk.Caching -CreateOption attach;
}
$vmconfig = $vmconfig | Add-AzureRmVMNetworkInterface -Id $primaryNicId -Primary;
foreach ($secondaryNic in $secondaryNics)
{
$secondaryNicId = $secondaryNic.Id;
$vmconfig = $vmconfig | Add-AzureRmVMNetworkInterface -Id $secondaryNicId;
}
[void](New-AzureRmVM -ResourceGroupName $rgName -Location $location -VM $vmconfig);
}
[void](Select-AzureRmSubscription -SubscriptionName $SubscriptionName);
Write-Host "Collecting VM information...";
$vmInfo = (CollectVMInformation $ResourceGroupName $VMName $AvailabilitySetName);
if ($vmInfo -eq $null)
{
Write-Host "Failed to collect vm information." -ForegroundColor Red;
return;
}
Write-Host "Deleting old VM...";
DeleteOldVM $ResourceGroupName $VMName;
Write-Host "Rebuilding VM...";
RebuildVM $vmInfo;
Write-Host "Finished";
腳本運作示例:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiIXZ05WZD9CX5RXa2Fmcn9CXwczLcVmds92czlGZvwVP9EUTDZ0aRJkSwk0LcxGbpZ2LcBDM08CXlpXazRnbvZ2LcRlMMVDT2EWNvwFdu9mZvwVPJhEZ1YFWhZnQYRWNS52YsRGWjZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TO1cTNxczM2ETNxgDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
腳本參數中指定的AvailabilitySetName可以是已有的,也可以指定不存在的,如果不存在的話,會建立一個AvailabilitySet,注意AvailabilitySet是區分托管和非托管的。