AVDでの「Allocation Failed」対策を考える!

今回は、AVDユーザーなら一度は遭遇した事がある「Allocation Failed」対策について考えたいと思います。クラウドの良さをぶち壊しにする”オンデマンドサービスの在庫切れ”は根深いものです。まずは、遭遇率を上げてしまう要因を見ていきましょう。裏を返せば、この構成を採用しなければいいのです!

※AVDと銘打っていますが、すべてのAzureVMが対象です。

Allocation Failed の発生率を上げる構成要因

・近接配置グループ:物理的に近いホストに限定される
・可用性ゾーン:指定したゾーンに限定される
・可用性セット:指定した更新/障害ドメインに限定される
・VM サイズ/SKU:需要の高い、SKUは影響を受けやすい ※特にGPUモデル
・Ultra Disk / Premium SSD v2:対応ホスト、対応SKUに限定される
・高速ネットワーク:SR-IOV対応ホストに限定される
・エフェメラル ディスク:ローカルSSDを搭載したホストに限定される

※複数に該当する場合は、さらに発生率が上がります。

下記のような対策が推奨されています。

①VMの起動を再実行する
②VMのサイズを変更する
③VMのシリーズを変更する
④リージョンを変更する

リージョンを変更するのは、事前に環境を作成しておく必要があるので、かなり難易度が高いと思います。残りの対策、①②③は作業が発生するため対応が容易ではありません。今回は、この作業を自動化するための仕組みを考案しました。

さっそく、構成を見てみましょう!

①Runbookのスケジュール機能により、指定時刻にスクリプトを実行する
②スクリプト内で指定されたリソースグループに対して、指定SKUでの起動を試みる

Runbookスクリプトには、事前に[サブスクリプションID][リソースグループ名][SKU]を記述しておく。スクリプトには、予め対象となるリソースグループ名とSKUを記述しておく。これらの記述が合致しない場合、スキップされます。複数のリソースグループと複数のSKUの組み合わせを同時に処理できます。スクリプトはリソースグループに対して実行するので、割り当て解除状態の全VMが起動対象となります。リソースグループ=ホストプールにしておくとよいでしょう。

【動作例】

ResourceGroupName:RG1,RG2
rgSkuMap:[RG1=SKU1,SKU2][RG2=SKU3,SKU4]
MaxRetryLoops:2

Loop1/2
①リソースグループ単位で、全DeallocatedVMの台数を把握
②RG1にて、1~100台でSKU1起動 → 60秒待機 → 状態確認
③RG1にて、101~200台でSKU1起動 → 60秒待機 → 状態確認(以降繰り返し)
④SKU1が全バッチ完了後、Deallocatedが残っていればSKU2で起動
⑤Deallocatedが残っていれば、Loop2/2にて②③④⑤を実行
⑥同様に、RG2にて②③④⑤を実施


それでは、やってみよう!!

先ずは、Automationアカウントを作成します。

外部からのトリガーは不要。Webhookなどの受口を設けない。
※プライベートアクセスにすると、プライベートエンドポイントの作成を求められる。

作成後ー[ID]ー[Azureロールの割り当て]を選択
※VMへのSKU変更、起動を実行するための権限を付与します。

スコープ:サブスクリプション
サブスクリプション:※対象のリソースグループが存在するサブスクリプションを選択
役割:Desktop Virtualization Virtual Machine Contributor
※権限を絞る場合は、カスタムロールの作成が必要です。

つづいて、Runbookの作成です。

[Runbook]ー[+作成]を選択

Runbook:新規作成
名前:表示名
Runbookの種類:PowerShell
ランタイム環境:PowerShell-7.2

こちらからダウンロードしたスクリプトをペースト。[保存]ー[公開]を選択

※環境に合わせて設定して下さい。
21行:サブスクリプションID
22行:対象となるリソースグループ名を列挙
23行:ループ回数を指定

27行:リソースグループ名と対応するSKU
28行:リソースグループが複数存在する場合は追記していく

[スケジュール][スケジュールの追加]を選択

[スケジュール]を選択

名前:表示名
開始時間:スケジュールを実行する時間
間隔:[2]週間に1回

[パラメータと実行設定]ー[OK]を選択

作成できました。


それでは、確認してみましょう!

既存環境では、2つのホストプールがあり、それぞれ、2台のVMがあります。
全てのVMは[割り当て解除]状態です。
クォーター制限のため、NV6ads_A10_v5は、1台しか起動できません。
D2as_v5には、台数制限はありません。

[ホストプール]
AVD-AllocationFailure [Allocation-0,Allocation-1]
AVD-ADmulti [AVD-ADmulti-2,AVD-ADmulti-3]

[スクリプト]
ResourceGroupName = “AVD-AllocationFailure,AVD-ADmulti”
rgSkuMap =
“AVD-AllocationFailure” = “Standard_NV6ads_A10_v5,Standard_D2as_v5”
“AVD-ADmulti” = “Standard_D2as_v5,Standard_NV6ads_A10_v5”

【実行結果】

1.[Allocation-0][Allocation-1]は、[NV6ads_A10_v5]で起動を試みる
2.[NV6ads_A10_v5]は1台しか起動できないので、[Allocation-0]が起動し、[Allocation-1]は起動に失敗する。
3.次に指定されたSKU[D2as_v5]で[Allocation-1]の起動を試みる
4.[AVD-ADmulti-2][AVD-ADmulti-3]は、[D2as_v5]で起動を試みる

無事に、指定したSKUで全台起動できました!


これまでの紆余曲折

本当は、下記のような完全自動化を夢みていました。。

①Allocation Failedが発生した際に、Activity LogからLoganalyticsにログが出力される
②アラートルール条件により[ログ+リソースグループ名]を元にアクションルールを実行
③アクションルールにより、Webhookを利用しRunbookを呼び出す
④Runbookのスクリプトは、指定したリソースグループに対して実行
⑤スクリプト内で指定されたSKUの起動を順番に試みる

※リソースグループ単位でVMの起動を試みます。
※(同時に起動してもよい)リソースグループの数だけ、②③④を作成する必要があります。
②はリソースグループの数だけ必要
④(同時に起動してもよい)リソースグループの数だけ必要
[補足]単純にAllocation Failedログの発生だけで、スクリプトを実行すると、対象のVMが全て起動してしまいます。この問題を解決するために、アラートルール条件でリソースグループを特定する事で、アクショングループで実行するスクリプトを指定しています。スクリプトには、複数のリソースグループを登録する事が可能です。

[改良版]
アラートルールは、サブスクリプションIDとリソースグループ名をWebhook経由でRunbookにわたす。Runbookスクリプトは、サブスクリプションIDとリソースグループ名をスクリプトに挿入。スクリプトには、予め対象となるリソースグループ名とSKUを記述しておく。Webhookからもらうリソースグループ名と合致した場合、指定のSKUで起動を試みる。リソースグループ名が合致しない場合、スクリプトは実行されません。スクリプトはリソースグループに対して実行するので、全VMが起動対象となります。リソースグループ=ホストプールにしておくとよいでしょう。

襲い掛かってきた問題点

①1台ずつ起動していた問題
②同時起動のスロットリング問題
③RG単位で[アラートルール→アクショングループ→Runbook]の作成が必要になる問題
④ActivityLogからWebhook経由で[サブスクID][リソースグループ名]を取得できるのか問題
⑤スクリプト実行時のAllocationFailedを再度ActivityLogで拾い、多重実行する問題
⑥挫折してしまう問題w