我想创建一个操作系统磁盘小于默认 127GB 的 Azure VM。我在Azure门户中找不到这样的选项,所以我尝试缩小磁盘。我还没有成功。
我知道我可以修剪(使用碎片整理工具)并缩小卷(使用磁盘管理),但这不会改变硬盘的“物理”大小。也就是说,如果我将磁盘缩小到 40GB,则只有 87GB 未分配,而 Blob 仍会报告 127GB。
我试图实现的是缩小 blob 以匹配分配的空间,从而促进更小的 VM 映像下载/导出(例如 40 与 127gb)。
感谢任何和所有帮助。
在 Azure 中,如果您创建 VM,它将使用某些默认配置进行创建。目前,不支持从 Azure 门户减少/缩小 Azure VM 的操作系统磁盘(托管或非托管)大小(例如从 128Gb 到 32Gb),我们可以使用以下过程对其进行存档,并减少磁盘成本。
步骤 4. 现在转到磁盘的“属性”边栏选项卡并复制资源 ID
步骤 5. 现在从本地系统执行以下 PowerShell 脚本。必须将 $DiskID、$VMName、$AzSubscription 更改为您的值
# Variables
$DiskID = ""# eg. "/subscriptions/203bdbf0-69bd-1a12-a894-a826cf0a34c8/resourcegroups/rg-server1-prod-1/providers/Microsoft.Compute/disks/Server1-Server1"
$VMName = "VM-Server1"
$DiskSizeGB = 32
$AzSubscription = "Prod Subscription"
# Script
# Provide your Azure admin credentials
Connect-AzAccount
#Provide the subscription Id of the subscription where snapshot is created
Select-AzSubscription -Subscription $AzSubscription
# VM to resize disk of
$VM = Get-AzVm | ? Name -eq $VMName
#Provide the name of your resource group where snapshot is created
$resourceGroupName = $VM.ResourceGroupName
# Get Disk from ID
$Disk = Get-AzDisk | ? Id -eq $DiskID
# Get VM/Disk generation from Disk
$HyperVGen = $Disk.HyperVGeneration
# Get Disk Name from Disk
$DiskName = $Disk.Name
# Get SAS URI for the Managed disk
$SAS = Grant-AzDiskAccess -ResourceGroupName $resourceGroupName -DiskName $DiskName -Access 'Read' -DurationInSecond 600000;
#Provide the managed disk name
#$managedDiskName = "yourManagedDiskName"
#Provide Shared Access Signature (SAS) expiry duration in seconds e.g. 3600.
#$sasExpiryDuration = "3600"
#Provide storage account name where you want to copy the snapshot - the script will create a new one temporarily
$storageAccountName = "shrink" + [system.guid]::NewGuid().tostring().replace('-','').substring(1,18)
#Name of the storage container where the downloaded snapshot will be stored
$storageContainerName = $storageAccountName
#Provide the key of the storage account where you want to copy snapshot.
#$storageAccountKey = "yourStorageAccountKey"
#Provide the name of the VHD file to which snapshot will be copied.
$destinationVHDFileName = "$($VM.StorageProfile.OsDisk.Name).vhd"
#Generate the SAS for the managed disk
#$sas = Grant-AzureRmDiskAccess -ResourceGroupName $resourceGroupName -DiskName $managedDiskName -Access Read -DurationInSecond $sasExpiryDuration
#Create the context for the storage account which will be used to copy snapshot to the storage account
$StorageAccount = New-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageAccountName -SkuName Standard_LRS -Location $VM.Location
$destinationContext = $StorageAccount.Context
$container = New-AzStorageContainer -Name $storageContainerName -Permission Off -Context $destinationContext
#Copy the snapshot to the storage account and wait for it to complete
Start-AzStorageBlobCopy -AbsoluteUri $SAS.AccessSAS -DestContainer $storageContainerName -DestBlob $destinationVHDFileName -DestContext $destinationContext
while(($state = Get-AzStorageBlobCopyState -Context $destinationContext -Blob $destinationVHDFileName -Container $storageContainerName).Status -ne "Success") { $state; Start-Sleep -Seconds 20 }
$state
# Revoke SAS token
Revoke-AzDiskAccess -ResourceGroupName $resourceGroupName -DiskName $DiskName
# Emtpy disk to get footer from
$emptydiskforfootername = "$($VM.StorageProfile.OsDisk.Name)-empty.vhd"
# Empty disk URI
#$EmptyDiskURI = $container.CloudBlobContainer.Uri.AbsoluteUri + "/" + $emptydiskforfooter
$diskConfig = New-AzDiskConfig `
-Location $VM.Location `
-CreateOption Empty `
-DiskSizeGB $DiskSizeGB `
-HyperVGeneration $HyperVGen
$dataDisk = New-AzDisk `
-ResourceGroupName $resourceGroupName `
-DiskName $emptydiskforfootername `
-Disk $diskConfig
$VM = Add-AzVMDataDisk `
-VM $VM `
-Name $emptydiskforfootername `
-CreateOption Attach `
-ManagedDiskId $dataDisk.Id `
-Lun 63
Update-AzVM -ResourceGroupName $resourceGroupName -VM $VM
$VM | Stop-AzVM -Force
# Get SAS token for the empty disk
$SAS = Grant-AzDiskAccess -ResourceGroupName $resourceGroupName -DiskName $emptydiskforfootername -Access 'Read' -DurationInSecond 600000;
# Copy the empty disk to blob storage
Start-AzStorageBlobCopy -AbsoluteUri $SAS.AccessSAS -DestContainer $storageContainerName -DestBlob $emptydiskforfootername -DestContext $destinationContext
while(($state = Get-AzStorageBlobCopyState -Context $destinationContext -Blob $emptydiskforfootername -Container $storageContainerName).Status -ne "Success") { $state; Start-Sleep -Seconds 20 }
$state
# Revoke SAS token
Revoke-AzDiskAccess -ResourceGroupName $resourceGroupName -DiskName $emptydiskforfootername
# Remove temp empty disk
Remove-AzVMDataDisk -VM $VM -DataDiskNames $emptydiskforfootername
Update-AzVM -ResourceGroupName $resourceGroupName -VM $VM
# Delete temp disk
Remove-AzDisk -ResourceGroupName $resourceGroupName -DiskName $emptydiskforfootername -Force;
# Get the blobs
$emptyDiskblob = Get-AzStorageBlob -Context $destinationContext -Container $storageContainerName -Blob $emptydiskforfootername
$osdisk = Get-AzStorageBlob -Context $destinationContext -Container $storageContainerName -Blob $destinationVHDFileName
$footer = New-Object -TypeName byte[] -ArgumentList 512
write-output "Get footer of empty disk"
$downloaded = $emptyDiskblob.ICloudBlob.DownloadRangeToByteArray($footer, 0, $emptyDiskblob.Length - 512, 512)
$osDisk.ICloudBlob.Resize($emptyDiskblob.Length)
$footerStream = New-Object -TypeName System.IO.MemoryStream -ArgumentList (,$footer)
write-output "Write footer of empty disk to OSDisk"
$osDisk.ICloudBlob.WritePages($footerStream, $emptyDiskblob.Length - 512)
Write-Output -InputObject "Removing empty disk blobs"
$emptyDiskblob | Remove-AzStorageBlob -Force
#Provide the name of the Managed Disk
$NewDiskName = "$DiskName" + "-new"
#Create the new disk with the same SKU as the current one
$accountType = $Disk.Sku.Name
# Get the new disk URI
$vhdUri = $osdisk.ICloudBlob.Uri.AbsoluteUri
# Specify the disk options
$diskConfig = New-AzDiskConfig -AccountType $accountType -Location $VM.location -DiskSizeGB $DiskSizeGB -SourceUri $vhdUri -CreateOption Import -StorageAccountId $StorageAccount.Id -HyperVGeneration $HyperVGen
#Create Managed disk
$NewManagedDisk = New-AzDisk -DiskName $NewDiskName -Disk $diskConfig -ResourceGroupName $resourceGroupName
$VM | Stop-AzVM -Force
# Set the VM configuration to point to the new disk
Set-AzVMOSDisk -VM $VM -ManagedDiskId $NewManagedDisk.Id -Name $NewManagedDisk.Name
# Update the VM with the new OS disk
Update-AzVM -ResourceGroupName $resourceGroupName -VM $VM
$VM | Start-AzVM
start-sleep 180
# Please check the VM is running before proceeding with the below tidy-up steps
# Delete old Managed Disk
Remove-AzDisk -ResourceGroupName $resourceGroupName -DiskName $DiskName -Force;
# Delete old blob storage
$osdisk | Remove-AzStorageBlob -Force
# Delete temp storage account
$StorageAccount | Remove-AzStorageAccount -Force
我已经写了一篇博客文章,详细介绍了这个答案。但这里的主要问题是能够减小 Azure VM 的大小(默认为 127GB),以便实现快速导出/下载。我实现此目的的方法是修剪硬盘驱动器,然后使用 Disk2VHD 创建正在运行的虚拟机的 VHD 文件。 Disk2VHD 将创建一个可扩展磁盘,其大小仅与磁盘上的当前数据一样大,而不是整个可用磁盘。就我而言,40GB vs 127GB。如果将此 VHD 文件保存到附加磁盘(读取:blob 存储),您的整个团队就可以通过 HTTP 轻松下载它。因此,下载量现在为 40GB,而不是 127GB。欲了解更多,请阅读我的详细博文:
http://www.kevinmcloutier.com/?p=263
原始链接不再有效: https://web.archive.org/web/20161027213258/http://kevinmcloutier.com/post/4
您必须创建自己的虚拟机映像,然后使用该映像进行部署。此模板向您展示如何使用您自己的映像进行部署。
https://github.com/Azure/azure-quickstart-templates/tree/master/101-vm-from-user-image
目前图库中的图像均为127GB。由于 Azure VM 仅使用固定大小的光盘,因此您不能只选择大小。
我仍然不是 100% 确定让它工作的神奇标准是什么,但最后,我有一个使用减少的磁盘运行的虚拟机。制作第一代就是其中之一。 我尝试了很多类似的事情,但它们都在启动时卡住了。
我的方法是:
从图库图像创建虚拟机。例如,Windows Server 2019 - 数据中心。您将拥有 128 GB 操作系统磁盘。注意:不要使用“smalldisk”版本,因为它没有 GUI。
根据您的需要调整虚拟机。您可以在此处运行调整大小脚本。因此,您最终会得到 ~90 GB 未分配空间。
(可选)为此磁盘创建快照,然后从快照创建磁盘。经过几次失败的尝试后,我开始重视已配置的虚拟机,并且不想重复配置。这些选项将通过快照和磁盘呈现给您。
从磁盘创建一个新的虚拟机。检查是否启动。启动诊断很快就会显示出来。
停止新 VM 后,查找 Sapnandu 脚本(其帖子中的步骤 5)所需的 3 个参数(subscriptionID、diskID、vmName),并在 Azure Cloud Shell 中执行该脚本。 (标题中的图标)
需要时间,大约10分钟左右。脚本完成后,新虚拟机将使用较小的磁盘运行。
因此,有一个虚拟机设置可以使脚本完美运行。 Sapnandu 的解决方案有效。非常感谢!