本文目录
背景
假如有一个由N台虚拟机组成的SAP系统,在上海的Azure数据中心落地,但是客户可能会想在北京数据中心搭建一套灾备系统(DR SITE)。虽然每一个数据中心都会标榜自己机房的安全性,稳定性和先进性,但是在天灾人祸不可控因素面前,为了降低业务中断时间,一套能够快速恢复的灾备系统仍旧值得拥有。
灾备系统可以重新部署,然后再同步核心数据。也可以全站复制,然后再调整核心参数。假如选择了后者,就抛出了一个问题:如何在主站不关机的情况下,把主站的虚拟机迁移到灾备站点?
为什么不选择虚拟机映像?
Azure平台上面支持给虚拟机创建映像,但是这样的映像创建时原虚拟机必须关机,并且要被通用化。通用化后,原虚拟机几乎等同于废掉了。所以此方案不可取。
为什么要选择磁盘快照?
因为磁盘快照创建时,磁盘所在的虚拟机可以保持开机。并且磁盘快照支持导出VHD,复制到灾备站点的存储账户中,就可以创建虚拟机了。
为什么需要自动化,批量,并行创建磁盘快照?
基于磁盘备份虚拟机,在不关机的情况下,数据一致性是不可能做到的,那么我们能做的就是减少整个系统进行快照捕获的时间差。假如有15个磁盘,每个手动操作可能需要5分钟,差不多得1个小时左右。如果使用PowerShell脚本自动化并行捕获快照的化,可能只需要2分钟多一点,效率提示了90%多。
脚本编写
多线程并行提高执行速度,在PowerShell中有很多途径,今天我们选择Runspace。脚本分为两部分:
- 第一部分:负责虚拟机的磁盘信息收集。
- 第二部分:负责并行快照捕获。
磁盘信息收集
输入是 Json字符串,包括资源组名称,以及资源组下面的机器名,形如:
[ { "rg":"SBD-SAP-POC", "vm":["Jump01","SBDEVICE01","AS01","AS02","NFS01","NFS02","ASCS01","ASCS02"] } ]
输出也是Json字符串,包含了输入机器中所有的磁盘参数,形如:
[
{
"OsType": 0,
"EncryptionSettings": null,
"Name": "Jump01_OsDisk_1_7cf45e4ffedc4756a7a6ca818238a4b7",
"Vhd": null,
"Image": null,
"Caching": 2,
"WriteAcceleratorEnabled": null,
"CreateOption": "FromImage",
"DiskSizeGB": 127,
"ManagedDisk": "Microsoft.Azure.Management.Compute.Models.ManagedDiskParameters",
"ResouceGroup": "SBD-SAP-POC",
"VmName": "Jump01",
"StorageAccountType": "Standard_LRS",
"ResourceId": "/subscriptions/xxxxxxx-xxx/resourceGroups/SBD-SAP-POC/providers/Microsoft.Compute/disks/Jump01_OsDisk_1_7cf45e4ffedc4756a7a6ca818238a4b7",
"ImageId": "a17aa115-4f46-4d6c-a30c-c8bf0e09efff"
},
上面红色的ImageId,是我自己生成的GUID,在创建快照时,也会作为磁盘快照的名称。所以这一步生成的json文件,不仅仅是中间结果,还是我们创建的快照和原始虚拟机之间的关系映射表,要保存好。
贴脚本:
Import-AzureRmContext -Path .\az.data # # 包装 VM的Disk对象,增加资源组和虚拟机名称,并生成一个唯一的镜像Id # function New-WrapDisk { param( $Disk, $ResouceGroup, $VmName, $StorageAccountType, $ResourceId) $Disk | Add-Member -NotePropertyName "ResouceGroup" -NotePropertyValue $ResouceGroup $Disk | Add-Member -NotePropertyName "VmName" -NotePropertyValue $VmName $Disk | Add-Member -NotePropertyName "StorageAccountType" -NotePropertyValue $StorageAccountType $Disk | Add-Member -NotePropertyName "ResourceId" -NotePropertyValue $ResourceId $Disk | Add-Member -NotePropertyName "ImageId" -NotePropertyValue (New-Guid) $Disk } # 需要批量创建镜像的磁盘所在的虚拟机列表,这里定义成json, # 方便后续从文件进行配置读取 # $vmListJson = @" [ { "rg":"SBD-SAP-POC", "vm":["Jump01","SBDEVICE01","AS01","AS02","NFS01","NFS02","ASCS01","ASCS02"] } ] "@ | ConvertFrom-Json # # 导出所有虚拟机磁盘的配置信息 # $vmListJson | ForEach-Object { $rg = $_.rg $_.vm | foreach { $vmName = $_ $vm = Get-AzureRmVM -ResourceGroupName $rg -Name $vmName $vm.StorageProfile.OsDisk | foreach { New-WrapDisk -Disk $_ ` -ResouceGroup $rg ` -VmName $vmName ` -StorageAccountType $_.ManagedDisk.StorageAccountType ` -ResourceId $_.ManagedDisk.Id } $vm.StorageProfile.DataDisks | foreach { New-WrapDisk -Disk $_ ` -ResouceGroup $rg ` -VmName $vmName ` -StorageAccountType $_.ManagedDisk.StorageAccountType ` -ResourceId $_.ManagedDisk.Id } } } | ConvertTo-Json -Depth 1 | Out-File vm-disk.config
磁盘快照捕获
脚本还是很精简的:
- 读取第一部分生成的磁盘信息文件。
- 检查目标资源组是否存在,如果不存在则创建。
- 并行处理,没有选择用Job,也没有选择用Workflow,而选择了Runspace,只是为了让所有的工作在同一个会话中,避免Azure账号多次登陆。
# # 创建磁盘镜像函数定义 # function New-AzureVMDiskImage { param( [string]$DiskConfigFileName, [string]$AzureContextFileName, [string]$ImageResourceGroup, [string]$Location ) $diskConfig = Get-Content .\vm-disk.config -Raw | ConvertFrom-Json Write-Output "配置文件中,共检测到$($diskConfig.Count)个磁盘" # 登陆 Import-AzureRmContext -Path $AzureContextFileName | Out-Null # 创建资源组 $rg = Get-AzureRmResourceGroup -Name $ImageResourceGroup -ErrorAction SilentlyContinue if($rg -eq $null) { $rg = New-AzureRmResourceGroup -Name $ImageResourceGroup -Location $Location } $sb = { param( $cfg, $Location, $ImageResourceGroup) $disk = Get-AzureRmDisk ` -ResourceGroupName $cfg.ResouceGroup ` -DiskName $cfg.Name $diskSnapshotCfg = new-AzureRmSnapshotConfig ` -SourceUri $disk.Id ` -Location $Location ` -CreateOption 'Copy' Write-Output "正在创建磁盘【$($disk.Name)】 的镜像.." New-AzureRmSnapshot ` -Snapshot $diskSnapshotCfg ` -SnapshotName $cfg.ImageId ` -ResourceGroupName $ImageResourceGroup | Out-Null Write-Output "磁盘【$($disk.Name)】 的镜像创建完毕" } $jobs = @() foreach ($cfg in $diskConfig) { $job=[PowerShell]::Create() $job = $job.AddScript($sb); $job = $job.AddParameter("cfg",$cfg).AddParameter("Location",$Location).AddParameter("ImageResourceGroup",$ImageResourceGroup) Write-Output "创建磁盘【$($cfg.Name)】的Job已开始" $jobs += New-Object PSObject -Property @{ cfg = $cfg Task = $job Result = $job.BeginInvoke() } } ForEach ($job in $jobs) { $job.Task.EndInvoke($job.Result) } } # # 调用示例 # New-AzureVMDiskImage ` -DiskConfigFileName ".\vm-disk.config" ` -AzureContextFileName ".\az.data" ` -ImageResourceGroup "SBD-SAP-POC-Image" ` -Location 'ChinaNorth'
脚本执行的输出如下:
配置文件中,共检测到15个磁盘 创建磁盘【Jump01_OsDisk_1_7cf45e4ffedc4756a7a6ca818238a4b7】的Job已开始 创建磁盘【SBDEVICE01】的Job已开始 创建磁盘【SBDEVICE01-Data-1】的Job已开始 创建磁盘【SBDEVICE01-Data-2】的Job已开始 创建磁盘【SBDEVICE01-Data-3】的Job已开始 创建磁盘【AS01_OsDisk_1_783772817628472a8dd163dd817c7a4f】的Job已开始 创建磁盘【AS01-Data-1】的Job已开始 创建磁盘【AS02_OsDisk_1_e38de3104b494da58f639a0a7b5b022c】的Job已开始 创建磁盘【AS02-Data-1】的Job已开始 创建磁盘【NFS01_OsDisk_1_1c4b77d6c0b241faa65de4b490788d81】的Job已开始 创建磁盘【NFS01-Data-1】的Job已开始 创建磁盘【NFS02_OsDisk_1_b93ab2b39b7948d5ac71047af1916d4c】的Job已开始 创建磁盘【NFS02-Data-1】的Job已开始 创建磁盘【ASCS01_OsDisk_1_ca38c16f7119453d8fb5007196997952】的Job已开始 创建磁盘【ASCS02_OsDisk_1_f2dd7bbc20a040b1bffdecf89c480159】的Job已开始 正在创建磁盘【Jump01_OsDisk_1_7cf45e4ffedc4756a7a6ca818238a4b7】 的镜像.. 磁盘【Jump01_OsDisk_1_7cf45e4ffedc4756a7a6ca818238a4b7】 的镜像创建完毕 正在创建磁盘【SBDEVICE01】 的镜像.. 磁盘【SBDEVICE01】 的镜像创建完毕 正在创建磁盘【SBDEVICE01-Data-1】 的镜像.. 磁盘【SBDEVICE01-Data-1】 的镜像创建完毕 正在创建磁盘【SBDEVICE01-Data-2】 的镜像.. 磁盘【SBDEVICE01-Data-2】 的镜像创建完毕 正在创建磁盘【SBDEVICE01-Data-3】 的镜像.. 磁盘【SBDEVICE01-Data-3】 的镜像创建完毕 正在创建磁盘【AS01_OsDisk_1_783772817628472a8dd163dd817c7a4f】 的镜像.. 磁盘【AS01_OsDisk_1_783772817628472a8dd163dd817c7a4f】 的镜像创建完毕 正在创建磁盘【AS01-Data-1】 的镜像.. 磁盘【AS01-Data-1】 的镜像创建完毕 正在创建磁盘【AS02_OsDisk_1_e38de3104b494da58f639a0a7b5b022c】 的镜像.. 磁盘【AS02_OsDisk_1_e38de3104b494da58f639a0a7b5b022c】 的镜像创建完毕 正在创建磁盘【AS02-Data-1】 的镜像.. 磁盘【AS02-Data-1】 的镜像创建完毕 正在创建磁盘【NFS01_OsDisk_1_1c4b77d6c0b241faa65de4b490788d81】 的镜像.. 磁盘【NFS01_OsDisk_1_1c4b77d6c0b241faa65de4b490788d81】 的镜像创建完毕 正在创建磁盘【NFS01-Data-1】 的镜像.. 磁盘【NFS01-Data-1】 的镜像创建完毕 正在创建磁盘【NFS02_OsDisk_1_b93ab2b39b7948d5ac71047af1916d4c】 的镜像.. 磁盘【NFS02_OsDisk_1_b93ab2b39b7948d5ac71047af1916d4c】 的镜像创建完毕 正在创建磁盘【NFS02-Data-1】 的镜像.. 磁盘【NFS02-Data-1】 的镜像创建完毕 正在创建磁盘【ASCS01_OsDisk_1_ca38c16f7119453d8fb5007196997952】 的镜像.. 磁盘【ASCS01_OsDisk_1_ca38c16f7119453d8fb5007196997952】 的镜像创建完毕 正在创建磁盘【ASCS02_OsDisk_1_f2dd7bbc20a040b1bffdecf89c480159】 的镜像.. 磁盘【ASCS02_OsDisk_1_f2dd7bbc20a040b1bffdecf89c480159】 的镜像创建完毕
这是所有磁盘创建完成后在Azure门户上的列表截图:
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!