この記事は更新から24ヶ月以上経過しているため、最新の情報を別途確認することを推奨いたします。
こんにちは!パーソルプロセス&テクノロジーの佐藤です。
コストの観点から定期的な仮想マシンの起動/停止を行うために、Azure Automationの自動起動/停止ソリューションを使用されているお客様は多いかと思います。
しかし、通常のソリューションではタスク実行スケジュールの設定を指定の日あるいは曜日で行うため、仮想マシンを使用しない祝日にも起動ジョブが走り、余計なコストがかかってしまう恐れがあります。
そこで今回は、国の定める祝日を反映させた仮想マシン自動起動/停止を構成するシンプルな方法をご紹介します。
※本記事で紹介するAutomation RunbookではPowershell Azモジュールを使用します。構成をお試しになる場合、新規にAutomationアカウントを作成してAzモジュールをインポートすることをお勧めします。
参考:
Azure AutomationのPowerShell RunbookでAzモジュールを使用することはできますか?(https://cloudsteady.jp/post/10046/)
概要
- 内閣府ホームページからダウンロードした祝日一覧をAutomation変数に格納します。
- 作成した変数を用いて祝日判定を行い、平日にのみ自動起動スクリプトを実行します。なお、自動停止スクリプトについては祝日判定を行わず毎日定時に実行する構成を取っていますが、自動起動スクリプトと同様の手順で祝日除外の構成をすることも可能です。
今回はAzure Automationの基礎の習熟も兼ね、祝日取得と祝日判定、自動起動のRunbookをPowershellで作成し、それらをグラフィカルRunbookで繋ぐ構成をとります。グラフィカルRunbookが面倒に感じたらひとつのPowershell Runbookで構成することも可能です。
前提条件
- AutomationアカウントにAzモジュールがインポートされ、Azコマンドが実行可能な状態であること
- Automation実行アカウントが利用可能な状態であること
Automation変数の作成
以下の3つの変数を作成します。
- Target_ResourceGroup(文字列):自動起動/停止の対象となる仮想マシンが存在するリソースグループ名を格納します。半角カンマ(,)で区切ることで複数指定も可能です。なお、複数のリソースグループを指定する場合、仮想マシン名はそれらのリソースグループ間で一意にする必要があります。
- ExcludeVMs(文字列):Target_ResourceGroupに入力するリソースグループ内で自動起動・停止の対象から除外する仮想マシン名を入力します。半角カンマで区切ることで複数指定が可能です。
- Japanese_Holidays(文字列):Webから取得する日本の祝日リストが格納されます。
Runbookの作成
以下5つのRunbookを作成します。
- AddHolidays:年に一度、内閣府HPから日本の祝日一覧(振替休日あり)を取得し、今年度の休日リストを作成して変数に格納します。
- IsitHoliday:月曜日から金曜日にかけて毎日決まった時間に休日判定を行います。
- StartVMs:決まった時間に対象の仮想マシンを起動します。
- StopVMs:決まった時間に対象の仮想マシンを停止します。
- HolidayAutomation:IsitHolidayとStartVMsをリンクさせます。
※HolidayAutomationはグラフィックRunbookで作成し、その他のRunbookはPowershell Runbookで作成します。
Powershell Runbookのソースコードは以下の通りです。
Runbook:AddHolidays
#内閣府HPから休日csvをインポート
$uri="https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv"
$importLoc=".\syukujitsu.csv"
Invoke-WebRequest -Uri $uri -OutFile $importLoc
$HolidaysCsv= Import-Csv $importLoc -Encoding Default -Header "date","name" |Where-Object -FilterScript{$_.date -ne "国民の祝日・休日月日"}
#年末年始休暇を追加
$thisyear =(get-date).Tostring("yyyy")
$aditionalHolidays =@("/1/2","/1/3","/12/29","/12/30","/12/31")
foreach($addition in $aditionalHolidays){
$addition= $thisyear+$addition
$HolidaysCsv += New-Object PsObject -Property @{ date = $addition ; name = '年末年始休暇' }
}
#来年の休日をソートして抜き出し
$thisyearsHolidays= $HolidaysCsv |Where-Object -FilterScript{$_.date -ge $thisyear+"/1/1"}|sort {[datetime]$_.date}
$thisyearsHolidays|export-csv -path $importLoc -Encoding Default -NoTypeInformation
#休日を文字列として結合
$content=""
$lastholiday=$thisyearsHolidays[-1]
$thisyearsHolidays|ForEach-Object{
$content+=[string]$_.date
if($_.date -ne $lastholiday.date){
$content+=","
}
}
#変数に追加
Set-AutomationVariable -Name 'Japanese_Holidays' -Value $content
Runbook:IsitHoliday
#変数の休日取得
$Holidays = (Get-AutomationVariable -Name 'Japanese_Holidays')-split(",")
#今日の日付
$Today= Get-Date -format d
#休日判定
$IsitHoliday= $Holidays.contains($Today)
Write-Output $IsitHoliday
Runbook:StartVMs
$servicePrincipalConnection=Get-AutomationConnection -Name "AzureRunAsConnection"
Add-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
#対象リソースグループ取得
$TargetResourceGroup= (Get-AutomationVariable -Name 'Target_ResourceGroup')-split(",")
#対象リソースグループ所属VMリスト取得
$VMList= @()
ForEach($rg in $TargetResourceGroup){
$VMList += (get-azVM -ResourceGroupName $rg).Name
}
#除外VMリスト取得
$ExcludeVMs =(Get-AutomationVariable -Name 'ExcludeVMs')-split(",")
#対象VM取得
$TargetVMs= Compare-Object -ReferenceObject $VMList -DifferenceObject $ExcludeVMs -PassThru
#対象VM起動
$TargetVMs|ForEach-Object{
Start-AzVM -ResourceGroupName (get-azVM -Name $_).ResourceGroupName -Name $_
}
Runbook:StopVMs
$servicePrincipalConnection=Get-AutomationConnection -Name "AzureRunAsConnection"
Add-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
#対象リソースグループ取得
$TargetResourceGroup= (Get-AutomationVariable -Name 'Target_ResourceGroup')-split(",")
#対象リソースグループ所属VMリスト取得
$VMList= @()
$TargetResourceGroup|ForEach-Object{
$VMList += (get-azVM -ResourceGroupName $_).Name
}
#除外VMリスト取得
$ExcludeVMs =(Get-AutomationVariable -Name 'ExcludeVMs')-split(",")
#対象VM取得
$TargetVMs= Compare-Object -ReferenceObject $VMList -DifferenceObject $ExcludeVMs -PassThru
#対象VM停止
$TargetVMs|ForEach-Object{
Stop-AzVM -ResourceGroupName (get-azVM -Name $_).ResourceGroupName -Name $_ -force
}
Runbook:HolidayAutomation
Powershell Runbookを作成したら、仮想マシン自動起動に休日条件を適用するため、下画像のようにIsitHolidayとStartVMsを条件付きシーケンスで繋いだグラフィックRunbookを作成します。
条件式にはRunbook:IsitHolidayで出力する変数を
$ActivityOutput['IsitHoliday']
としてBoolean型を返す式を入力することができます。
$ActivityOutput
はAzure Automationの規定の書式であり、オブジェクト型の変数を格納することが可能です。
(参考:Azure Automationでのグラフィカル作成)
スケジュール設定
AddHolidays・HolidayAutomation・StopVMsのRunbookに対してそれぞれのスケジュールを作成し、割り当てを行います。
なお、Azure AutomationではRunbookの実行時間が課金単位となります。
よってスケジュールを細かく設定するほど課金額は大きくなるので、任意でStopVMsのスケジュールを週単位に設定してください。
(本当はStartVMs・StopVMsのRunbookの中で次回スケジュールを設定できれば良いのですが、スケジュールの時刻変更を行うPowershellコマンドは未だ無いようです…)
AddHolidays
HolidayAutomation
StopVMs
割り当て
まとめ
長文おつきあいいただきありがとうございます。
csvファイルを取得して変数に格納し、それによって毎日の休日判定を行うといった愚直な構成のソリューションですが、
本記事が皆様の運用の改善ないしAzure Automation理解のお役に立てれば幸いです。