Alternative Architecture DOJO

オルターブースのクラウドネイティブ特化型ブログです。

.NET AspireのAzure Functions統合とAzureリソースデプロイを試す

adventar.org

こんにちは、MLBお兄さんこと松村です。
この記事はオルターブース Advent Calendar 2024の12日目の記事です。
昨日は花岡くんの「拡張性と保守性を高めるMediatR入門」でした。

aadojo.alterbooth.com


先日11月12日に .NET 9 が正式リリースとなりました。
.NET 9のリリースに合わせて、.NET Aspire もバージョン 9.0 がリリースとなっています。

dotnet.microsoft.com

.NET Aspire 9.0 のアップデート内容の一つに、Azure Functions との統合があります。
Azure Functions のプロジェクトや、Azure Functions が接続する Azure リソースを .NET Aspire で構成管理することが可能になるというものです。

learn.microsoft.com

github.com

.NET Aspire プロジェクトを作成する

Visual Studio 2022 17.3 Preview を使用します。
.NET Aspire の空のプロジェクトはスタート画面から作成することができます。
このときのフレームワークは .NET 9 を選択しましょう。

まだこの段階では AppHost と ServiceDefaults の2つのプロジェクトだけがある状態です。

.NET Aspire で Azure Functions を管理する

続いて Azure Functions のプロジェクトを作成します。
Visual Studio でプロジェクトを作成する際に、「.NET Aspire オーケストレーションへの参加 (プレビュー)」を選択した状態で、 プロジェクトを作成します。

このとき AppHost には Azure Functions 用のパッケージ (Aspire.Hosting.Azure.Functions) が追加され、 Program.cs には、Azure Functions の参照構成が記載されます。

var builder = DistributedApplication.CreateBuilder(args);

builder.AddAzureFunctionsProject<Projects.FunctionApp1>("functionapp1")
    .WithExternalHttpEndpoints();

builder.Build().Run();

もちろん Aspire のダッシュボードには、Azure Functions のエンドポイントが表示されています。

リソース一覧にはもう一つコンテナーがありますが、これは AzureWebJobsStorage 用のストレージです。
Visual Studio では Azurite エミュレーターを使用しますが、Aspire では Azurite のコンテナーに置き換わります。
コンテナーイメージには mcr.microsoft.com/azure-storage/azurite:3.32.0 が使用されています。

トリガーとなる Azure の依存リソースを追加する

.NET Aspire で管理可能な Azure Functions のトリガーは、現時点では6つです。

  1. Event Hubs トリガー
  2. Service Bus トリガー
  3. Storage Blob トリガー
  4. Storage Queue トリガー
  5. HTTP トリガー
  6. タイマートリガー

そのうち Event Hubs、Service Bus、ストレージについては、.NET Aspire でリソースを管理することが可能です。
今回は Event Hubs トリガーの関数を作成するのにあわせて、リソースの管理も構成してみます。

.NET Aspire x Event Hubs

  1. AppHost プロジェクトに Event Hubs 拡張機能をインストールする
  2. https://www.nuget.org/packages/Aspire.Hosting.Azure.EventHubs
  3. AppHost プロジェクト > Program.cs に Event Hubs の依存関係を定義する

     var builder = DistributedApplication.CreateBuilder(args);
    
     var eventHubs = builder.AddAzureEventHubs("eventhubs").AddEventHub("items");
    
     builder.AddAzureFunctionsProject<Projects.FunctionApp1>("functionapp1")
         .WithExternalHttpEndpoints()
         .WithReference(eventHubs);
    
     builder.Build().Run();
    
  4. AppHost プロジェクト > appsettings.{Environment}.json にデプロイ先の Azure 情報を記載する
    (サブスクリプションID、リソースグループ名のプレフィックス、リージョン、リソースグループ作成の許可、マネージドIDの種類)

     {
       "Logging": {
         "LogLevel": {
           "Default": "Information",
           "Microsoft.AspNetCore": "Warning",
           "Aspire.Hosting.Dcp": "Warning"
         }
       },
       "Azure": {
         "SubscriptionId": "<your subscription id>",
         "ResourceGroupPrefix": "rg",
         "Location": "Japan East",
         "AllowResourceGroupCreation": true,
         "CredentialSource": "AzureCli"
       }
     }
    
  5. Azure CLI で対象のサブスクリプションにログインしたうえで、AppHost プロジェクトを実行すると、Event Hubs がデプロイされる

このように Aspire で依存関係として Azure リソースを指定しておくことで、そのリソースが使用可能な状態までデプロイしてくれます。
Event Hubs 以外のリソースも同様に定義します。

Event Hubs トリガー関数から接続する

続いて、その Event Hubs リソースを使用する Azure Functions の Event Hubs トリガーを作成します。
Visual Studio ではダイアログから作成することができますが、各種指定が必要な項目には以下の値を入力します。

項目
Connection string setting name eventhubs
Event Hub name items

この値はどこからくるかというと、AppHost > Program.cs で構成している Event Hubs の設定値と合わせる必要があります。

var eventHubs = builder.AddAzureEventHubs("eventhubs").AddEventHub("items");

こういった構成値は依存先のプロジェクト (今回は Azure Functions) の環境変数として自動的に設定されます。自身で接続文字列などを管理する必要がありません。
Aspire のダッシュボードから環境変数を確認することができます。

Aspire がデプロイするリソース情報を確認する

Aspire から Azure リソースをデプロイすると、リソースグループ名やリソース名のサフィックスにランダムな文字列が付与されます。
今回の例では以下のようなサフィックスがついています。

種類 名前 サフィックス
リソースグループ rg-aspirewithfunctionappapphost-b3f9b03c aspirewithfunctionappapphost-b3f9b03c
Event Hubs eventhubs-wn5zsceq2jx3u wn5zsceq2jx3u

では、このサフィックスなどはどこで管理されているかというと、 AppHost プロジェクトのユーザーシークレットに保管されています。

learn.microsoft.com

実際に AppHost プロジェクトのユーザーシークレットを参照してみると、様々な情報が登録されています。
ユーザーシークレットを直接変更するような必要性はありませんが、ここで管理されているということは知っておいて損はないと思います。

> dotnet user-secrets list
Azure:Tenant = (省略).onmicrosoft.com
Azure:ResourceGroup = rg-aspirewithfunctionappapphost-b3f9b03c
Azure:Deployments:storage:Parameters = {"principalId":{"value":"(省略)"},"principalType":{"value":"User"},"location":{"value":"japaneast"}}
Azure:Deployments:storage:Outputs = {"blobEndpoint":{"type":"String","value":"https://storagewn5zsceq2jx3u.blob.core.windows.net/"},"queueEndpoint":{"type":"String","value":"https://storagewn5zsceq2jx3u.queue.core.windows.net/"},"tableEndpoint":{"type":"String","value":"https://storagewn5zsceq2jx3u.table.core.windows.net/"}}
Azure:Deployments:storage:Id = /subscriptions/(省略)/resourceGroups/rg-aspirewithfunctionappapphost-b3f9b03c/providers/Microsoft.Resources/deployments/storage
Azure:Deployments:storage:CheckSum = 9783bcde
Azure:Deployments:eventhubs:Parameters = {"principalId":{"value":"(省略)"},"principalType":{"value":"User"},"location":{"value":"japaneast"}}
Azure:Deployments:eventhubs:Outputs = {"eventHubsEndpoint":{"type":"String","value":"https://eventhubs-wn5zsceq2jx3u.servicebus.windows.net:443/"}}
Azure:Deployments:eventhubs:Id = /subscriptions/(省略)/resourceGroups/rg-aspirewithfunctionappapphost-b3f9b03c/providers/Microsoft.Resources/deployments/eventhubs
Azure:Deployments:eventhubs:CheckSum = 1acf9c50

Docker Desktop 必須という少し微妙なところはありますが、.NET Aspire 自体はクラウドネイティブアプリケーションの環境管理として、とてもパワーを発揮すると感じています。
この記事で興味をもっていただけたなら、ぜひ .NET Aspire で遊んでみてください。

また、こういった内容を来年1月にある .NET Conf 2024 Fukuoka x Osaka で話す予定ですのでお楽しみに!

fukuten.connpass.com


サービス一覧 www.alterbooth.com cloudpointer.tech www.alterbooth.com