重新部署虚拟机的主要思路是将原虚拟机以“保留磁盘”的方式删除,然后使用保留下来的磁盘重建虚拟机。
不过实际情况中,问题往往要比以上情况复杂许多,要考虑的因素例如:虚拟机的终结点,ACL,NSG,虚拟网络,子网,所在云服务的公网IP地址(如果未保留且这台虚拟机是该云服务下的唯一一台,则重建后云服务IP会发生变化),虚拟机内网IP地址,数据磁盘,实例级公网IP,可用性集等等。
这个脚本针对以上方面进行了恢复,对于实例级公网IP,由于不能固定,所以重建后该IP地址会发生变化。此外,对于云服务存在多VIP的情况,脚本中仅对默认IP进行了保留,如果添加了其他IP地址且云服务中仅有这一台虚拟机,这种情况下,未保留的其他云服务VIP会发生改变。
脚本如下:
param(
#Subscription Name
[Parameter(Mandatory = $true)]
[string]$SubscriptionName,
# Cloud Service Name
[Parameter(Mandatory = $true)]
[string]$ServiceName,
# Virtual Machine Name
[Parameter(Mandatory = $true)]
[string]$VmName
)
Function RebuildVirtualMachine()
{
# collect basic virtual machine information
Write-Host "Collecting virtual machine basic information...";
$vm = Get-AzureVM -ServiceName $ServiceName -Name $VmName;
$service = Get-AzureService -ServiceName DanEastCS;
$deployment = Get-AzureDeployment -ServiceName $ServiceName;
$vmSize = $vm.InstanceSize;
$vnetName = $vm.VirtualNetworkName;
$subnetName = $vm.VM.ConfigurationSets[0].SubnetNames[0];
$location = $service.Location;
$osType = $vm.VM.OSVirtualHardDisk.OS;
$availabilitySetName = $vm.AvailabilitySetName; # if not exist, $availabilitySetName -eq $null
Write-Host "VM Size:" $vmSize;
Write-Host "VNET:" $vnetName;
Write-Host "Subnet:" $subnetName;
Write-Host "Location:" $location;
Write-Host "OS Type:" $vm.VM.OSVirtualHardDisk.OS;
Write-Host "Availability Set:" $availabilitySetName;
# collect Disk information
Write-Host "Collecting disk information...";
$osDisk = $vm.VM.OSVirtualHardDisk; # use $osDisk.MediaLink.AbsoluteUri to get vhd url
Write-Host "OS Disk:" $osDisk.MediaLink.AbsoluteUri;
$dataDisks = $dataDisks = $vm.VM.DataVirtualHardDisks;
foreach ($dataDisk in $dataDisks)
{
Write-Host "Data Disk:" $dataDisk.MediaLink.AbsoluteUri;
}
# collect endpoint information and ACL
Write-Host "Collecting endpoint configuration...";
$endpoints = $vm | Get-AzureEndpoint; # use $endpoints[index].Acl.Rules to get acl rules
Write-Host $endpoints.Count "endpoint(s) collected";
# collect network security group to virtual machine
Write-Host "Collecting network security group information...";
$networkSecurityGroupName = $vm.VM.ConfigurationSets[0].NetworkSecurityGroup; # if not exist, $networkSecurityGroupName -eq $null
if ($networkSecurityGroupName -ne $null)
{
Write-Host "Network security group:" $networkSecurityGroupName;
}
# reservedIP (Cloud Service VIP)
$reservedIPName = $deployment.ReservedIPName;
if ($reservedIPName -eq $null)
{
Write-Host "CloudService VIP is not reserved, begin reserving...";
$reservedIPName = $ServiceName + "ReserveIP";
[void](New-AzureReservedIP -ReservedIPName $reservedIPName -ServiceName $ServiceName -Location $location);
Write-Host "CloudService VIP reserved, reservedIP name:" $reservedIPName;
}
# collect instance-level public ip address
Write-Host "Checking instance-level public ip configuration...";
$pipName = $null;
if ($vm.VM.ConfigurationSets[0].PublicIPs.Count -gt 0)
{
$pipName = $vm.VM.ConfigurationSets[0].PublicIPs[0].Name;
Write-Host "Instance-level public ip:" $pipName;
} else {
Write-Host "No instance-level public ip configured";
}
# collectstatic vnet ip
Write-Host "Collecting vnet ip configuration...";
$dip = $vm.IpAddress; # if not exist, $dip -eq $null
if ($dip -ne $null)
{
Write-Host "Vnet ip:" $dip;
}
Write-Host "Rebuilding virtual machine...";
[void](Remove-AzureVM -ServiceName $ServiceName -Name $VmName);
Write-Host "Old virtual machine removed";
# wait some time for disks to be detached
sleep(120);
Write-Host "Configuring new virtual machine";
# build virtual machine configurations
$vmConfig = New-AzureVMConfig -Name $VmName -InstanceSize $vmSize -DiskName $osDisk.DiskName;
$vmConfig = $vmConfig | Set-AzureSubnet -SubnetNames $subnetName;
# attach data disks
foreach ($dataDisk in $dataDisks)
{
$vmConfig = $vmConfig | Add-AzureDataDisk -Import -DiskName $dataDisk.DiskName -LUN $dataDisk.Lun -HostCaching $dataDisk.HostCaching;
}
# configure endpoints and ACLs
foreach ($endpoint in $endpoints)
{
if ($endpoint.LBSetName -ne $null)
{
if ($endpoint.ProbePath -ne $null)
{
$vmConfig = $vmConfig | Add-AzureEndpoint -Name $endpoint.Name -Protocol $endpoint.Protocol `
-LocalPort $endpoint.LocalPort -PublicPort $endpoint.Port `
-LBSetName $endpoint.LBSetName -ProbePort $endpoint.ProbePort `
-ProbeProtocol $endpoint.ProbeProtocol -ProbePath $endpoint.ProbePath `
-ProbeIntervalInSeconds $endpoint.ProbeIntervalInSeconds `
-ProbeTimeoutInSeconds $endpoint.ProbeTimeoutInSeconds;
} else {
$vmConfig = $vmConfig | Add-AzureEndpoint -Name $endpoint.Name -Protocol $endpoint.Protocol `
-LocalPort $endpoint.LocalPort -PublicPort $endpoint.Port `
-LBSetName $endpoint.LBSetName -ProbePort $endpoint.ProbePort `
-ProbeProtocol $endpoint.ProbeProtocol `
-ProbeIntervalInSeconds $endpoint.ProbeIntervalInSeconds `
-ProbeTimeoutInSeconds $endpoint.ProbeTimeoutInSeconds;
}
} else {
$vmConfig = $vmConfig | Add-AzureEndpoint -Name $endpoint.Name -Protocol $endpoint.Protocol `
-LocalPort $endpoint.LocalPort -PublicPort $endpoint.Port;
}
if ($endpoint.InternalLoadBalancerName -ne $null)
{
$vmConfig = $vmConfig | Set-AzureEndpoint -Name $endpoint.Name -InternalLoadBalancerName $endpoint.InternalLoadBalancerName;
}
$vmConfig = $vmConfig | Set-AzureEndpoint -Name $endpoint.Name -DirectServerReturn $endpoint.EnableDirectServerReturn -ACL $endpoint.Acl;
if ($endpoint.IdleTimeoutInMinutes -ne $null)
{
$vmConfig = $vmConfig | Set-AzureEndpoint -Name $endpoint.Name -IdleTimeoutInMinutes $endpoint.IdleTimeoutInMinutes;
}
if ($endpoint.LoadBalancerDistribution -ne $null)
{
$vmConfig = $vmConfig | Set-AzureEndpoint -Name $endpoint.Name -LoadBalancerDistribution $endpoint.LoadBalancerDistribution;
}
if ($endpoint.VirtualIPName -ne $null)
{
$vmConfig = $vmConfig | Set-AzureEndpoint -Name $endpoint.Name -VirtualIPName $endpoint.VirtualIPName;
}
}
# configure instance-level public ip
if ($pipName -ne $null)
{
$vmConfig = $vmConfig | Set-AzurePublicIP -PublicIPName $pipName;
}
# configure vnet ip
if ($dip -ne $null)
{
$vmConfig = $vmConfig | Set-AzureStaticVNetIP -IPAddress $dip;
}
# configure availability set
if ($availabilitySetName -ne $null)
{
$vmConfig = $vmConfig | Set-AzureAvailabilitySet -AvailabilitySetName $availabilitySetName;
}
Write-Host "Finished configurations, creating virtual machine...";
[void]($vmConfig | New-AzureVM -ServiceName $ServiceName -VNetName $vnetName -Location $location -WaitForBoot -WarningAction Ignore);
Write-Host "Virtual machine created";
# if reservedIP is released, re-associate it to cloudservice
$deployment = Get-AzureDeployment -ServiceName $ServiceName;
$ripName = $deployment.ReservedIPName;
if ($ripName -eq $null)
{
Write-Host "Recovering cloudservice reserved ip...";
[void](Set-AzureReservedIPAssociation -ReservedIPName $reservedIPName -ServiceName $ServiceName);
Write-Host "CloudService reserved ip recovered";
}
# configure network security group
if ($networkSecurityGroupName -ne $null)
{
$vm = Get-AzureVM -ServiceName $ServiceName -Name $VmName;
$vm | Set-AzureNetworkSecurityGroupAssociation -Name $networkSecurityGroupName -Force;
}
Write-Host "Finished rebuilding virtual machine";
}
Function BreakLease($diskUrl, $context)
{
$storageAccountName = GetPropertyFromUrl $diskUrl "https://" ".";
$containerName = GetPropertyFromUrl $diskUrl ".blob.core.chinacloudapi.cn/" "/";
$blobName = $diskUrl.Substring($diskUrl.LastIndexOf("/") + 1);
$blob = Get-AzureStorageBlob -Context $context -Container $containerName -Blob $blobName -ErrorAction Ignore;
if ($blob.ICloudBlob.Properties.LeaseStatus -eq "Locked")
{
$blob.ICloudBlob.BreakLease();
}
}
Function ShowWarning() {
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes","Description.";
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No","Description.";
$cancel = New-Object System.Management.Automation.Host.ChoiceDescription "&Cancel","Description.";
$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $cancel);
$title = "!!! Before rebuilding this virtual machine !!!";
$message = "WARNING: Data on temporary disk (Usually 'D:\' or '/dev/sdb') will be `
lost, Instance-Level Public IP Address could not be reserved (Will be `
changed), are you sure to continue?";
$result = $host.ui.PromptForChoice($title, $message, $options, 1); # 0 - YES / 1 - NO / 2 - Cancel
return $result;
}
$choice = ShowWarning;
if ($choice -eq 0)
{
$cred = Get-Credential;
[void](Add-AzureAccount -Environment AzureChinaCloud -Credential $cred);
[void](Select-AzureSubscription -SubscriptionName $SubscriptionName);
RebuildVirtualMachine;
}
执行过程:
PS C:\Users\DanielHX> &.\[ASM]rebuild_virtualmachine.ps1 -SubscriptionName XXXXXXXX -ServiceName DanEastCS -VmName DanCentOS65
!!! Before rebuilding this virtual machine !!!
WARNING: Data on temporary disk (Usually 'D:\' or '/dev/sdb') will be lost, Instance-Level Public IP Address could
not be reserved (Will be changed), are you sure to continue?
[Y] Yes [N] No [C] Cancel [?] Help (default is "N"): y
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
Collecting virtual machine basic information...
VM Size: Large
VNET: DanEastVNET
Subnet: Subnet-1
Location: China East
OS Type: Linux
Availability Set:
Collecting disk information...
OS Disk: https://danieleaststorage.blob.core.chinacloudapi.cn/vhds/DanEastCS-DanCentOS65-2016-05-17.vhd
Data Disk: https://danieleaststorage.blob.core.chinacloudapi.cn/vhds/DanServerTest-DanCentOS65-0616-DataDisk1.vhd
Data Disk: https://danieleaststorage.blob.core.chinacloudapi.cn/vhds/DanServerTest-DanCentOS65-0616-DataDisk2.vhd
Data Disk: https://danieleaststorage.blob.core.chinacloudapi.cn/vhds/DanServerTest-DanCentOS65-0616-DataDisk3.vhd
Data Disk: https://danieleaststorage.blob.core.chinacloudapi.cn/vhds/DanServerTest-DanCentOS65-0616-DataDisk4.vhd
Collecting endpoint configuration...
4 endpoint(s) collected
Collecting network security group information...
Checking instance-level public ip configuration...
No instance-level public ip configured
Collecting vnet ip configuration...
Vnet ip: 10.0.0.4
Rebuilding virtual machine...
Old virtual machine removed
Configuring new virtual machine
Finished configurations, creating virtual machine...
Virtual machine created
Finished rebuilding virtual machine