Application InsightsのカスタムTrackAvailabilityテストを使ったAzure OpenAIの正常性監視
2024-12-12
azblob://2024/12/12/eyecatch/2024-12-12-appi-custom-track-availability-test-000.png
本記事は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を監視対象としましたが、リクエストを送る部分を修正することで、他のサービス監視にも使用できると思います。どなたかの参考になれば幸いです。