+ All Categories
Home > Documents > Automated shutdown

Automated shutdown

Date post: 13-Apr-2017
Category:
Upload: mario-berend
View: 33 times
Download: 1 times
Share this document with a friend
11
Controlling costs using automated shutdown Mario Berend [email protected]
Transcript
Page 1: Automated shutdown

Controlling costs using automated shutdown

Mario Berend [email protected]

Page 2: Automated shutdown

Azure provides us with some great features when it comes to the flexibility of our virtual datacenter.

For example: let’s say you are managing the public website for a popular clothing brand, and they are

about to introduce their summer collection with a big on- and offline marketing campaign. This

marketing campaign will, obviously, cause a huge increase in web traffic. This scenario will be a

challenge in an on-premise environment. You will probably have to set up one or more extra VM’s to

deal with the extra traffic. Things will get more complicated if your Hyper-V server is running out of

resources… Azure fans will immediately say “autoscaling”. And yes, autoscaling is the answer for

easily adding some temporary muscle to your environment.

So, we are covered for dealing with peak performance moments. But I’ve noticed that the other side

of the spectrum is usually completely forgotten, the moments that we are not using our environment

at all. Let’s say you have a private Azure subscription with some VM’s in a VNet, using it on a regular

basis. I bet that these VM’s will remain powered on during those moments you don’t use them, for

example overnight and during the weekends… Is it not just a waste of money to have these machines

run for no reason, eating our credit cards?

Fortunately, this is where Azure Runbooks and the Scheduler can be of help. Let’s say we want to

have our VM’s powered on only from Monday till Friday, from 8AM till 8PM. First, we have to create

an automation account. We can do this through the portal, I am placing my automation account in

the resource group where my VM’s are located.

This is also possible through Powershell, but it will require quite a lot of scripting to have the RunAs

account created properly. We will skip that for now.

Page 3: Automated shutdown

So now that we have our automation account, we can proceed with creating a new runbook. We can

do this through the portal by clicking on our automation account, click Runbooks, and Add a runbook.

Now we will create a new runbook either by using the portal:

Or with Powershell:

New-AzureRmAutomationRunbook -AutomationAccountName AutomationAccount ` -Name TurnOffVMs -ResourceGroupName Avanade_Resourcegroup_Prod -Type PowerShell ` -Description "This runbook contains a script to shut down VM's."

Which will produce the following output:

Page 4: Automated shutdown

Now that we have our runbook, it is time to add some scripting. Open the runbook and click Edit. We

can now work on our script:

Let’s have a look at what this script does. It will first set up a connection with our Automation

Account which is required to fire the commands we want to execute within our runbook. Once the

authentication is successful, we can perform our actual actions. Let’s save this script, and go to the

Test pane. Now press the Start button and wait for the script to complete. It will show an output of

all VM’s and their properties which are located in our tenant.

We can also use Powershell to create a runbook from an existing .ps1 file. This is similar to the earlier

creation of our runbook, but this time we are creating the runbook and injecting our script in one

step.

Import-AzureRmAutomationRunbook -ResourceGroupName AVANADE_RESOURCEGROUP_PROD ` -AutomationAccountName AutomationAccount -Name TurnOffVms ` -Path ".\TurnOffVMs_pre.ps1" -Type PowerShell ` -Description "This runbook contains a script to shut down VM's."

Page 5: Automated shutdown

You will have to delete the previously created runbook if you want to try the above example. You can

delete a runbook with the following command:

Remove-AzureRmAutomationRunbook -Name TurnOffVMs -ResourceGroupName AVANADE_RESOURCEGROUP_PROD -AutomationAccountName AutomationAccount

Now that we have a runbook with a script, we need to schedule execution. If you are using the portal

you might have noticed that the Schedule button is greyed out. This is because we haven’t published

our script yet. Press the Publish button in the portal, or run the following Powershell command:

Publish-AzureRmAutomationRunbook -AutomationAccountName AutomationAccount ` -Name TurnOffVMs -ResourceGroupName AVANADE_RESOURCEGROUP_PROD

This will produce the following output:

You will see that the State attribute is now set to Published, so we can now proceed with the

creation of our schedule. Click on Schedule, Link a schedule to your runbook, and then on Create a

new schedule.

The Powershell command associated with this action is as follow:

New-AzureRmAutomationSchedule –AutomationAccountName AutomationAccount ` –Name TurnVMsOffDaily –StartTime "12/1/2017 16:30:00" ` –DayInterval 1 -ResourceGroupName AVANADE_RESOURCEGROUP_PROD ` -Description "This schedule will turn off all VM's in our tenant on a daily basis."

Page 6: Automated shutdown

You will see the following output:

Now link the schedule to the runbook:

Register-AzurermAutomationScheduledRunbook –AutomationAccountName ` AutomationAccount –Name TurnOffVMs –ScheduleName TurnVMsOffDaily ` -ResourceGroupName AVANADE_RESOURCEGROUP_PROD

When creating a schedule, the start time of the schedule must be at least 5 minutes after the time

you create the schedule. So check your current time, add a few minutes to it, and set that as the

Starttime of your schedule. Grab a coffee and wait for the schedule to kick in.

Open the runbook, and open the Jobs tab. You will see the job status listed as Completed. Open the

job to have a closer look.

No errors, no warnings, this looks good. You can check the Output button to see the result of the

script that was fired by our schedule.

So now we have our automation account, a runbook with some sample code, and a working

scheduled job attached to it. Time to customize the runbook with some code to implement the

automated shutdown. Open the runbook and press edit. Our current code is currently capturing all

VM’s in our tenant and stores them in a variable, and then outputs this variable. We will remove the

$VMs output and create a foreach-loop to iterate through every VM in the $VMs variable. We will

shut down each VM during this loop to perform our shutdown using the following command:

Stop-AzureRmVM -Name $vm.Name ` -ResourceGroupName $vm.ResourceGroupName ` -force

Page 7: Automated shutdown

Save and publish your updated script version. This will overwrite our previous version. Now set the

schedule to a new time, and wait for the script to be fired. It will take a while to run. Once

completed, the output will be similar to this:

Cool! All VM’s in our tenant are now in a stopped state, which will save a noticeable amount of

credits each month. Let’s say you set you create a runbook and schedule to shut down all of your

VM’s each evening at 11PM, and start them again at 7AM. This means you cut on 1/3 of the costs of

the running VM’s! Keep in mind though, any dynamically assigned IP address (public or private) will

be released when this script is performed.

Now that we created a script to shut down our VM’s every evening, we also need a script to start the

VM’s each morning. Create a new runbook, add a recurring schedule that fires every morning, and

copy the script from our Shutdown script. We only have to make some slight adaptions to let it start

our VM’s instead of stop:

Page 8: Automated shutdown

There we go, we are shutting down and powering on our VM’s without having to do anything for it.

This scenario however, is not giving us much control over which VM’s are shut down. You might want

to shut down only specific VM’s. Good news, we can achieve that with a little customization.

I once faced the scenario that the development team of the project I was assigned to had a VNet

running in Azure, divided into two subnets: one for development/testing purposes, and one for

production. The development machines were only necessary during production hours, while the

production server was required 24/7. So basically what was required in this scenario was the

following:

- Determine which subnet that contains the VMs that need to be shutdown

- Get all interfaces connected to the VNet. Each VM had one NIC connected to a subnet.

- Check which subnets these NICs are connected to

- If the subnet of the NIC matches the subnet that needs to be shutdown, the VMname needs

to be retrieved and eventually the VM needs to shutdown.

This brought me to the following script:

Page 9: Automated shutdown

Let’s test it out. Open the Test Pane, start it, and wait for it to complete. Note: at the time of writing,

the modules containing the cmdlets used in this script aren’t natively imported into Azure's

automation accounts. You will have to manually import AzureRM.Network and AzureRM.profile. If

you have any issues firing the script above, please read my article “Powershell modules in runbooks”.

Now check the status of your VMs:

Voila! Both of the VMs in the DevAndTest subnet are stopped, while the VM in Production is still

running. Exactly what we wanted!

That’s it for now! With this article I hope to give you a view on the power of Azure’s runbooks and

how you can use them to control the costs of your virtual data center, or how you can easily save

your Azure credits in your personal tenant.

Happy scripting!

Mario Berend [email protected] | https://www.linkedin.com/in/mario-berend-7b214228

Page 10: Automated shutdown

Used scripts:

Creation of a new runbook:

New-AzureRmAutomationRunbook -AutomationAccountName AutomationAccount ` -Name TurnOffVMs -ResourceGroupName Avanade_Resourcegroup_Prod -Type PowerShell ` -Description "This runbook contains a script to shut down VM's."

Connecting with the automation account and retrieval of VM’s:

$connectionName = "AzureRunAsConnection" try { $Conn=Get-AutomationConnection -Name $ConnectionName "Logging in to Azure..." Add-AzureRmAccount ` -ServicePrincipal ` -TenantId $Conn.TenantId ` -ApplicationId $Conn.ApplicationId ` -CertificateThumbprint $Conn.CertificateThumbprint } catch { Write-host "Error while creating connection!" } $VMs = get-azurermvm $VMs

Connecting with the automation account and stopping the VM’s:

$connectionName = "AzureRunAsConnection" try { $Conn=Get-AutomationConnection -Name $ConnectionName "Logging in to Azure..." Add-AzureRmAccount ` -ServicePrincipal ` -TenantId $Conn.TenantId ` -ApplicationId $Conn.ApplicationId ` -CertificateThumbprint $Conn.CertificateThumbprint } catch { Write-host "Error while creating connection!" } foreach($vm in $vms) { Stop-AzureRmVM -Name $vm.Name ` -ResourceGroupName $vm.ResourceGroupName ` -force }

Page 11: Automated shutdown

Connecting with the automation account and starting the VM’s:

$connectionName = "AzureRunAsConnection" try { $Conn=Get-AutomationConnection -Name $ConnectionName "Logging in to Azure..." Add-AzureRmAccount ` -ServicePrincipal ` -TenantId $Conn.TenantId ` -ApplicationId $Conn.ApplicationId ` -CertificateThumbprint $Conn.CertificateThumbprint } catch { Write-host "Error while creating connection!" } foreach($vm in $vms) { Start-AzureRmVM -Name $vm.Name ` -ResourceGroupName $vm.ResourceGroupName ` }

Connecting with the automation account and stopping the VM’s in a specified VNet:

$connectionName = "AzureRunAsConnection" try { $Conn=Get-AutomationConnection -Name $ConnectionName "Logging in to Azure..." Add-AzureRmAccount ` -ServicePrincipal ` -TenantId $Conn.TenantId ` -ApplicationId $Conn.ApplicationId ` -CertificateThumbprint $Conn.CertificateThumbprint } catch { Write-host "Error while creating connection!" } $SubnetIDToShutDown = "*DevAndTest*" $interfaces = Get-AzureRmNetworkInterface | select name, IpConfigurations, VirtualMachine, ResourceGroupName foreach($interface in $interfaces) { $ResourceGroupName = $interface.ResourceGroupName $SubnetID = $interface.IpConfigurations.Subnet.id if($SubnetID -like $SubnetIDToShutDown) { $VMName = ($interface.VirtualMachine.Id.Split("/"))[-1] stop-AzureRMVM -Name $VMName -ResourceGroupName $ResourceGroupName -force } }


Recommended