仿照前一篇文章對 Automation 上的 PowerShell 範本做一點調整,讓你可以按照所想要的時間,自動 Scale 調整 VM 的等級,做最經濟的考量
在前一篇文章中「定時自動將 Azure SQL Database 給 Scale Up 或 Scale Down」,主要是介紹使用別人已經寫好的腳本來做使用,但如果有些時候,您想要的並沒有辦法在 runbooks gallery 裡面找到合適的腳本,其實您也可以跟我用類似的方法,先找一個類似的功能腳本,再來修改成為您所想要的功能。
這個緣由是我本來要找一個可以自動定時調整 VM 規模的腳本,因為我們放在 Azure 的 VM 在工作日的時候,某些時候的尖峰需要比較多的核心去運算,但晚上或者是周末,就不需要那麼高的資源。因此如果按照白天所需要的規格去選擇 VM 的規模,那所需要的成本就會非常高。很可惜的我在 runbooks 上並沒有找到合適的,只有找到前一篇文章中所介紹的腳本,因此我就參考那個腳本去做一些小幅的調整,就變成一個符合我所使用的 Automotion 上的 Runbook 了。
腳本內容如下:
<#
.SYNOPSIS
Vertically scale an Azure VM up or down according to a
schedule using Azure Automation.
.DESCRIPTION
This Azure Automation runbook enables vertically scaling of
an Azure VM according to a schedule.
.PARAMETER resourceGroupName
Name of the resource group to which the VM is assigned.
.PARAMETER azureRunAsConnectionName
Azure Automation Run As account name. Needs to be able to access
the $serverName.
.PARAMETER serverName
Azure VM name.
.PARAMETER scalingSchedule
VM Scaling Schedule. It is possible to enter multiple
comma separated schedules: [{},{}]
Weekdays start at 0 (sunday) and end at 6 (saturday).
If the script is executed outside the scaling schedule time slots
that you defined, the defaut edition/tier (see below) will be
configured.
.PARAMETER scalingScheduleTimeZone
Time Zone of time slots in $scalingSchedule.
Available time zones: [System.TimeZoneInfo]::GetSystemTimeZones().
.PARAMETER defaultSize
Azure VM that wil be used outside the slots
specified in the scalingSchedule paramater value.
.EXAMPLE
-resourceGroupName myResourceGroup
-azureRunAsConnectionName AzureRunAsConnection
-serverName myserver
-scalingSchedule [{WeekDays:[1], StartTime:"06:59:59", StopTime:"17:59:59", Size: "Standard_D3_v2"}, {WeekDays:[2,3,4,5], StartTime:"06:59:59", StopTime:"17:59:59", Size: "Standard_D2_v2"}]
-scalingScheduleTimeZone Taipei Standard Time
-defaultSize Standard_D1_v2
.NOTES
Author: James Fu
Last Update: Apr 2018
#>
param(
[parameter(Mandatory=$true)]
[string] $resourceGroupName,
[parameter(Mandatory=$false)]
[string] $azureRunAsConnectionName = "AzureRunAsConnection",
[parameter(Mandatory=$true)]
[string] $serverName,
[parameter(Mandatory=$true)]
[string] $scalingSchedule,
[parameter(Mandatory=$false)]
[string] $scalingScheduleTimeZone = "Taipei Standard Time",
[parameter(Mandatory=$false)]
[string] $defaultSize = "Standard_D1_v2"
)
filter timestamp {"[$(Get-Date -Format G)]: $_"}
Write-Output "Script started." | timestamp
$VerbosePreference = "Continue"
$ErrorActionPreference = "Stop"
#Authenticate with Azure Automation Run As account (service principal)
$runAsConnectionProfile = Get-AutomationConnection `
-Name $azureRunAsConnectionName
Add-AzureRmAccount -ServicePrincipal `
-TenantId $runAsConnectionProfile.TenantId `
-ApplicationId $runAsConnectionProfile.ApplicationId `
-CertificateThumbprint ` $runAsConnectionProfile.CertificateThumbprint | Out-Null
Write-Output "Authenticated with Automation Run As Account." | timestamp
#Get current date/time and convert to $scalingScheduleTimeZone
$stateConfig = $scalingSchedule | ConvertFrom-Json
$startTime = Get-Date
Write-Output "Azure Automation local time: $startTime." | timestamp
$toTimeZone = [System.TimeZoneInfo]::FindSystemTimeZoneById($scalingScheduleTimeZone)
Write-Output "Time zone to convert to: $toTimeZone." | timestamp
$newTime = [System.TimeZoneInfo]::ConvertTime($startTime, $toTimeZone)
Write-Output "Converted time: $newTime." | timestamp
$startTime = $newTime
#Get current day of week, based on converted start time
$currentDayOfWeek = [Int]($startTime).DayOfWeek
Write-Output "Current day of week: $currentDayOfWeek." | timestamp
# Get the scaling schedule for the current day of week
$dayObjects = $stateConfig | Where-Object {$_.WeekDays -contains $currentDayOfWeek } `
|Select-Object Size, `
@{Name="StartTime"; Expression = {[datetime]::ParseExact($_.StartTime,"HH:mm:ss", [System.Globalization.CultureInfo]::InvariantCulture)}}, `
@{Name="StopTime"; Expression = {[datetime]::ParseExact($_.StopTime,"HH:mm:ss", [System.Globalization.CultureInfo]::InvariantCulture)}}
# Get the VM object
$vm = Get-AzureRmVm -ResourceGroupName $resourceGroupName -Name $serverName
Write-Output "VM name: $($vm.Name)" | timestamp
Write-Output "Current VM size: $($vm.HardwareProfile.vmSize)" | timestamp
if($dayObjects -ne $null) { # Scaling schedule found for this day
# Get the scaling schedule for the current time. If there is more than one available, pick the first
$matchingObject = $dayObjects | Where-Object { ($startTime -ge $_.StartTime) -and ($startTime -lt $_.StopTime) } | Select-Object -First 1
if($matchingObject -ne $null)
{
Write-Output "Scaling schedule found. Check if current size is matching..." | timestamp
if($vm.HardwareProfile.vmSize -ne $matchingObject.Size)
{
Write-Output "VM is not in the size of the scaling schedule. Changing!" | timestamp
$vm.HardwareProfile.VmSize = $matchingObject.Size
Update-AzureRmVm -VM $vm -ResourceGroupName $ResourceGroupName | out-null
Write-Output "Change to size as specified in scaling schedule initiated..." | timestamp
$vm = Get-AzureRmVm -ResourceGroupName $resourceGroupName -Name $serverName
Write-Output "Current VM size: $($vm.HardwareProfile.VmSize)" | timestamp
}
else
{
Write-Output "Current VM size matches the scaling schedule already. Exiting..." | timestamp
}
}
else { # Scaling schedule not found for current time
Write-Output "No matching scaling schedule time slot for this time found. Check if current edition/tier matches the default..." | timestamp
if($vm.HardwareProfile.vmSize -ne $defaultSize)
{
Write-Output "VM is not in the default size. Changing!" | timestamp
$vm.HardwareProfile.VmSize = $defaultSize
Update-AzureRmVm -VM $vm -ResourceGroupName $ResourceGroupName | out-null
Write-Output "Change to default size initiated." | timestamp
$vm = Get-AzureRmVm -ResourceGroupName $resourceGroupName -Name $serverName
Write-Output "Current VM size: $($vm.HardwareProfile.VmSize)" | timestamp
}
else
{
Write-Output "Current VM size matches the default already. Exiting..." | timestamp
}
}
}
else # Scaling schedule not found for this day
{
Write-Output "No matching scaling schedule for this day found. Check if current size matches the default..." | timestamp
if($vm.HardwareProfile.vmSize -ne $defaultSize)
{
Write-Output "VM is not in the default size. Changing!" | timestamp
$vm.HardwareProfile.VmSize = $defaultSize
Update-AzureRmVm -VM $vm -ResourceGroupName $ResourceGroupName | out-null
Write-Output "Change to default size initiated." | timestamp
$vm = Get-AzureRmVm -ResourceGroupName $resourceGroupName -Name $serverName
Write-Output "Current VM size: $($vm.HardwareProfile.VmSize)" | timestamp
}
else
{
Write-Output "Current VM size matches the default already. Exiting..." | timestamp
}
}
Write-Output "Script finished." | timestamp
基本上這個腳本需要六個參數
- 資源群組名稱 : 主要是記錄你要改哪個資源群組下的資料庫
- 連線資訊:如果是跟 Azure Automation 在同一個訂閱帳號下的資料庫要被管理,那麼就不用設定
- Azure VM 名稱:給 VM 的名稱就好,不用填寫全域名稱
- 時間區間:設定每週的哪個時間需要將 VM 設定為哪個等級
- 時區:用來指定上述時間是哪個時區,預設為 Taipei Standard Time
- 預設規格:在非第 4 項時間範圍內的時候,使用哪個規模大小
VM 的規模大小,可以用以下幾個參數,設定的時候要注意一下,也要注意所在的區域和訂閱是能夠支援的
Basic_A0
Basic_A1
Basic_A2
Basic_A3
Basic_A4
Standard_A0
Standard_A1
Standard_A2
Standard_A3
Standard_A4
Standard_A5
Standard_A6
Standard_A7
Standard_A8
Standard_A9
Standard_A10
Standard_A11
Standard_A1_v2
Standard_A2_v2
Standard_A4_v2
Standard_A8_v2
Standard_A2m_v2
Standard_A4m_v2
Standard_A8m_v2
Standard_D1_v2
Standard_D2_v2
Standard_D3_v2
Standard_D4_v2
Standard_D5_v2
Standard_DS1_v2
Standard_DS2_v2
Standard_DS3_v2
Standard_DS4_v2
Standard_DS5_v2
Standard_D11_v2
Standard_D12_v2
Standard_D13_v2
Standard_D14_v2
Standard_D15_v2
Standard_DS11_v2
Standard_DS12_v2
Standard_DS13_v2
Standard_DS14_v2
Standard_DS15_v2
Standard_DS1
Standard_DS2
Standard_DS3
Standard_DS4
Standard_DS11
Standard_DS12
Standard_DS13
Standard_DS14
Standard_D1
Standard_D2
Standard_D3
Standard_D4
Standard_D11
Standard_D12
Standard_D13
Standard_D14
Standard_G1
Standard_G2
Standard_G3
Standard_G4
Standard_G5
Standard_GS1
Standard_GS2
Standard_GS3
Standard_GS4
Standard_GS5
Standard_D2_v3
Standard_D4_v3
Standard_D8_v3
Standard_D16_v3
Standard_D32_v3
Standard_D64_v3
Standard_D2s_v3
Standard_D4s_v3
Standard_D8s_v3
Standard_D16s_v3
Standard_D32s_v3
Standard_D64s_v3
Standard_E2_v3
Standard_E4_v3
Standard_E8_v3
Standard_E16_v3
Standard_E32_v3
Standard_E64_v3
Standard_E2s_v3
Standard_E4s_v3
Standard_E8s_v3
Standard_E16s_v3
Standard_E32s_v3
Standard_E64s_v3
Standard_F1
Standard_F2
Standard_F4
Standard_F8
Standard_F16
Standard_F1s
Standard_F2s
Standard_F4s
Standard_F8s
Standard_F16s
Standard_F2s_v2
Standard_F4s_v2
Standard_F8s_v2
Standard_F16s_v2
Standard_F32s_v2
Standard_F64s_v2
Standard_F72s_v2
Standard_L4s
Standard_L8s
Standard_L16s
Standard_L32s
Standard_NV6
Standard_NV12
Standard_NV24
Standard_NC6
Standard_NC12
Standard_NC24
Standard_H8
Standard_H16
Standard_H8m
Standard_H16m