我们在创建 Azure 云的 VM 虚拟机时,其自带的系统盘(C:)往往占用了过大的空间,产生很多额外的开销,我们可以通过如下的 PowerShell 脚本进行空间的裁剪,以优化节约花费!
具体操作步骤,请参考: https://jrudlin.github.io/2019-08-27-shrink-azure-vm-osdisk/
Shrink Azure VM System Disk PowerShell Script:
# Variables $DiskID = "TODO: 形式如同: /subscriptions/203bdbf0-69bd-1a12-a894-a826cf0a34c8/resourcegroups/rg-server1-prod-1/providers/Microsoft.Compute/disks/Server1-Server1" $VMName = "TODO: Azure VM NAME VVVVVV" $DiskSizeGB = 32 $AzSubscription = "TODO: Azure Subscription NAME SSSSSS" # 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