《Windows Azure Platform 系列文章目录

  为什么要写这篇Blog?

  之前遇到过很多客户提问:

  (1)我之前创建的虚拟机,没有加入虚拟网络。现在需要重新加入虚拟机网络,应该如何操作?

  (2)之前创建的虚拟机,想重新设置DNS。但是又想保留虚拟机里面的内容,应该如何操作?

  (3)我之前部署在订阅A下面的一些虚拟机,现在想迁移到订阅B下面,应该如何操作?

  

  在回答这些问题之前,我们先回顾一下Azure虚拟机可能需要的资源:

  (1)虚拟网络(Azure Virtual Network)

  定义Subnet和IP Rang,Azure虚拟机的内网IP地址是由Azure Virtual Network

  (2)云服务(Cloud Service)

  定义了Azure虚拟机的DNS地址

  (3)VHD文件(Virtual Hard Disk)

  我们在虚拟机安装的任何软件和配置,都是持久化保存在Azure VHD文件里的。

  所以只要能保留VHD,就可以迁移Azure虚拟机,同时保留虚拟机里面的内容

  好了,看到这里,各位看官明白了,其实我们只要迁移Azure虚拟机所在的VHD文件即可。

  然后还有一个问题请读者注意:

  如果你的Azure VM所在的DNS Name已经固定的公网IP地址(Reserved IP)

  (Azure China (8) 使用Azure PowerShell创建虚拟机,并设置固定Virtual IP Address和Private IP)

  我们在迁移Azure虚拟机的时候需要注意,固定公网IP地址只能属于某一个订阅,无法跨订阅,或者是多个订阅共享同一个公网IP地址。

  所以当我们将某一台虚拟机,从订阅A迁移到订阅B的时候,订阅A下的该虚拟机的公网IP地址,是无法转换到订阅B下的。

  当我们跨订阅迁移Azure虚拟机的时候,笔者建议的做法是:先将订阅A下的公网IP地址进行释放。然后再订阅B下申请新的公网IP地址。

  如果客户已经设置了自定义域名的A记录,需要重新设置,指向到订阅B下的公网IP地址。

  好了,描述了那么多的内容。我们开始今天的文章吧。

  首先笔者先模拟一个场景,假设我们有两个订阅,Subscription_ASubscription_B

  在订阅Subscription_A下有以下部署:

  -  虚拟网络名称VNetA,有一个子网Subnet-1

  -  有1台虚拟机,虚拟机DNS Name为LeiCloudServiceA

  -  该虚拟机的机器名为LeiVMA,操作系统为Windows Server 2012 中文版

  -  这台虚拟机有2块磁盘

  我们需要把上述虚拟机,迁移到订阅Subscription_B

  -  手动创建虚拟网络VNetB

  -  新的DNS Name为LeiCloudServiceB,新的虚拟机的机器名为LeiVMB

  -  需要保留原虚拟机里的磁盘内容

  关键步骤有以下几点:

  (1)请在Azure PowerShell下运行

  (2)输入源订阅,和目标订阅的Azure用户名和密码

  (3)手动创建目标订阅下的虚拟机网络和子网

  (4)更新PowerShell下的相关参数

  (5)PowerShell会提示:首先把需要迁移的Azure虚拟机关机

  (6)PowerShell会在目标订阅下,创建新的存储账户

  (7)PowerShell会将源订阅的下的,需要迁移的虚拟机的所有VHD文件,拷贝到目标订阅下的,新的存储账号里

  (8)在目标订阅下,将VHD系统文件创建为虚拟机镜像,将VHD数据文件创建为虚拟机磁盘镜像

  (9)如果源订阅和目标订阅是同一个订阅的话,会有提示:Please update the Diskname in the configuration file 

  客户手动修改PowerShell同一目录下的,ExportedVMConfig文件,修改以下XML节点:

  <DataVirtualHardDisks>和<OSVirtualHardDisk>

  

  在DiskName里,增加相应的后缀。

  比如$DiskNameSuffix变量,我们赋值为-prem

  则修改上面的红色部分的DiskName,参数增加后缀-prem。如下图:

  

  修改完毕后,直接按Enter 继续执行PowerShell

  PowerShell源代码如下:

<#
Modified by Lei Zhang on 2016-04-29
#> Param
(
#源订阅ID
[string] $SourceSubscriptionId="e2eaa986-29d9-48c9-8302-1e2900a4504b", #源云服务名称
[string] $SourceCloudServiceName="lei2012chnvm", #源虚拟机名称
[string] $SourceVMName="lei2012chnvm01", #源Azure Storage Container Name
[string] $SourceStorageContainerName="vhds", #目标订阅ID
[string] $DestSubscritpionId="919ae904-1260-4f4b-85a6-8ac9d44d3106", #目标云服务名称
[string] $DestCloudServiceName="LeiNewVM", #目标虚拟机名称
[string] $DestVMName="LeiNewVM01", #目标存储账户名称
[string] $DestStorageAccountName="leinewvmstorage1", #目标Azure Storage Container Name
[string] $DestStorageContainerName="vhds", #目标虚拟机所在数据中心,分别为China North和China East
[string] $DestLocationName, #目标虚拟机所在虚拟网络名称
[string] $DestVNetName="LeiDesVNet", #目标虚拟机所在子网名称
[string] $DestSubNet="Subnet-1", #目标虚拟机磁盘文件后缀
[string] $DiskNameSuffix="-prem"
) $IsSameSub = $false if (($SourceSubscriptionId -eq $DestSubscritpionId) -or ($DestSubscritpionId -eq ""))
{
Write-Host "VM is copied at the same subscription!" -ForegroundColor Green
$IsSameSub = $true
$DestSubscritpionId = $SourceSubscriptionId
} if ($SourceStorageContainerName -eq "")
{
Write-Host "Using the default source storage container vhds!" -ForegroundColor Green
$SourceStorageContainerName = "vhds"
} if ($DestStorageContainerName -eq "")
{
Write-Host "Using the default destination storage container vhds!" -ForegroundColor Green
$DestStorageContainerName = "vhds"
} if ($DestLocationName -eq "")
{
$DestLocationName = "China East"
} if ($DestSubNet -eq "")
{
$DestSubNet = "Subnet-1"
} if (($DiskNameSuffix -eq $null) -or ($DiskNameSuffix -eq ""))
{
$DiskNameSuffix = "-prem"
Write-Host "Set the copyed Disk Name Suffix as:"+ $DiskNameSuffix -ForegroundColor Green
} Write-Host "`t================= Migration Setting =======================" -ForegroundColor Green
Write-Host "`t Source Subscription ID = $SourceSubscriptionId " -ForegroundColor Green
Write-Host "`t Source Cloud Service Name = $SourceCloudServiceName " -ForegroundColor Green
Write-Host "`t Source VM Name = $SourceVMName " -ForegroundColor Green
Write-Host "`t Dest Subscription ID = $DestSubscritpionId " -ForegroundColor Green
Write-Host "`t Dest Cloud Service Name = $DestCloudServiceName " -ForegroundColor Green
Write-Host "`t Dest Storage Account Name = $DestStorageAccountName " -ForegroundColor Green
Write-Host "`t Source Storage Container Name = $SourceStorageContainerName " -ForegroundColor Green
Write-Host "`t Dest Storage Container Name = $DestStorageContainerName " -ForegroundColor Green
Write-Host "`t Dest Location = $DestLocationName " -ForegroundColor Green
Write-Host "`t Dest VNET = $DestVNetName " -ForegroundColor Green
Write-Host "`t Dest Subnet = $DestSubNet " -ForegroundColor Green
Write-Host "`t Disk Name Prefix = $DiskNameSuffix " -ForegroundColor Green
Write-Host "`t===============================================================" -ForegroundColor Green #######################################################################
# Verify Azure Source Subscription and Azure Desination Subscription
#######################################################################
Write-Host "Please verify the Source Azure Subscription" -ForegroundColor Green
Add-AzureAccount -Environment AzureChinaCloud Write-Host "Please verify the Destination Azure Subscription" -ForegroundColor Green
Add-AzureAccount -Environment AzureChinaCloud $ErrorActionPreference = "Stop" try{ stop-transcript|out-null }
catch [System.InvalidOperationException] { } $workingDir = (Get-Location).Path
$log = $workingDir + "\VM-" + $SourceCloudServiceName + "-" + $SourceVMName + ".log"
Start-Transcript -Path $log -Append -Force Select-AzureSubscription -SubscriptionId $SourceSubscriptionId #######################################################################
# Check if the VM is shut down
# Stopping the VM is a required step so that the file system is consistent when you do the copy operation.
# Azure does not support live migration at this time..
#######################################################################
$sourceVM = Get-AzureVM –ServiceName $SourceCloudServiceName –Name $SourceVMName
if ( $sourceVM -eq $null )
{
Write-Host "[ERROR] - The source VM doesn't exist. Exiting." -ForegroundColor Red
Exit
} # check if VM is shut down
if ( $sourceVM.Status -notmatch "Stopped" )
{
Write-Host "[Warning] - Stopping the VM is a required step so that the file system is consistent when you do the copy operation. Azure does not support live migration at this time. If you’d like to create a VM from a generalized image, sys-prep the Virtual Machine before stopping it." -ForegroundColor Yellow
$ContinueAnswer = Read-Host "`n`tDo you wish to stop $SourceVMName now? (Y/N)"
If ($ContinueAnswer -ne "Y") { Write-Host "`n Exiting." -ForegroundColor Red; Exit }
$sourceVM | Stop-AzureVM -StayProvisioned # wait until the VM is shut down
$sourceVMStatus = (Get-AzureVM –ServiceName $SourceCloudServiceName –Name $SourceVMName).Status
while ($sourceVMStatus -notmatch "Stopped")
{
Write-Host "Waiting VM $vmName to shut down, current status is $sourceVMStatus" -ForegroundColor Green
Sleep -Seconds 5
$sourceVMStatus = (Get-AzureVM –ServiceName $SourceCloudServiceName –Name $SourceVMName).Status
}
} # exporting the source vm to a configuration file, you can restore the original VM by importing this config file
# see more information for Import-AzureVM
$vmConfigurationPath = $workingDir + "\ExportedVMConfig-" + $SourceCloudServiceName + "-" + $SourceVMName +".xml"
Write-Host "Exporting VM configuration to $vmConfigurationPath" -ForegroundColor Green
$sourceVM | Export-AzureVM -Path $vmConfigurationPath #######################################################################
# Copy the vhds of the source vm
# You can choose to copy all disks including os and data disks by specifying the
# parameter -DataDiskOnly to be $false. The default is to copy only data disk vhds
# and the new VM will boot from the original os disk.
####################################################################### $sourceOSDisk = $sourceVM.VM.OSVirtualHardDisk
$sourceDataDisks = $sourceVM.VM.DataVirtualHardDisks # Get source storage account information, not considering the data disks and os disks are in different accounts
$sourceStorageAccountName = $sourceOSDisk.MediaLink.Host -split "\." | select -First 1
$sourceStorageAccount = Get-AzureStorageAccount –StorageAccountName $sourceStorageAccountName
$sourceStorageKey = (Get-AzureStorageKey -StorageAccountName $sourceStorageAccountName).Primary Select-AzureSubscription -SubscriptionId $DestSubscritpionId
# Create destination context
$destStorageAccount = Get-AzureStorageAccount | ? {$_.StorageAccountName -eq $DestStorageAccountName} | select -first 1
if ($destStorageAccount -eq $null)
{
New-AzureStorageAccount -StorageAccountName $DestStorageAccountName -Location $DestLocationName
$destStorageAccount = Get-AzureStorageAccount -StorageAccountName $DestStorageAccountName
}
$DestStorageAccountName = $destStorageAccount.StorageAccountName
$destStorageKey = (Get-AzureStorageKey -StorageAccountName $DestStorageAccountName).Primary $sourceContext = New-AzureStorageContext –StorageAccountName $sourceStorageAccountName -StorageAccountKey $sourceStorageKey -Environment AzureChinaCloud
$destContext = New-AzureStorageContext –StorageAccountName $DestStorageAccountName -StorageAccountKey $destStorageKey # Create a container of vhds if it doesn't exist
Set-AzureSubscription -CurrentStorageAccountName $DestStorageAccountName -SubscriptionId $DestSubscritpionId
#if ((Get-AzureStorageContainer -Context $destContext -Name vhds -ErrorAction SilentlyContinue) -eq $null)
if ((Get-AzureStorageContainer -Name $DestStorageContainerName -ErrorAction SilentlyContinue) -eq $null)
{
Write-Host "Creating a container vhds in the destination storage account." -ForegroundColor Green
# New-AzureStorageContainer -Context $destContext -Name vhds
New-AzureStorageContainer -Name $DestStorageContainerName
} $allDisks = @($sourceOSDisk) + $sourceDataDisks
$destDataDisks = @()
# Copy all data disk vhds
# Start all async copy requests in parallel.
foreach($disk in $allDisks)
{
$blobName = $disk.MediaLink.Segments[2]
# copy all data disks
Write-Host "Starting copying data disk $($disk.DiskName) at $(get-date)." -ForegroundColor Green
$sourceBlob = "https://" + $disk.MediaLink.Host + "/" + $SourceStorageContainerName + "/"
$targetBlob = $destStorageAccount.Endpoints[0] + $DestStorageContainerName + "/"
$azcopylog = "azcopy-" + $SourceCloudServiceName + "-" + $SourceVMName +".log" Write-Host "Start copy vhd to destination storage account" -ForegroundColor Green
#Write-Host .\azcopy\AzCopy\AzCopy.exe /Source:$sourceBlob /Dest:$targetBlob /SourceKey:$sourceStorageKey /DestKey:$destStorageKey /Pattern:$blobName /SyncCopy /v:$azcopylog -ForegroundColor Green #cd 'C:\Program Files (x86)\Microsoft SDKs\Azure\AzCopy'
#AzCopy.exe /Source:$sourceBlob /Dest:$targetBlob /SourceKey:$sourceStorageKey /DestKey:$destStorageKey /Pattern:$blobName /SyncCopy /v:$azcopylog #cd D:\AzCopy
#.\AzCopy.exe /Source:$sourceBlob /Dest:$targetBlob /SourceKey:$sourceStorageKey /DestKey:$destStorageKey /Pattern:$blobName /SyncCopy /v:$azcopylog #Start-AzureStorageBlobCopy is too slow
Start-AzureStorageBlobCopy -SrcContainer $SourceStorageContainerName -SrcBlob $blobName -DestContainer $DestStorageContainerName -DestBlob $blobName -Context $sourceContext -DestContext $destContext -Force if ($disk –eq $sourceOSDisk)
{
$destOSDisk = $targetBlob + $blobName
}
else
{
$destDataDisks += $targetBlob + $blobName
}
} # Wait until all vhd files are copied.
$CopyStatusReportInterval = 15
$diskComplete = @()
do
{
Write-Host "`n[WORKITEM] - Waiting for all disk copy to complete. Checking status every $CopyStatusReportInterval seconds." -ForegroundColor Yellow
# check status every 30 seconds
Sleep -Seconds $CopyStatusReportInterval
foreach ( $disk in $allDisks)
{
if ($diskComplete -contains $disk)
{
Continue
}
$blobName = $disk.MediaLink.Segments[2]
$copyState = Get-AzureStorageBlobCopyState -Blob $blobName -Container vhds -Context $destContext
if ($copyState.Status -eq "Success")
{
Write-Host "`n[Status] - Success for disk copy $($disk.DiskName) at $($copyState.CompletionTime)" -ForegroundColor Green
$diskComplete += $disk
}
else
{
if ($copyState.TotalBytes -gt 0)
{
$percent = ($copyState.BytesCopied / $copyState.TotalBytes) * 100
Write-Host "`n[Status] - $('{0:N2}' -f $percent)% Complete for disk copy $($disk.DiskName)" -ForegroundColor Green
}
}
}
}
while($diskComplete.Count -lt $allDisks.Count) # Create OS and data disks
Write-Host "Add VM OS Disk. OS "+ $sourceOSDisk.OS +"diskName:" + $sourceOSDisk.DiskName + "Medialink:"+ $destOSDisk -ForegroundColor Green # 设置源VM的Disk Name和目标VM的Disk Name
$disknameOS = $sourceOSDisk.DiskName
if($IsSameSub)
{
#OSDisk, 如果在同一个订阅下,则增加后缀以区分VHD文件名
$disknameOS = $sourceOSDisk.DiskName + $DiskNameSuffix
} Add-AzureDisk -OS $sourceOSDisk.OS -DiskName $disknameOS -MediaLocation $destOSDisk
# Attached the copied data disks to the new VM
foreach($currenDataDisk in $destDataDisks)
{
$diskName = ($sourceDataDisks | ? {$currenDataDisk.EndsWith($_.MediaLink.Segments[2])}).DiskName
if($IsSameSub)
{
#DataDisk, 如果在同一个订阅下,则增加后缀以区分VHD文件名
$diskName = ($sourceDataDisks | ? {$currenDataDisk.EndsWith($_.MediaLink.Segments[2])}).DiskName + $DiskNameSuffix
}
Write-Host "Add VM Data Disk $diskName" -ForegroundColor Green
Add-AzureDisk -DiskName $diskName -MediaLocation $currenDataDisk
} Write-Host "Import VM from " $vmConfigurationPath -ForegroundColor Green
Set-AzureSubscription -SubscriptionId $DestSubscritpionId -CurrentStorageAccountName $DestStorageAccountName # Manually change the data diskname in the same subscription coz it can't be same
if($IsSameSub)
{
$ContinueAnswer = Read-Host "`n`tPlease update the Diskname in the configuration file "+ $vmConfigurationPath +", just add your suffix $DiskNameSuffix to the filename! Then press ENTER to continue.."
}
# Import VM from previous exported configuration plus vnet info
if (( Get-AzureService | Where { $_.ServiceName -eq $DestCloudServiceName } ).Count -eq 0 )
{
New-AzureService -ServiceName $DestCloudServiceName -Location $DestLocationName
} Write-Host "`n import-AzureVM -Path $vmConfigurationPath | Set-AzureSubnet -SubnetNames $DestSubNet | New-AzureVM -ServiceName $DestCloudServiceName -VNetName $DestVNetName -WaitForBoot" -ForegroundColor Green Import-AzureVM -Path $vmConfigurationPath | Set-AzureSubnet -SubnetNames $DestSubNet | New-AzureVM -ServiceName $DestCloudServiceName -VNetName $DestVNetName -WaitForBoot

Windows Azure Virtual Machine (31) 迁移Azure虚拟机的更多相关文章

  1. [New Portal]Windows Azure Virtual Machine (22) 使用Azure PowerShell,设置Virtual Machine Endpoint

    <Windows Azure Platform 系列文章目录> 我们可以通过Windows Azure Management Portal,打开Virtual Machine的Endpoi ...

  2. Windows Azure Virtual Machine (34) 保护Azure虚拟机

    <Windows Azure Platform 系列文章目录> 请注意:我们在Azure上创建的虚拟机,都是可以通过公网IP地址来访问的.(直接通过虚拟机的IP地址:PIP,或者通过负载均 ...

  3. Windows Azure Virtual Machine (30) 修改Azure VM 的Subnet

    <Windows Azure Platform 系列文章目录> 我在使用Azure Virtual Machine虚拟机的时候,常常会结合Virtual Network虚拟网络一起使用. ...

  4. Windows Azure Virtual Machine (28) 使用Azure实例级别IP,Instance-Level Public IP Address (PIP)

    <Windows Azure Platform 系列文章目录> 本文介绍的是国内由世纪互联运维的Azure China 熟悉Azure平台的读者都知道,我们在使用Azure Virtual ...

  5. Windows Azure Virtual Machine (29) 修改Azure VM 数据磁盘容量

    <Windows Azure Platform 系列文章目录> 当我们使用Windows Azure管理界面,创建Azure虚拟机的时候,默认挂载的磁盘是固定大小的 1.比如我创建1个Wi ...

  6. [New Portal]Windows Azure Virtual Machine (16) 使用Azure PowerShell创建Azure Virtual Machine

    <Windows Azure Platform 系列文章目录> 注:本章内容和之前的[New Portal]Windows Azure Virtual Machine (12) 在本地制作 ...

  7. [New Portal]Windows Azure Virtual Machine (19) 关闭Azure Virtual Machine与VIP Address,Internal IP Address的关系(1)

    <Windows Azure Platform 系列文章目录> 默认情况下,通过Azure Management Portal创建的Public IP和Private IP都是随机分配的. ...

  8. [New Portal]Windows Azure Virtual Machine (20) 关闭Azure Virtual Machine与VIP Address,Internal IP Address的关系(2)

    <Windows Azure Platform 系列文章目录> 默认情况下,通过Azure Management Portal创建的Public IP和Private IP都是随机分配的. ...

  9. Windows Azure Virtual Machine (36) 扩展Azure ARM VM的磁盘大小

    <Windows Azure Platform 系列文章目录> 在默认情况下,Azure ARM VM的操作系统磁盘(OS Disk),容量为: (1)Windows VM OS Disk ...

随机推荐

  1. C# 通过服务启动窗体(把窗体添加到服务里)实现用户交互的windows服务[转发]

    由于个人需要,想找一个键盘记录的程序,从网上下载了很多,多数都是需要注册的,另外也多被杀软查杀.于是决定自己写一个,如果作为一个windows应用程序,可以实现抓取键盘的记录.想要实现随系统启动的话, ...

  2. 读《我是IT小小鸟》后有感

    我是一名大一新生,在下半学期开学时,我迎来新课程——<大学生职业生涯规划与就业指导 >.这是一门既新颖,又有许多就业知识和理论的学科.在课上,老师向我们推荐了一本书,名叫<我是IT小 ...

  3. 详解spring事务属性

    Spring声明式事务让我们从复杂的事务处理中得到解脱.使得我们再也无需要去处理获得连接.关闭连接.事务提交和回滚等这些操作.再也无需要我们在与事务相关的方法中处理大量的try…catch…final ...

  4. libnode 0.4.0 发布,C++ 语言版的 Node.js

    libnode 0.4.0 支持 Windows ,提升了性能,libuv 更新到 0.10.17 版本,libj 更新到 0.8.2 版本. libnode 是 C++ 语言版的 Node.js,和 ...

  5. 浅谈 facebook .net sdk 应用

    今天看了一篇非常好的文章,就放在这里与大家分享一下,顺便也给自己留一份.这段时间一直在学习MVC,另外如果大家有什么好的建议或者学习的地方,也请告知一下,谢谢. 这篇主要介绍如何应用facebook ...

  6. Aoite 系列(01) - 比 Dapper 更好用的 ORM

    Aoite 是一个适于任何 .Net Framework 4.0+ 项目的快速开发整体解决方案.Aoite.Data 适用于市面上大多数的数据库提供程序,通过统一封装,可以在日常开发中简单便捷的操作数 ...

  7. Silverlight中异步调用WCF服务,传入回调函数

    以前学的ASP.NET,调用的都是同步方法,同步方法的好处就是,一步一步走,完成这步才会走下一步.然而,WCF使用的都是异步方法,调用之后不管有没有获得结果就直接往下走,最可恶的是异步函数都是Void ...

  8. [Java面试二]Java基础知识精华部分.

    一:java概述(快速浏览): 1991 年Sun公司的James Gosling等人开始开发名称为 Oak 的语言,希望用于控制嵌入在有线电视交换盒.PDA等的微处理器: 1994年将Oak语言更名 ...

  9. Atitti 知识图谱构建方法attilax 总结

    Atitti 知识图谱构建方法attilax 总结   1.1. 知识图谱schema构建(体系化)1 1.2. 纵向垂直拓展(向上抽象,向下属性拓展)2 1.3. 横向拓展2 1.4. 网拓展2 1 ...

  10. 模糊测试——强制发掘安全漏洞的利器(Jolt 大奖精选丛书)

    模糊测试——强制发掘安全漏洞的利器(Jolt 大奖精选丛书) [美]Sutton, M.Greene, A.Amini, P. 著 段念赵勇译 ISBN 978-7-121-21083-9 2013年 ...