在不同Azure存储账号之前迁移虚拟机的vhd文件

对于Azure云的管理人员来说,把Azure虚拟机的vhd从一个存储账号迁移到另外一个存储账号是很常见的任务.。

在讨论如何把虚拟机的vhd从一个存储账号迁移到另外一个存储账号之前,我们先来回顾一下Azure虚拟机的一些基本概念。首先,对于Azure IaaS的虚拟机在设计上是把计算和存储是分离开的。在创建虚拟机的时候,所有持久vhd(系统盘,数据盘vhd文件)都是创建在Azure存储里,而不是直接在创建在HyperV的物理节点上,虚拟机启动的时候,会直接从存储账号里的vhd文件启动引导操作系统。位于存储的VHD本质上是一个blob文件,所以直接拥有存储的重要特性比如多副本,高可用等。其次,创建VM的时候,azure只允许把vhd创建在和虚拟机在同一个区域的存储里,这主要是为了保证到计算节点和存储之间的网络延迟尽可能小,从而保证虚拟机的IO性能。

在有了这些概念后,我们来看看实现把虚拟机的vhd文件从一个存储迁移到另外一个存储的一些技术流程。

  1. 1. 把虚机配置文件导出
  2. 2. 关闭虚拟机
  3. 2. 把所有的vhd文件从一个存储复制到另外一个存储
  4. 3. 删除和旧vhd关联的disk,从新的vhd创建disk
  5. 4. 从配置文件重新创建虚机并启动

关闭虚拟机并且删除disk

复制或者移动vhd文件之前很重要的一个步骤就是关闭虚拟机,保证文件的一致性,避免新的vhd文件不能正常启动的情况。关机推荐通过管理门户来完成,也可以通过下面PowerShel来完成

$servicename = “TestService”

$vmname = “TestVM”

Get-AzureVM -ServiceName $servicename -Name $vmname | Stop-AzureVM

虚拟机

复制vhd到新的存储

Azure存储提供了从一个存储账号复制文件到另外一个存储账号的api,这里有一些需要注意的地方:首先,跨存储账号的blob复制的PowerShell命令Start-AzureStorageBlobCopy是一个异步命令,也就是说会立刻返回,调用者需要通过Get-AzureStorageBlobCopyState轮询来获得复制的最新进度。其次,blob的复制是没有SLA的,所以在跨tenant复制blob的时候,可能会遇到花费时间比较长的情况。下面便是把虚拟机所有的vhd文件从老的存储账号复制到新的账号的代码示例

foreach($disk in $allDisks)
{
$elapsed = [System.Diagnostics.Stopwatch]::StartNew()
$blobName = $disk.MediaLink.Segments[2]
Write-Host “$blobName copy started at $(get-date)”
Write-Host “Source =” $sourceContext.BlobEndpoint
Write-Host “Dest =” $destContext.BlobEndpoint

$targetBlob = Start-AzureStorageBlobCopy -SrcContainer vhds -SrcBlob $blobName -DestContainer vhds -DestBlob $blobName -Context $sourceContext -DestContext $destContext -Force
do
{
if ($copyState.TotalBytes -gt 0 )
{
$percent = ($copyState.BytesCopied / $copyState.TotalBytes) * 100
Write-Host “$blobName copy completed $(‘{0:N2}’ -f $percent)%”
}
Start-Sleep -Seconds 10
$copyState = $targetBlob | Get-AzureStorageBlobCopyState
} while ($copyState.Status -ne “Success”)
Write-Host “$blobName copy ended at $(get-date)”
Write-Host “$blobName copy total elapsed time: $($elapsed.Elapsed.ToString())”
If ($disk -eq $sourceOSDisk)
{
$destOSDisk = $targetBlob
}
Else
{
$destDataDisks += $targetBlob
}
}

创建Azure Disk

在完成把VHD复制到新的存储账号后,下一步便是把所有的disk通过Add-Disk来创建出来,这里需要

Add-AzureDisk -OS $sourceOSDisk.OS -DiskName $sourceOSDisk.DiskName -MediaLocation $destOSDisk.ICloudBlob.Uri

foreach($currenDataDisk in $destDataDisks)
{
$diskName = ($sourceDataDisks | ? {$_.MediaLink.Segments[2] -eq $currenDataDisk.Name}).DiskName
Add-AzureDisk -DiskName $diskName -MediaLocation $currenDataDisk.ICloudBlob.Uri
}

创建VM

最后,用Import-AzureVM和New-AzureVM这2个powershell cmdlet就可以将虚拟机按原有的配置重新建出来。

Import-AzureVM -Path $vmConfigurationPath | Set-AzureStaticVNetIP -IPAddress $sourceVM.IpAddress | New-AzureVM -ServiceName $cloudServiceName -VNetName $vnetName -WaitForBoot

完整代码可以参考https://github.com/blrchen/AzureAutomationScripts/blob/master/Move-AzureVHD/Move-AzureVHD.ps1


Comments

48 responses to “在不同Azure存储账号之前迁移虚拟机的vhd文件”

Leave a Reply