Automatic Azure VM resizing

Automatic Azure VM resizing

People who know me know that I often cut costs for my Azure services in a variety of ways. Automatic resizing of VMs (virtual machines) was one of the first cost savings I used. It has good and bad sides, after 3 years of testing I will try to tell you more about them.

So it started with the fact that if we have a lot of cloud servers and they are expensive, it would be good to lower the cost of maintaining them.

A certain group of servers were used intensively between 7:00 a.m. – 5:00 p.m. and outside of these hours you could say the machines were boring. The problem was that the servers could not be turned off because the services had to be available all the time.

Here, a great way to cut costs is to resize the VM. We just don’t want to do it manually, because every time after finishing the work, you would have to reduce the size, and in the morning before starting the work, you would have to increase the size.

Size Azure VM in Azure portal

We can use, for example, the Azur “Automation Account” to automate this process.

Azure automation account

We create a new “PowerShell” runbook in it, add a name and description to it, so that we know what it is in the future.

create azure runbook

In the Runbook, we give the Resource Group name where our VM is, name our VM and size specified by us.

$ResourceGroupName = "Resource_group_name"
$VMname = "VM_name"
$Size = "Standard_F1s"

$vm = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -VMName $VMname -Status
$vm = $vm.Statuses.DisplayStatus | Select-String -Pattern "VM running"

if($vm -match "VM running")
{
Stop-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMname -Force
$vm1 = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -VMName $VMname
$vm1.HardwareProfile.VmSize = $Size
Update-AzureRmVM -VM $vm1 -ResourceGroupName $ResourceGroupName
Start-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMname
}

If the machine is running, a script to resize it will be executed. If the VM is turned off, there is no need to resize it, because we don’t pay any additional charges for the turned off machine, except for the disks of course.

So the script stops the VM, changes its parameters (size) and starts it.

Now you just need to save our runbook and specify the time of the script execution. We do it using the “Add a schedule” option.

Azure add schedule

Then we need to create the same script again, only change the size and runtime to be executed before starting work, not after its completion.

The upside is that we save money. The smaller the size of the machine, the less it costs. If we have a large number of machines or machines with large dimensions, you can really save a lot.

The downside is that sometimes the machine gets stuck in a “deallocated” state, for example when some data center is out of resources or has some technical problems. Such a situation happened literally several times in these 3 years, but it is worth keeping in mind.

Therefore, I introduced an additional condition that the machine can only change size when the previous one, which was being resized, has the “running” status. We can easily check it, for example:

#if VM1 is "running" then execute the script
$sprawdz_VM = "Nazwa_wcześniej_zmienianej_VM"
$sprawdz_RG = "Nazwa_ResourceGroup_wcześniej_zmienianej_VM"

$VMStats = (Get-AzureRmVM -Name $sprawdz_VM -ResourceGroupName $sprawdz_RG -Status).Statuses

$VMStats= ($VMStats | Where Code -Like 'PowerState/*')[0].DisplayStatus

if ($VMStats  -eq "VM running")
{
PLEASE INSERT THE SCRIPT FROM THE SIZE HERE
}

Finally, I give the entire content of the runbook:

$DateTimeNow = Get-Date
if($DateTimeNow.DayOfWeek -ne "Saturday" -and $DateTimeNow.DayOfWeek -ne "Sunday") 
{
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName         
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint 
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} 
else
{
 Write-Error -Message $_.Exception
throw $_.Exception
}
}



$sprawdz_VM = "Nazwa_wcześniej_zmienianej_VM"
$sprawdz_RG = "Nazwa_ResourceGroup_wcześniej_zmienianej_VM"

$VMStats = (Get-AzureRmVM -Name $sprawdz_VM -ResourceGroupName $sprawdz_RG -Status).Statuses
$VMStats= ($VMStats | Where Code -Like 'PowerState/*')[0].DisplayStatus

#jeśli poprzednia maszyna VM1 ma stan "running" to wykonaj skrypt
if ($VMStats  -eq "VM running")
{
$ResourceGroupName = "Nazwa_resource_group"
$VMname = "Nazwa_VM"
$Size = "Standard_F1s"

$vm = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -VMName $VMname -Status
$vm = $vm.Statuses.DisplayStatus | Select-String -Pattern "VM running"

# jeśli maszyna której chcesz zmienić rozmiar ma stan "running" to wykonaj skrypt 
if($vm -match "VM running")
{
Stop-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMname -Force
$vm1 = Get-AzureRmVM -ResourceGroupName $ResourceGroupName -VMName $VMname
$vm1.HardwareProfile.VmSize = $Size
Update-AzureRmVM -VM $vm1 -ResourceGroupName $ResourceGroupName
Start-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VMname
}
}

More information on the Automation Account can be found, as usual, in the Microsoft documentation https://docs.microsoft.com/en-us/azure/automation/automation-intro

More information on the sizes of virtual machines can be found at: https://docs.microsoft.com/en-us/azure/virtual-machines/sizes

If you would like to know more ways to save money on Azure, I invite you to my other entries in the Azure category https://lepczynski.it/en/category/azure_en/

2 thoughts on “Automatic Azure VM resizing”

  1. Hi. I seem to be stuck with this. It does everything except the resize. It powers it off and on again but doenst resize. The log shows “‘Vhd’ cannot be null.” When i try it direct in cloud shell it works fine…
    Any idea?

    1. Hi. Check if you provide the correct size of the VM, check the list of available sizes:
      az vm list-vm-resize-options –resource-group ResourceGroup_NAME –name VM_NAME –output table

      Maybe a typo, it’s hard to advise without seeing the code.

      ——-
      You can check for example:
      #dealocate
      az vm deallocate –resource-group ResourceGroup_NAME –name VM_NAME
      #resize
      az vm resize –resource-group ResourceGroup_NAME –name VM_NAME –size Standard_DS3_v2

Leave a Reply

Your email address will not be published. Required fields are marked *