内部ループにおけるネットワーキングの概要
Aspire を使って開発する利点の一つは、クラウド ネイティブ アプリをローカル環境で開発、テスト、デバッグできることです。内部ループ ネットワーキングは、開発環境内でアプリ同士が相互に通信できるようにする Aspire の重要な要素です。本記事では、プロキシ、エンドポイント、エンドポイント構成、起動プロファイルを用いて、Aspire がさまざまなネットワーキング シナリオをどのように扱うかを学びます。
内部ループにおけるネットワーキング
Section titled “内部ループにおけるネットワーキング”内部ループとは、アプリをターゲット環境にデプロイする前に、ローカル環境で開発およびテストを行うプロセスです。Aspire には、内部ループにおけるネットワーキング体験を簡素化し、向上させるためのさまざまなツールや機能が用意されています。例えば次のようなものです:
- 起動プロファイル: 起動プロファイルは、アプリをローカルでどのように実行するかを指定する構成ファイルです。起動プロファイル(launchSettings.json ファイルなど)を使用して、アプリのエンドポイント、環境変数、起動設定を定義できます。
- Kestrel 構成: Kestrel 構成では、Kestrel Web サーバーが待ち受けるエンドポイントを指定できます。アプリ設定で Kestrel のエンドポイントを構成すると、Aspire はそれらの設定を自動的に使用してエンドポイントを作成します。
- エンドポイント/エンドポイント 構成: エンドポイントは、データベース、メッセージ キュー、API など、アプリが依存するサービスとアプリとの間の接続を表します。エンドポイントには、サービス名、ホスト ポート、スキーム、環境変数などの情報が含まれます。エンドポイントは、起動プロファイルによって暗黙的に追加することも、
WithEndpointを呼び出して明示的に追加することもできます。 - プロキシ: Aspire は、アプリに追加した各サービス バインディングごとに自動的にプロキシを起動し、プロキシが待ち受けるポートを割り当てます。プロキシは、その後、アプリが待ち受けているポート(プロキシ ポートとは異なる場合があります)にリクエストを転送します。これにより、ポートの競合を回避し、一貫性があり予測可能な URL を使用してアプリやサービスにアクセスできるようになります。
エンドポイントの仕組み
Section titled “エンドポイントの仕組み”Aspire におけるサービス バインディングは、次の 2 つの統合要素で構成されます。1 つは、アプリが必要とする外部リソース(データベース、メッセージ キュー、API など)を表す サービス、もう 1 つは、アプリとそのサービスの間の接続を確立し、必要な情報を提供する バインディング です。
Aspire は 2 種類のサービス バインディングをサポートしています。1 つは、異なる環境でのアプリの動作を定義する起動プロファイルに基づいて自動的に作成される 暗黙的 なバインディング、もう 1 つは、WithEndpoint を使用して手動で作成する 明示的 なバインディングです。
暗黙的・明示的のいずれでバインディングが作成された場合でも、Aspire は指定されたポートで軽量なリバース プロキシを起動し、アプリからサービスへのリクエストに対するルーティングや負荷分散を処理します。このプロキシは Aspire の実装上の詳細であり、構成や管理について意識する必要はありません。
エンドポイントの動作を視覚的に理解するために、Aspire スターター テンプレートの内部ループ ネットワーキング図を確認してください:

コンテナー ネットワークの管理方法
Section titled “コンテナー ネットワークの管理方法”1 つ以上のコンテナー リソースを追加すると、Aspire はコンテナー間のサービス検出を可能にするため、専用のコンテナー ブリッジ ネットワークを作成します。このブリッジ ネットワークは、コンテナー同士が相互に通信できるようにする仮想ネットワークであり、DNS 名を使用したコンテナー間のサービス検出のための DNS サーバーも提供します。
ネットワークのライフタイムは、コンテナー リソースの設定に依存します:
- すべてのコンテナーがセッション ライフタイムの場合、ネットワークもセッション ベースとなり、AppHost プロセスの終了時にクリーンアップされます。
- いずれかのコンテナーが永続ライフタイムの場合、ネットワークは永続化され、AppHost プロセスが終了した後も稼働し続けます。Aspire は以降の実行時にこのネットワークを再利用するため、AppHost が動作していない間も、永続コンテナー同士の通信が維持されます。
コンテナーのライフタイムの詳細については、 永続コンテナーのライフタイムを参照してください。
コンテナー ネットワークの命名規則は次のとおりです:
- セッション ネットワーク:
aspire-session-network-<unique-id>-<app-host-name> - 永続ネットワーク:
aspire-persistent-network-<project-hash>-<app-host-name>
各 AppHost インスタンスは、それぞれ独自のネットワーク リソースを持ちます。異なるのはネットワークのライフタイムと名前のみで、サービス検出の仕組みはどちらの場合も同じです。
コンテナーは、自身のリソース名を使用してネットワークに登録されます。Aspire はこの名前を、コンテナー間のサービス検出に利用します。たとえば、pgadmin コンテナーは、postgres という名前のデータベース リソースに対して postgres:5432 を使って接続できます。
起動プロファイル
Section titled “起動プロファイル”AddProject を呼び出すと、AppHost は既定のエンドポイント セットを決定するために Properties/launchSettings.json を参照します。AppHost は、次の規則に従って特定の起動プロファイルを選択します:
AddProjectの呼び出し時に明示的に指定されたlaunchProfileName引数。DOTNET_LAUNCH_PROFILE環境変数。詳細については .NET の環境変数 を参照してください。- launchSettings.json に定義されている最初の起動プロファイル。
次の launchSettings.json ファイルを例に考えてみましょう:
{ "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "http": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", "applicationUrl": "https://localhost:7239;http://localhost:5066", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } }}この記事の以降では、DistributedApplication.CreateBuilder API を使用して、builder という名前の変数に割り当てられた IDistributedApplicationBuilder を作成したものとします:
var builder = DistributedApplication.CreateBuilder(args);http および https の起動プロファイルを指定するには、launchSettings.json ファイル内でそれぞれの applicationUrl の値を構成します。これらの URL は、このプロジェクトのエンドポイントを作成するために使用されます。これは次と同等です:
builder.AddProject<Projects.Networking_Frontend>("frontend") .WithHttpEndpoint(port: 5066) .WithHttpsEndpoint(port: 7239);詳細については、 起動プロファイル を参照してください。
Kestrel で構成されたエンドポイント
Section titled “Kestrel で構成されたエンドポイント”Aspire は Kestrel のエンドポイント構成をサポートしています。たとえば、HTTPS スキームとポート 5271 を持つ Kestrel エンドポイントを定義したプロジェクトの appsettings.json ファイルは、次のようになります:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "Kestrel": { "Endpoints": { "Https": { "Url": "https://*:5271" } } }}前述の構成では、Https エンドポイントが指定されています。Url プロパティは https://*:5271 に設定されており、これはポート 5271 で、すべてのインターフェイスを対象に待ち受けることを意味します。詳細については、ASP.NET Core Kestrel Web サーバーのエンドポイントを構成する を参照してください。
Kestrel エンドポイントを構成した場合は、launchSettings.json ファイルから、構成されている applicationUrl を削除する必要があります。
プロジェクト リソースを追加する際には、launchSettings.json ファイルの代わりに Kestrel エンドポイントを使用することを指定できるオーバーロードがあります:
builder.AddProject<Projects.Networking_ApiService>( name: "apiservice", configure: static project => { project.ExcludeLaunchProfile = true; project.ExcludeKestrelEndpoints = false; }) .WithHttpsEndpoint();詳細については、AddProject を参照してください。
ポートとプロキシ
Section titled “ポートとプロキシ”サービス バインディングを定義する際、ホスト ポートは 常に サービスの前段に配置されるプロキシに割り当てられます。これにより、サービスが単一レプリカの場合でも複数レプリカの場合でも、同様に振る舞うことができます。さらに、WithReference API を使用するすべてのリソース依存関係は、環境変数から取得されるプロキシのエンドポイントに依存します。
次の例では、AddProject、WithHttpEndpoint、WithReplicas を順に呼び出すメソッド チェーンを示しています:
builder.AddProject<Projects.Networking_Frontend>("frontend") .WithHttpEndpoint(port: 5066) .WithReplicas(2);前述のコードにより、次のネットワーキング図が得られます:

前述の図は、次の内容を示しています:
- アプリへのエントリ ポイントとしての Web ブラウザー。
- 5066 のホスト ポート。
- Web ブラウザーとフロントエンド サービスのレプリカの間に配置され、ポート 5066 で待ち受けるフロントエンド プロキシ。
- ランダムに割り当てられたポート 65001 で待ち受ける
frontend_0フロントエンド サービス レプリカ。 - ランダムに割り当てられたポート 65002 で待ち受ける
frontend_1フロントエンド サービス レプリカ。
WithReplicas を呼び出さない場合、フロントエンド サービスは 1 つだけになります。この場合でもプロキシはポート 5066 で待ち受けますが、フロントエンド サービス自体はランダムなポートで待ち受けます:
builder.AddProject<Projects.Networking_Frontend>("frontend") .WithHttpEndpoint(port: 5066);次の 2 つのポートが定義されています:
- 5066 のホスト ポート。
- 基になるサービスがバインドされる、ランダムに割り当てられたプロキシ ポート。

前述の図は、次の内容を示しています:
- アプリへのエントリ ポイントとしての Web ブラウザー。
- 5066 のホスト ポート。
- Web ブラウザーとフロントエンド サービスの間に配置され、ポート 5066 で待ち受けるフロントエンド プロキシ。
- ランダムに割り当てられたポート 65001 で待ち受けるフロントエンド サービス。
基になるサービスには、このポートがプロジェクト リソースの場合は ASPNETCORE_URLS を通じて渡されます。その他のリソースは、サービス バインディングに環境変数を指定することでこのポートにアクセスします:
builder.AddNpmApp("frontend", "../NodeFrontend", "watch") .WithHttpEndpoint(port: 5067, env: "PORT");前述のコードにより、ランダム ポートが PORT 環境変数として利用可能になります。アプリはこのポートを使用して、プロキシからの受信接続を待ち受けます。次の図を参照してください:

前述の図は、次の内容を示しています:
- アプリへのエントリ ポイントとしての Web ブラウザー。
- 5067 のホスト ポート。
- Web ブラウザーとフロントエンド サービスの間に配置され、ポート 5067 で待ち受けるフロントエンド プロキシ。
- 環境変数で指定されたポート 65001 で待ち受けるフロントエンド サービス。
ホスト ポートを省略する場合
Section titled “ホスト ポートを省略する場合”ホスト ポートを省略すると、Aspire はホスト ポートとサービス ポートの両方に対してランダムなポートを生成します。これは、ポートの競合を回避したい場合や、ホスト ポートやサービス ポートを特に意識しない場合に便利です。次のコードを例に考えてみましょう:
builder.AddProject<Projects.Networking_Frontend>("frontend") .WithHttpEndpoint();このシナリオでは、次の図に示すように、ホスト ポートとサービス ポートの両方がランダムになります:

前述の図は、次の内容を示しています:
- アプリへのエントリ ポイントとしての Web ブラウザー。
- ランダムに割り当てられたホスト ポート 65000。
- Web ブラウザーとフロントエンド サービスの間に配置され、ポート 65000 で待ち受けるフロントエンド プロキシ。
- ランダムに割り当てられたポート 65001 で待ち受けるフロントエンド サービス。
コンテナー ポート
Section titled “コンテナー ポート”コンテナー リソースを追加すると、Aspire は自動的にランダムなポートをコンテナーに割り当てます。コンテナー ポートを指定するには、目的のポートを使用するようにコンテナー リソースを構成します:
builder.AddContainer("frontend", "mcr.microsoft.com/dotnet/samples", "aspnetapp") .WithHttpEndpoint(port: 8000, targetPort: 8080);前述のコードでは、次のことが行われています:
mcr.microsoft.com/dotnet/samples:aspnetappイメージから、frontendという名前のコンテナー リソースを作成します。- ホストをポート 8000 にバインドし、コンテナーのポート 8080 にマッピングしつつ、
httpエンドポイントを公開します。
次の図を参照してください:

エンドポイント拡張メソッド
Section titled “エンドポイント拡張メソッド”IResourceWithEndpoints インターフェイスを実装する任意のリソースは、WithEndpoint 拡張メソッドを使用できます。この拡張メソッドには複数のオーバーロードがあり、スキーム、コンテナー ポート、ホスト ポート、環境変数名、そしてエンドポイントをプロキシ経由にするかどうかを指定できます。
また、エンドポイントを構成するためのデリゲートを指定できるオーバーロードもあります。これは、環境やその他の要因に応じてエンドポイントを構成する必要がある場合に便利です。次のコードを例に考えてみましょう:
builder.AddProject<Projects.Networking_ApiService>("apiService") .WithEndpoint( endpointName: "admin", callback: static endpoint => { endpoint.Port = 17003; endpoint.UriScheme = "http"; endpoint.Transport = "http"; });前述のコードでは、エンドポイントを構成するためのコールバック デリゲートが提供されています。このエンドポイントは admin という名前で、http スキームおよびトランスポートを使用し、ホスト ポート 17003 に構成されています。コンシューマーは、このエンドポイントを名前で参照します。次の AddHttpClient の呼び出しを確認してください:
builder.Services.AddHttpClient<WeatherApiClient>( client => client.BaseAddress = new Uri("http://_admin.apiservice"));Uri は、_ プレフィックスを付けた admin エンドポイント名を使用して構築されます。これは、admin セグメントが apiservice サービスに属するエンドポイント名であることを示すための規約です。詳細については、サービス検出を参照してください。
追加の考慮事項
Section titled “追加の考慮事項”WithEndpoint 拡張メソッドを呼び出す際、callback オーバーロードでは生の EndpointAnnotation が公開され、これによりエンドポイントのさまざまな側面をカスタマイズできます。
AllocatedEndpoint プロパティを使用すると、サービスのエンドポイントを取得または設定できます。IsExternal と IsProxied プロパティは、エンドポイントの管理方法や公開方法を決定します。IsExternal は公開アクセス可能かどうかを決定し、IsProxied は DCP による管理を有効にして、内部ポートの違いやレプリケーションを可能にします。
Name プロパティはサービスを識別し、Port および TargetPort プロパティは、それぞれ希望するポートと実際に待ち受けるポートを指定します。
ネットワーク通信に関しては、Protocol プロパティが TCP および UDP をサポートしており、将来的にはさらに追加される可能性があります。また、Transport プロパティはトランスポート プロトコル(HTTP、HTTP2、HTTP3)を示します。最後に、サービスが URI でアドレス指定可能な場合、UriScheme プロパティがサービス URI を構築するための URI スキームを提供します。
詳細については、EndpointAnnotation のプロパティ一覧を参照してください。
エンドポイントのフィルタリング
Section titled “エンドポイントのフィルタリング”Aspire のすべてのプロジェクト リソース エンドポイントは、あらかじめ定められたルールや判断基準に基づいて扱われます。実行時に ASPNETCORE_URLS に含まれるエンドポイントもあれば、HTTP/HTTPS_PORTS として公開されるもの、Kestrel の構成から解決されるものもあります。こうした既定の動作に関わらず、WithEndpointsInEnvironment 拡張メソッドを使用することで、環境変数に含めるエンドポイントをフィルタリングできます:
builder.AddProject<Projects.Networking_ApiService>("apiservice") .WithHttpsEndpoint() // Adds a default "https" endpoint .WithHttpsEndpoint(port: 19227, name: "admin") .WithEndpointsInEnvironment( filter: static endpoint => { return endpoint.Name is not "admin"; });前述のコードでは、既定の HTTPS エンドポイントに加えて、ポート 19227 の admin エンドポイントが追加されます。ただし、admin エンドポイントは環境変数には含まれません。これは、内部利用のみにエンドポイントを公開したい場合に便利です。