[Advent Calendar 2017 Day15] Azure Web Apps お役立ち PowerShell スクリプトいろいろ

 

こちらの記事は、Qiita に掲載した Microsoft Azure Tech Advent Calendar 2017 の企画に基づき、執筆した内容となります。
カレンダーに掲載された記事の一覧は、こちらよりご確認ください。

 

こんにちは。Azure サポートの板垣です。

今回は、Azure Web Apps の管理 API 呼び出しを行う、PowerShell スクリプトのサンプルをご紹介します。
情報採取やトラブルシューティングのために実行する他、Azure Functions や Web Jobs でスクリプトを実行することで、自動運用を実現するようなこともできます。是非ともご参考ください。

# Azure PowerShell のインストール方法につきましては、Azure PowerShell 最新版のインストール手順 もご参考ください。

 


API の認証方法

PowerShell を使って Azure Web Apps を管理する方法として、Azure PowerShell を使う方法と、Azure Web Apps の管理サービスである Kudu サイト (https://.scm.azurewebsites.net) で提供される API を使用する方法があります。

Azure Power Shell

Kudu REST API

REST API Process Threads list and minidump gcdump diagsession

今回ご紹介するサンプルスクリプトでは、Azure PowerShell と Kudu REST API を組み合わせて使用しますが、それぞれで認証方法が異なりますので、まずはその点をご案内します。

Azure PowerShell の認証

Azure PowerShell を使用するために、Azure PowerShell でのログインが必要です。
対話形式でスクリプトを実行する場合、Login-AzureRmAccountと入力すると、Azure の資格情報の入力を求めるダイアログ ボックスが表示されます。
運用フェーズでの利用では、サービス プリンシパルを使用した非対話形式の方法が適切な場合がありますが、その方法については本稿では割愛します。

Kudu REST API の認証

Kudu REST API は、Azure Web Apps のデプロイ資格情報による基本認証で認証されます。
以下は、基本認証情報を Authorization ヘッダーに設定するサンプルです。

[基本認証情報を設定する]

[powershell]
$username = "<username>"
$password = "<password>"
$base64AuthInfo = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password)))
$authHeader = @{Authorization=("Basic {0}" -f $base64AuthInfo)}
[/powershell]

 

また、デプロイ資格情報は Web Apps のリソース情報から取得することもできます。

[デプロイ資格情報を取得する]

[powershell]
$webAppName = "<webAppName>"
$resourceGroupName = "<resourceGroupName>"
$resource = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType Microsoft.Web/sites/config -ResourceName "$webAppName/publishingcredentials" -Action list -ApiVersion 2016-08-01 -Force
$username = $resource.properties.publishingUserName
$password = $resource.properties.publishingPassword
[/powershell]

 

特定のインスタンスを管理する

Azure Web Apps を複数インスタンスでホストしている際に、トラブルシューティング等のために、特定のインスタンスに対して管理を実行したい場合があります。
通常、複数インスタンスでホストされている場合、要求はラウンドロビンでロードバランシングされ、任意のインスタンスによって要求が処理されます。しかし、ARRAffinity クッキー (通常はセッション アフィニティの目的で使用されます) に、アクセスしたいインスタンスの ID を設定することで、特定のインスタンスに狙ってアクセスすることができます。

以下は、Web App で使用中のインスタンス ID を取得するサンプルです。

[インスタンス ID を取得する]

[powershell]
$webAppName = "<webAppName>"
$resourceGroupName = "<resourceGroupName>"
$instances = Get-AzureRmResource -ResourceGroupName $resourceGroupName -ResourceType Microsoft.Web/sites/instances -ResourceName $webAppName -ApiVersion 2016-08-01
$instanceIds = @()
foreach($instance in $instances)
{
$instanceIds += $instance.Name
}
[/powershell]

実行すると、$instanceIdsとして以下のような結果を取得することができます。

 a4951240a2a973f8aa3fb4a433eabf17c8d5b37bb6f444edb7d6e21bd160d35e
abd1db53c6d9f913fdd9aa2b9362933ec2770d5b2e294178637a5b55a95b0667
2dcf59fa789311a8e661bb55bb9eb5a641d4657871dba8575dead3011e293b1a

続いて、そのインスタンス ID を ARRAffinity クッキーに設定するサンプルです。このクッキーを設定して要求を発行することで、特定のインスタンスに狙ってアクセスすることができます。

[ARRAffinity クッキーを設定する]

[powershell]
$instanceId = "a4951240a2a973f8aa3fb4a433eabf17c8d5b37bb6f444edb7d6e21bd160d35e"
$kuduUrl = "https://<webAppName>.scm.azurewebsites.net"
$cookieSession = New-Object -TypeName Microsoft.PowerShell.Commands.WebRequestSession
$myCookie = New-Object -TypeName System.Net.Cookie
$myCookie.Name = "ARRAffinity"
$myCookie.Value = $instanceId
$cookieSession.Cookies.Add($kuduUrl, $myCookie)
[/powershell]

 

サンプル スクリプト

それでは、ここまでのご案内を踏まえまして、Web Apps の管理に役立つサンプル スクリプトをご紹介します。
以降のサンプルでは、前述の方法で基本認証情報を設定した$authHeaderと、ARRAffinity クッキーを設定した$cookieSessionを使用しています。

[プロセスをシャットダウンする]

[powershell]
$kuduUrl = "https://<webAppName>.scm.azurewebsites.net"
$endpoint = $kuduUrl + "/api/processes/-1"
Invoke-RestMethod -Headers $authHeader -WebSession $cookieSession -Uri $endpoint -Method Delete
[/powershell]

特定インスタンスのみでアプリケーションの再起動が必要になる場合、一旦ワーカー プロセスをシャットダウンすることで、次回アクセス時に再起動されます。
このサンプルでは、アプリケーションのメイン プロセスのみをシャットダウンします。

 

[プロセス メモリ ダンプを取得する]

[powershell]
$kuduUrl = "https://<webAppName>.scm.azurewebsites.net"
$dumpCount = 3
$dumpInterval = 10000
for ($i = 0; $i -lt $dumpCount; $i++)
{
$outfile = "C:\Diagnostics\" + (Get-Date).ToString("yyyyMMddHHmmss") + ".zip"
Invoke-RestMethod -Headers $authHeader -WebSession $cookieSession -Uri "$kuduUrl/api/processes/-1/dump?dumpType=2&amp&format=zip" -Method Get -OutFile $outfile
Start-Sleep -m $dumpInterval
}
[/powershell]

アプリケーションがハングアップする場合等に、プロセス メモリ ダンプを取得して解析することが調査方法として有効である場合があります。
このサンプルでは、10 秒間隔で 3 回、プロセス メモリ ダンプを取得し、ローカル環境の C:\Diagnostics に保存します。
取得したプロセス メモリ ダンプは、Debug Diagnostic Tool 等で解析することができます。

 

[コンピューター名を取得する]

[powershell]
$kuduUrl = "https://<webAppName>.scm.azurewebsites.net"
$endpoint = $kuduUrl + "/api/processes/-1"
$result = Invoke-RestMethod -Headers $authHeader -WebSession $cookieSession -Uri $endpoint -Method Get
$computerName = $result.environment_variables.COMPUTERNAME;
[/powershell]

Azure ポータル上のインスタンス表示では、インスタンス ID ではなく、"RD000D3A5019EF" というように仮想マシンのコンピューター名で表示される場合があります。
このサンプルの方法で、インスタンス上の環境変数から、コンピューター名を取得することができます。

 

まとめ

最後に、それぞれを組み合わせたサンプルを作成してみます。
このサンプルでは、各インスタンスのヘルスチェックを実行し、HTTP 200 応答が得られなかった場合にプロセス メモリ ダンプを取得しています。

[powershell]
$webAppName = "<webAppName>"
$resourceGroupName = "<resourceGroupName>"
$siteUrl = "https://$webAppName.azurewebsites.net"
$kuduUrl = "https://$webAppName.scm.azurewebsites.net"
$dumpCount = 3
$dumpInterval = 10000

# Azure PowerShell ログイン
Login-AzureRmAccount

# デプロイ資格情報を取得する
$resource = Invoke-AzureRmResourceAction -ResourceGroupName $resourceGroupName -ResourceType Microsoft.Web/sites/config -ResourceName "$webAppName/publishingcredentials" -Action list -ApiVersion 2016-08-01 -Force
$username = $resource.properties.publishingUserName
$password = $resource.properties.publishingPassword

# 基本認証情報を設定する
$base64AuthInfo = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password)))
$authHeader = @{Authorization=("Basic {0}" -f $base64AuthInfo)}

# インスタンス一覧を取得する
$instances = Get-AzureRmResource -ResourceGroupName $resourceGroupName -ResourceType Microsoft.Web/sites/instances -ResourceName $webAppName -ApiVersion 2016-08-01

# 各インスタンスに対して処理を実行する
foreach($instance in $instances)
{
# ARRAffinity クッキーを設定する
$cookieSession = New-Object -TypeName Microsoft.PowerShell.Commands.WebRequestSession
$myCookie = New-Object -TypeName System.Net.Cookie
$myCookie.Name = "ARRAffinity"
$myCookie.Value = $instance.Name
$cookieSession.Cookies.Add($kuduUrl, $myCookie)

# ヘルスチェックを実行する
$result = Invoke-WebRequest -WebSession $cookieSession -Uri $siteUrl -Method Get

if ($result.StatusCode -eq 200)
{
# 応答が HTTP 200 の場合
echo "$($instance.Name) is Healthy"
} else {
# 応答が HTTP 200 以外の場合
echo "$($instance.Name) is Unhealthy"

# プロセス メモリ ダンプを取得する
for ($i = 0; $i -lt $dumpCount; $i++)
{
$outfile = "C:\Diagnostics\" + (Get-Date).ToString("yyyyMMddHHmmss") + ".zip"
Invoke-RestMethod -Headers $authHeader -WebSession $cookieSession -Uri "$kuduUrl/api/processes/-1/dump?dumpType=2&amp&format=zip" -Method Get -OutFile $outfile
Start-Sleep -m $dumpInterval
}
}
}

[/powershell]

 


 

以上、今回は Kudu REST API の一部を使用したサンプルでしたが、組み合わせることで運用時のトラブルシューティング自動化にもご利用いただけるのではないかと思います。
また、認証情報の設定方法、特定のインスタンスにアクセスする方法を流用して、今回ご紹介していないその他の API も活用することができます。
今後も便利なスクリプトがありましたら、本ブログでご紹介していきたいと思います。