Azureの「App Serviceプラン」になるべく多くのApp Serviceを詰め込んで料金を節約しようとしたことはないだろうか? もしあるなら、「高密度ホスティング」が役に立つかもしれない。その設定方法や注意点を紹介する。
対象:Azure App Serviceプラン、App Service
Azureの「App Service」の料金を節約する方法の一つとして、「App Serviceプラン」になるべく多くのApp Serviceを詰め込むというものがある。App Serviceの料金は基本的にApp Serviceプランの性能とそのインスタンス数で決まるため、より多くのApp Serviceを詰め込むほど、App Service一つ当たりの料金を下げることができるからだ(もちろん詰め込み過ぎれば性能が下がってしまうが)。
その点で注目したいのがApp Serviceプランの「高密度ホスティング」という機能だ。スケーリングを工夫することで、より多くのApp ServiceをApp Serviceプランに乗せることができるという。
本Tech TIPSでは、App Service/プランを実際にデプロイしたことがある運用担当を対象として、この機能を実際に試しながら、その設定方法や注意点などを紹介する。
「高密度ホスティング(high-density hosting)」とは、App Serviceごとにスケーリングの上限数を変える(アプリごとのスケーリングを有効にする)ことで、通常より多くのApp ServiceをApp Serviceプランに詰め込むことを指す。
デフォルトの設定の場合、App Serviceのスケーリング数はApp Serviceプランのインスタンス数と一致する。App Serviceプランのインスタンス数を増やすと、そこで実行中の全App Serviceも、その分だけ下図のように増える。
しかし、全てのApp Serviceで等しくスケールアウトが必要とは限らない。例えば、幾つかのApp Serviceでは負荷もアクセス数も大きく変動しないのでスケールアウトは不要(常に1つでよい)な一方で、他のApp Serviceはよくアクセスされるので2つ以上にスケールアウトさせたい、といった状況が考えられる。
そこで、App Serviceごとにスケールアウトの上限数を別々に設定できるようにすると、インスタンス数を増やしてもスケールアウトしないApp Serviceがある分、インスタンスに余裕が生じる。下図のように同じインスタンス数でも、より多くのApp Serviceを詰め込めるようになる。
App Serviceごとにスケーリング上限数を可変にするには、App ServiceプランとApp Serviceの両方で設定変更が必要になる。ただ、どちらもAzureポータルからは設定できない。ここではARM(Azure Resource Manager)テンプレートによる設定方法を説明する。
まずApp Serviceプランについては、以下のリストのリソース「appServicePlan」にある「properties.perSiteScaling」に「true」を指定する(デフォルトはfalse)。
// ファイル: asp.azuredeploy.bicep
////////// App Serviceごとにスケーリング上限数を //////////
////////// 変更できるApp Serviceプランを作成する //////////
param appServicePlanName string // App Serviceプラン名
param location string = resourceGroup().location // 作成先のリージョン
@maxValue(30)
param baseCapacity int = 2 // デプロイ直後のインスタンス数
param skuName string = 'P1v3' // SKU名称。すぐ下の「skus」のキー名から選択
var skus = {
// SKUの定義。Premium V3のみ
P0v3: {
name: 'P0v3'
tier: 'PremiumV3'
capacity: baseCapacity
}
P1v3: {
name: 'P1v3'
tier: 'PremiumV3'
capacity: baseCapacity
}
P1mv3: {
name: 'P1mv3'
tier: 'PremiumV3'
capacity: baseCapacity
}
}
// リソース生成: App Serviceプラン
resource appServicePlan 'Microsoft.Web/serverfarms@2024-04-01' = {
name: appServicePlanName
location: location
sku: skus[skuName]
kind: 'linux' // OSはLinuxとする
properties: {
perSiteScaling: true // App Serviceごとにスケーリング上限数を変える
reserved: true // Linuxを使用する場合はtrue(falseだとエラーで失敗する)
}
}
次にApp Serviceを新規作成する際、以下のリストのパラメーター「numberOfWorkers」にスケーリング上限数を指定する。例えば、スケールアウトが不要なら「1」、4つまでスケールアウトさせたいなら「4」というように指定すること。
// ファイル: app.azuredeploy.bicep
////////// App Serviceのデプロイ時にスケーリング上限数を指定する //////////
param location string = resourceGroup().location
param siteName string // App Serviceの名前
param numberOfWorkers int = 1 // App Serviceのスケーリング上限数
// リソース生成: App Serviceのサイト本体
resource webApp 'Microsoft.Web/sites@2024-04-01' = {
name: siteName
location: location
properties: { /* ……<省略>…… */ }
}
// リソース生成: App ServiceのWeb設定
resource webAppConfig 'Microsoft.Web/sites/config@2024-04-01' = {
parent: webApp
name: 'web' // 必ず「web」を指定
properties: {
// ……<省略>……
numberOfWorkers: numberOfWorkers
// ……<省略>……
}
}
上記の設定は、「アプリごとのスケーリング」を有効化したApp Serviceプラン上の全App Serviceに対して個別に実行する必要がある。
既存のApp Serviceプラン/App Serviceでも、デプロイし直すことなくスケーリング上限数を可変にできる。ここではAzure PowerShellによる設定方法を説明する。
まずApp Serviceプランについては、「Set-AzAppServicePlan」コマンドレットに「-PerSiteScaling $true」というオプションを指定して実行する。
Set-AzAppServicePlan -ResourceGroupName <App Serviceプランのリソースグループ名> -Name <App Serviceプランのリソース名> -PerSiteScaling $true
設定できたかどうかを確認するには、「Get-AzAppServicePlan」コマンドレットを利用する。
(Get-AzAppServicePlan -ResourceGroupName <App Serviceプランのリソースグループ名> -Name <App Serviceプランのリソース名>).PerSiteScaling
次にApp Serviceについては、「Get-AzWebApp」「Set-AzWebApp」コマンドレットを使って、「SiteConfig.NumberOfWorkers」にスケーリング上限数を指定する。
$app = Get-AzWebApp -ResourceGroupName <App Serviceのリソースグループ名> -Name <App Serviceのリソース名>
$app.SiteConfig.NumberOfWorkers = <スケーリング上限数>
Set-AzWebApp $app
また、スケーリング上限数を確認するには以下のコマンドラインを実行する。
(Get-AzWebApp -ResourceGroupName <App Serviceのリソースグループ名> -Name <App Serviceのリソース名>).SiteConfig.NumberOfWorkers
App Serviceごとのスケーリング上限数を可変にすると、当然ながらApp Serviceプランのインスタンス数とApp Serviceのスケーリング数が一致しなくなる。例えばインスタンス数が2つ以上でも、スケーリング上限数を「1」に設定したApp Serviceは、スケーリング数は「1」になる。また、スケーリング上限数を「3」にしたApp Serviceでも、インスタンス数が2つの場合、スケーリング数は「2」のはずだ。
こうなると、各App Serviceが「現在」どれくらいスケーリングされているか、その数を確認したくなる。
ところが、筆者が調べた限りでは、この「現在」のスケーリング数を簡単に確認する方法を見つけられなかった。唯一、App Serviceが出力するログ「HTTP logs」(いわゆるアクセスログ)に含まれる「ComputerName」カラムに現れる各インスタンスのコンピュータ名の個数でスケーリング数を推定できそうだ。
Azureのログ分析サービス「Log Analytics」がApp Serviceに対してセットアップ済みの場合、以下のクエリを実行すると、クライアントからのリクエストを受け付けたインスタンスのコンピュータ名が一覧表示される。直近のアクセス数(以下のリストや画面にある「RequestCount」)がおおよそ均等なら、コンピュータ名の数がApp Serviceの「現在」のスケーリング数と推定できる。
// インスタンスごとにアクセス数を集計して、スケーリング数を推定する
AppServiceHTTPLogs
| where CsHost !endswith ".scm.azurewebsites.net" // 高度なサイトは除外
| summarize RequestCount = count() by ComputerName
| order by ComputerName
ここまで説明した方法で実際に「アプリごとのスケーリング」を有効にしたApp Serviceプランとスケーリング上限数が異なる複数のApp Serviceをデプロイし、インスタンス数を増減させながら、各App Serviceがどのように配置されるのか試してみた。
その結果を以下に図示する。「n=1」と記しているアイコンは、「スケーリング上限数が1のApp Service」を表している。
図「4.n=1のアプリを複数追加」のように、上限数が「1」のApp Serviceを複数追加したところ、各インスタンスへ均等には配分されず、インスタンスごとに密度の偏りが生じた。これはMicrosoftが公開しているドキュメントに「均等な配分は保証されていない」と記されているとおりの挙動といえる。
一方、上限数が2つ以上のApp Serviceについては、インスタンス数が足りていれば、各インスタンスへ均等にスケールアウトされた。これもMicrosoftのドキュメントの通りである。
また、図「6.インスタンス3のn=1のApp Serviceを削除して再作成」の挙動からすると、密度の偏りが生じたら、いったんApp Serviceを削除して再作成すると、均等な配置に近づけられそうだ。
App Serviceプランで「アプリごとのスケーリング」を有効にした場合、スケールアウトの方法に制約が生じる。
具体的には、AzureポータルでApp Serviceプランのページを開き、[設定]−[スケールアウト(App Serviceのプラン)]を選択すると表示されるスケールアウトの設定ページで、「スケールアウト方法」欄の[自動](トラフィックに基づくプラットフォームマネージドスケールアップとスケールダウン)というラジオボタンがグレーアウトして選択できない。
このスケールアウト方法をどうしても使いたい場合、執筆時点では「アプリごとのスケーリング」を無効にするしかないようだ。
■関連リンク
Copyright© Digital Advantage Corp. All Rights Reserved.