Application InsightsのカスタムTrackAvailabilityテストを使ったAzure OpenAIの正常性監視

目次
- 本ブログで紹介するシステム構成
- 要件
- インフラ構成
- インフラ構築
- リソースグループ
- VNET/サブネット
- Azure OpenAI
- Log Analytics
- Automateアカウント
- Application Insights
- AutomationアカウントのマネージドIDに権限付与
- 正常性確認用のアプリケーション作成
- アプリケーションファイルの作成
- 必要なパッケージのインストール
- Program.csの作成
- Dockerfileの作成
- コンテナイメージのビルド&プッシュ
- アプリケーションの配置
- Container Instanceの作成
- Container InstanceのマネージドIDに各種権限付与
- AutomationアカウントにRunbookを追加
- Automationアカウントに環境変数追加
- Automationアカウントの定期実行設定
- 動作確認
- 最後に
本記事はFIXER Advent Calendar 2024( FIXER Advent Calendar 2024 ~tech編~ )12月12日の記事です。
Application InsightsのカスタムTrackAvailabilityテストを使ってAzure OpenAIの正常性監視が行えるか検証したので、備忘録として残しておきます。
本ブログで紹介するシステム構成
要件
構築する監視システムは、下記の要件があるものとします。
- 5分に1回 Azure OpenAIに回答生成のリクエストを送り、成功可否をApplication Insightsに記録する。
- 監視対象のAzure OpenAIはパブリックアクセスが禁止されている。
インフラ構成

Azure OpenAIへパブリックアクセスが禁止されているので、アプリケーション基盤はVNET統合ができるContainer Instanceを採用し、サービスエンドポイント経由でリクエストを送る構成になっています。
関数アプリを採用する案もあったのですが、料金の安い従量課金プランはVNET統合に対応していなかったので見送りになりました。
インフラ構築
リソースグループ

特にコメントなし。
VNET/サブネット


Container Instance VNET統合用のVNETとサブネットをそれぞれ作成します。
また、Container InstanceとAuzre OpenAI間の通信をサービスエンドポイント経由にするために、Container Instance VNET統合用のサブネットにサービスエンドポイント`Microsoft.CognitiveServices`を追加します。
Azure OpenAI

ネットワーク設定で、[Selected networks, configure network security for your Azure AI services resource.]にチェックを入れ、選択したネットワーク以外からアクセスできないようにします。
また、Container InstanceがあるVENTからアクセスできるように、[Virtual network]と[Subnets]の欄に、1つ前の項で作成したVNETとサブネットを入力します。
Azure OpenAIが作成されたら、GPT-4o-miniモデルをデプロイし、アプリケーションからリクエストを送ることができるようにします。
Log Analytics

Container InstanceとApplication Insightsのログ取得のために作成します。
Automateアカウント

システム割り当てマネージドIDを有効化して作成してください。

デフォルトでRunbookが追加されるので不要なら削除します。
Application Insights

先ほど作成したLog Analyticsを指定して作成します。

作成したApplication Insightsの[構成] > [プロパティ] > [ローカル認証] を開き、[ローカル認証]を無効化します。
※ この作業を行わないと接続文字列を使った認証となりRBACでのアクセス制御が行えない。

Container Instance用のコンテナイメージをプッシュするコンテナレジストリを作成します。
AutomationアカウントのマネージドIDに権限付与
AutomationアカウントにContainer Instanceを開始できる権限を付与します。先ほど作成したContainer Instanceのアクセス制御から、`Azure Container Instances Contributor Role`というロールをAutomationアカウントのマネージドIDに追加します。
正常性確認用のアプリケーション作成
次にContainer Instanceにデプロイするアプリケーションを作成します。
$ dotnet --version
// 8.0.404
アプリケーションファイルの作成
$ dotnet new console -o App -n DotNet.Docker
必要なパッケージのインストール
// Application Insights用SDK
$ dotnet add package Microsoft.ApplicationInsights --version 2.22.0
// Azure認証用
$ dotnet add package Azure.Identity --version 1.13.1
// Azure OpenAI用
$ dotnet add package Azure.AI.OpenAI --version 2.1.0
Program.csの作成
[/App/Program.cs]を開き下記のコードを貼り付けます。
using System.Diagnostics;
// マネージドID関連
using Azure.Identity;
// Azure OpenAI関連
using Azure.AI.OpenAI;
using OpenAI.Chat;
// Application Insights関連
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;
// 認証情報の作成
var credential = new DefaultAzureCredential();
// Application Insgihtsの設定
var telemetryConfiguration = new TelemetryConfiguration();
telemetryConfiguration.ConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING");
telemetryConfiguration.TelemetryChannel = new InMemoryChannel();
telemetryConfiguration.SetAzureTokenCredential(credential);
var telemetryClient = new TelemetryClient(telemetryConfiguration);
// 可用性テストの作成
string testName = "openai-availability-test";
string location = "Japan East";
var availability = new AvailabilityTelemetry
{
Name = testName,
RunLocation = location,
Success = false
};
// Azure OpenAIからのレスポンス時間を測定
var stopwatch = new Stopwatch();
stopwatch.Start();
try
{
using (var activity = new Activity("AvailabilityContext"))
{
activity.Start();
availability.Id = "202412111530";
// Azure OpenAIに回答生成のリクエストを送信
string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
var client = new AzureOpenAIClient(new Uri(endpoint), credential);
var chatClient = client.GetChatClient("gpt-4o-mini");
var completion = await chatClient.CompleteChatAsync(
new UserChatMessage("Output 'Y'")
);
}
// 可用性テストの成功フラグ
availability.Success = true;
}
catch (Exception ex)
{
availability.Message = ex.Message;
throw;
}
finally
{
stopwatch.Stop();
availability.Duration = stopwatch.Elapsed;
availability.Timestamp = DateTimeOffset.UtcNow;
// Application Insightsに可用性テスト結果を送信
telemetryClient.TrackAvailability(availability);
telemetryClient.Flush();
}
Dockerfileの作成
C#FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:35792ea4ad1db051981f62b313f1be3b46b1f45cadbaa3c288cd0d3056eefb83 AS build-env
WORKDIR /App
# Copy
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -c Release -o out
# Build
FROM mcr.microsoft.com/dotnet/aspnet:8.0@sha256:6c4df091e4e531bb93bdbfe7e7f0998e7ced344f54426b7e874116a3dc3233ff
WORKDIR /App
COPY --from=build-env /App/out .
ENTRYPOINT ["dotnet", "DotNet.Docker.dll"]
コンテナイメージのビルド&プッシュ
C#$ docker login <コンテナレジストリ名>.azurecr.io
$ docker build -t my-app .
$ docker tag my-app <コンテナレジストリ名>.azurecr.io/my-app
$ docker push <コンテナレジストリ名>.azurecr.io/my-app
アプリケーションの配置
Container Instanceの作成

先ほどコンテナレジストリにイメージをプッシュしたイメージを選択してContainer Instanceを作成します。また、VNET統合を行うために[ネットワーク]設定で、[ネットワークの種類]をプライベートに、[仮想ネットワーク]と[サブネット]の欄は先ほど作成したVNETとサブネットを入力してください。さらに、環境変数に下記の内容を追加し、アプリケーションにAzure OpenAIのエンドポイントとApplication Insightsの接続文字列を渡せるようにします。
- AZURE_OPENAI_ENDPOINT: https://<Azure OpenAI名>.openai.azure.com/
- APPLICATIONINSIGHTS_CONNECTION_STRING: <Application Insightsの接続文字列>

Container Instanceの作成が完了したら、システム割り当てのマネージドIDを有効化します。後程このマネージドIDにAzure OpenAIとApplication Insightsにリクエストを送るための権限を追加します。
Container InstanceのマネージドIDに各種権限付与


Azure OpenAI用に、[Cognitive Services OpenAI User]を、Application Insights用に[監視メトリック発行者]というロールをそれぞれ付与してください。
AutomationアカウントにRunbookを追加

作成したAutomationアカウントを開き、[Runbook] > [+Runbookの作成]を押下し、下記の内容でRunbookを作成します。
C#- 名前: CheckAzureOpenAiAvailavility
- Runbookの種類 PowerShell
- ランタイムバージョン: 7.2
Runbookが作成されると、[PowerShell Runbookの編集]画面に遷移するので、下記のスクリプトを貼り付け、[公開]を押下します。
# 変数読み込み
$acirResourceGroupName = Get-AutomationVariable -Name "ACI_RESOURCE_GROUP_NAME"
$aciName = Get-AutomationVariable -Name "ACI_NAME"
# マネージドIDで認証
try
{
"Logging in to Azure..."
Connect-AzAccount -Identity
}
catch {
Write-Error -Message $_.Exception
throw $_.Exception
}
# コンテナインスタンスを開始
Start-AzContainerGroup -Name $aciName -ResourceGroupName $acirResourceGroupName
Automationアカウントに環境変数追加
作成したAutomationアカウントを開き、[変数] > [変数の追加]から下記の内容で環境変数を追加します。
- ACI_RESOURCE_GROUP_NAME: <Container Instanceがあるリソースグループ名>
- ACI_NAME: <Container Instance名>
Automationアカウントの定期実行設定
作成したAutomationアカウントを開き、[スケジュール] > [+スケジュールの追加]を押下しRunbookを定期実行させるための設定を追加します。

Automationアカウントのスケジュールは、実行間隔を1時間より短くできないので、開始時刻を5分刻みでずらしたものを12個作ることで、強引に対応します。

次に作成したRunbookを開き、[スケジュール] > [+スケジュールの追加]を押下し、先ほど作成したAutomationアカウントのスケジュールをRunbookに追加します。
動作確認

作成したApplication Insightsから[調査] > [有効]を開き、可用性テストが正常に記録されているか確認します。
可用性テストの成功可否はApplication Insightsのログやメトリックに保存されるため、その内容を元にアラートを作成することで、Azure OpenAIの障害時に迅速に対応することができるようになると思います。
最後に
今回はAzure OpenAIを監視対象としましたが、リクエストを送る部分を修正することで、他のサービス監視にも使用できると思います。どなたかの参考になれば幸いです。