作者:魏衡,微软云解决方案架构师

在 Azure 经典 ASM 模式下,可以通过Manage Portal上捕获 VM 的镜像,并创建新的VM。在Azure 资源管理器 (ARM) 模式下,在Portal上目前还没有这个功能,要做VM镜像的捕获和创建新的VM需要用PowerShell或Azure CLI来实现。

本文将介绍如何用PowerShell捕获VM的镜像,并用PowerShell从这个Image创建新的VM。

一、VM的Generalized

本文采用的是Linux CentOS的机器,需要通过waageng对其进行Generalized。就是删除用户信息:

[root@hwhpc04 ~]# waagent -deprovision+user
WARNING! The waagent service will be stopped.
WARNING! All SSH host key pairs will be deleted.
WARNING! Cached DHCP leases will be deleted.
WARNING! Nameserver configuration in /etc/resolv.conf will be deleted.
WARNING! root password will be disabled. You will not be able to login as root.
WARNING! hengwei account and entire home directory will be deleted.
Do you want to proceed (y/n)? y
[root@hwhpc04 ~]#

结束后,在portal上关机。

二、在PowerShell下捕获镜像
下面的PowerShell脚本进行了
1. VM的Generalized
2. Capture VM image
3. 从捕获的Image创建一台VM
具体的PowerShell代码如下:

function cpt-crtvm {
param(
#The VM resource group
[Parameter(Mandatory=$true)]
[String]$rg,

#The VM name
[Parameter(Mandatory=$true)]
[String]$vm_name,

#The new VM admin name
[Parameter(Mandatory=$true)]
[String]$newuser,

#The new VM password
[Parameter(Mandatory=$true)]
[String]$newpwd,

#The new VM size
[Parameter(Mandatory=$true)]
[String]$newvmsize,

#haset name
[Parameter(Mandatory=$true)]
[String]$haset

)
#Get a random text as the VM new name
$subhash = $null
for ($i = 0; $i -le 4; $i++){
$j = (97..122) | Get-Random -Count 1 | % {[char]$_}
$subhash = $subhash + $j
}
for ($i = 0; $i -le 4; $i++){
$j = (48..57) | Get-Random -Count 1 | % {[char]$_}
$subhash = $subhash + $j
}

#Get the VM need to be generalized
$vm = get-azurermvm -ResourceGroupName $rg -Name $vm_name
#New VM name from the radom text
$newvmname = $subhash + “vm”

#old VM generalized
set-azurermvm -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Generalized

#Catpture the VM to image
Save-AzureRmVMImage -Name $vm.Name -DestinationContainerName $subhash -VHDNamePrefix $subhash -ResourceGroupName $vm.ResourceGroupName -Path d:\hwhpc.json

#get the storage related information
$sa = Get-AzureRmStorageAccount -ResourceGroupName $vm.ResourceGroupName -Name $vm.StorageProfile.OsDisk.Vhd.Uri.Split(“/”)[2].split(“.”)[0]
$blob = $sa | Get-AzureStorageBlob -Container system | Where-Object {$_.name -match “$subhash.*vhd$”}
$url = $blob.Context.BlobEndPoint + “system/” + $blob.Name

#get the network related information
$nicname = $vm.NetworkProfile.NetworkInterfaces[0].Id.Split(“/”)[-1]
$vmnic = Get-AzureRmNetworkInterface -Name $nicname -ResourceGroupName $vm.ResourceGroupName
$vnetname = $vmnic.IpConfigurations[0].Subnet.Id.Split(“/”)[-3]
$vmvnet = Get-AzureRmVirtualNetwork -Name $vnetname -ResourceGroupName $vm.ResourceGroupName

#new VM pip name
$newvmnamepip = $subhash+”vmpip”

#create new public ip address
New-AzureRmPublicIpAddress -Name $newvmname -ResourceGroupName $vm.ResourceGroupName -Location “China East” -AllocationMethod Dynamic -DomainNameLabel $newvmnamepip
$newvmpip = Get-AzureRmPublicIpAddress -Name $newvmname -ResourceGroupName $vm.ResourceGroupName

#create new nic
New-AzureRmNetworkInterface -Name $newvmname -ResourceGroupName $vm.ResourceGroupName -Location “China East” -SubnetId $vmvnet.Subnets[0].Id -PublicIpAddressId $newvmpip.Id
$newvmnic = Get-AzureRmNetworkInterface -ResourceGroupName $vm.ResourceGroupName -Name $newvmname

#create the new vm credential
$pwd=ConvertTo-SecureString $newpwd -AsPlainText -Force
$newvmcred=New-Object System.Management.Automation.PSCredential($newuser,$pwd)

#newOSDiskName
$newosDiskName = $newvmname+”osdisk”

#haset
$has = Get-AzureRmAvailabilitySet -ResourceGroupName $vm.ResourceGroupName
$harslt = $false
foreach ($h in $ha){if($h.name -eq $haset){$harslt = $true}}
if(-not $harslt) {New-AzureRmAvailabilitySet -ResourceGroupName $vm.ResourceGroupName -Name $haset -Location $vm.Location}
$has = Get-AzureRmAvailabilitySet -ResourceGroupName $vm.ResourceGroupName -Name $haset
#Put the VM config to VM
$newvmconfig = New-AzureRmVMConfig -VMName $newvmname -VMSize $newvmsize -AvailabilitySetId $has.Id
$newvm = Set-AzureRmVMOperatingSystem -VM $newvmconfig -Linux -ComputerName $newvmname -Credential $newvmcred
$newvm = Add-AzureRmVMNetworkInterface -vm $newvm -Id $newvmnic.Id
$newosDiskUri = ‘{0}vhds/{1}-{2}.vhd’ -f $sa.PrimaryEndpoints.Blob.ToString(), “vm”,$newosDiskName
$newvm = Set-AzureRmVMOSDisk -VM $newvm -name $newosDiskName -VhdUri $newosDiskUri -CreateOption FromImage -SourceImageUri $url -Linux

$result = new-azurermvm -ResourceGroupName $vm.ResourceGroupName -Location $vm.Location -VM $newvm

}

cpt-crtvm -rg hwhpc -vm_name hwhpc03 -newuser xxxxxxx -newpwd xxxxxxx -newvmsize Standard_D1 -haset a1

代码中用了随机的Text(5个字母5个数字)来定义VM的名字。当然也可以自己定义机器的名称。
但如果自己定义机器的名称,建议在创建VM的各个组件前先检查这些组件是否有重名的情况,否则创建VM会失败。