【.NET Aspire入門】第1回:クラウドネイティブ開発の新時代
はじめに
クラウドネイティブアプリケーションの開発は、現代のソフトウェア開発において避けて通れない道となりました。しかし、マイクロサービスアーキテクチャの複雑性、分散システムの運用、ローカル開発環境の構築など、多くの課題があります。
.NET Aspireは、これらの課題を解決するためにMicrosoftが開発した革新的なフレームワークです。本シリーズでは、.NET Aspireを使ったクラウドネイティブアプリケーション開発を基礎から実践まで、段階的に解説していきます。
.NET Aspireとは?
.NET Aspireは、クラウドネイティブアプリケーションの開発を簡素化するためのオープンソースフレームワークです。分散アプリケーションの構築、デバッグ、デプロイを効率化し、開発者の生産性を大幅に向上させます。
主な特徴
- 統合開発体験: ローカル開発からクラウドデプロイまでシームレスに対応
- サービスディスカバリー: 自動的なサービス検出と接続
- 観測可能性: 組み込みのロギング、メトリクス、トレーシング
- 開発者ツール: Visual StudioやVS Codeとの深い統合
- 柔軟なデプロイメント: Docker、Kubernetes、Azure Container Appsなど多様な環境に対応
なぜ.NET Aspireが必要なのか
従来の課題
# 従来の docker-compose.yml の例
version: '3.8'
services:
api:
build: ./api
ports:
- "5000:80"
environment:
- ConnectionStrings__DefaultConnection=Server=db;Database=MyApp;User=sa;Password=MyPassword123!
- Redis__ConnectionString=redis:6379
depends_on:
- db
- redis
frontend:
build: ./frontend
ports:
- "3000:80"
environment:
- API_URL=http://api:80
depends_on:
- api
db:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=MyPassword123!
ports:
- "1433:1433"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
このような構成では以下の問題があります:
- 環境変数の管理が複雑
- サービス間の依存関係の定義が煩雑
- ローカル開発時のデバッグが困難
- 観測可能性の実装が別途必要
.NET Aspireによる解決
// Program.cs (.NET Aspire AppHost)
var builder = DistributedApplication.CreateBuilder(args);
// インフラストラクチャの定義
var cache = builder.AddRedis("cache");
var database = builder.AddSqlServer("sql")
.AddDatabase("myapp");
// APIサービスの追加
var api = builder.AddProject<Projects.MyApp_Api>("api")
.WithReference(cache)
.WithReference(database);
// フロントエンドの追加
var frontend = builder.AddProject<Projects.MyApp_Frontend>("frontend")
.WithReference(api);
builder.Build().Run();
開発環境のセットアップ
前提条件
- .NET 8.0 以上
- Docker Desktop
- Visual Studio 2022 17.9+ または VS Code
- .NET Aspire ワークロード
インストール手順
# .NET Aspire ワークロードのインストール
dotnet workload update
dotnet workload install aspire
# インストールの確認
dotnet workload list
Visual Studio での設定
Visual Studio を使用する場合は、以下の手順でセットアップします:
- Visual Studio Installer を開く
- 「変更」をクリック
- 「ASP.NET と Web 開発」ワークロードを選択
- 「.NET Aspire SDK (プレビュー)」にチェック
- インストール
最初の.NET Aspireアプリケーション
プロジェクトの作成
# ソリューションの作成
dotnet new aspire-starter -n MyFirstAspireApp
cd MyFirstAspireApp
# プロジェクト構造の確認
tree /F
生成されるプロジェクト構造:
MyFirstAspireApp/
├── MyFirstAspireApp.sln
├── MyFirstAspireApp.ApiService/
│ ├── Program.cs
│ ├── appsettings.json
│ └── MyFirstAspireApp.ApiService.csproj
├── MyFirstAspireApp.AppHost/
│ ├── Program.cs
│ ├── appsettings.json
│ └── MyFirstAspireApp.AppHost.csproj
├── MyFirstAspireApp.ServiceDefaults/
│ ├── Extensions.cs
│ └── MyFirstAspireApp.ServiceDefaults.csproj
└── MyFirstAspireApp.Web/
├── Program.cs
├── Components/
└── MyFirstAspireApp.Web.csproj
各プロジェクトの役割
- AppHost: オーケストレーター(全体の構成を定義)
- ServiceDefaults: 共通設定(ロギング、ヘルスチェックなど)
- ApiService: バックエンドAPI
- Web: フロントエンドアプリケーション
基本的なサービス構成
AppHost の設定
// MyFirstAspireApp.AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);
// Redisキャッシュの追加
var cache = builder.AddRedis("cache");
// APIサービスの追加(Redisを参照)
var apiService = builder.AddProject<Projects.MyFirstAspireApp_ApiService>("apiservice")
.WithReference(cache);
// Webフロントエンドの追加(APIを参照)
builder.AddProject<Projects.MyFirstAspireApp_Web>("webfrontend")
.WithReference(apiService);
builder.Build().Run();
ServiceDefaults の実装
// MyFirstAspireApp.ServiceDefaults/Extensions.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
namespace Microsoft.Extensions.Hosting;
public static class Extensions
{
public static IHostApplicationBuilder AddServiceDefaults(
this IHostApplicationBuilder builder)
{
// OpenTelemetryの設定
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
});
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation();
})
.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation();
});
// デフォルトのヘルスチェック
builder.Services.AddDefaultHealthChecks();
// サービスディスカバリーの設定
builder.Services.AddServiceDiscovery();
builder.Services.ConfigureHttpClientDefaults(http =>
{
http.AddStandardResilienceHandler();
http.AddServiceDiscovery();
});
return builder;
}
public static IHostApplicationBuilder ConfigureOpenTelemetryLogging(
this IHostApplicationBuilder builder)
{
var otlpEndpoint = builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"];
if (!string.IsNullOrEmpty(otlpEndpoint))
{
builder.Logging.AddOpenTelemetry(logging =>
{
logging.AddOtlpExporter();
});
}
return builder;
}
private static IServiceCollection AddDefaultHealthChecks(
this IServiceCollection services)
{
services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy(),
["live"]);
return services;
}
public static WebApplication MapDefaultEndpoints(
this WebApplication app)
{
// ヘルスチェックエンドポイント
app.MapHealthChecks("/health");
app.MapHealthChecks("/alive", new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("live")
});
return app;
}
}
実行とデバッグ
アプリケーションの起動
# AppHostプロジェクトから起動
cd MyFirstAspireApp.AppHost
dotnet run
起動すると、Aspire Dashboardが自動的に開きます:
- URL: https://localhost:17209 (ポートは自動割り当て)
- ダッシュボード機能:
- サービスの状態監視
- ログの集約表示
- 分散トレーシング
- メトリクスの可視化
Visual Studioでのデバッグ
- ソリューションエクスプローラーでAppHostプロジェクトを右クリック
- 「スタートアッププロジェクトに設定」を選択
- F5キーでデバッグ開始
- 各サービスに個別にブレークポイントを設定可能
観測可能性の活用
ログの確認
// ApiService でのロギング例
app.MapGet("/weatherforecast", (ILogger<Program> logger) =>
{
logger.LogInformation("Weather forecast requested at {Time}",
DateTimeOffset.UtcNow);
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
logger.LogInformation("Returning {Count} weather forecasts",
forecast.Length);
return forecast;
});
分散トレーシング
// サービス間の呼び出しを自動的にトレース
public class WeatherService
{
private readonly HttpClient _httpClient;
private readonly ILogger<WeatherService> _logger;
public WeatherService(HttpClient httpClient, ILogger<WeatherService> logger)
{
_httpClient = httpClient;
_logger = logger;
}
public async Task<WeatherForecast[]> GetForecastAsync()
{
// このHTTP呼び出しは自動的にトレースされる
var response = await _httpClient.GetFromJsonAsync<WeatherForecast[]>(
"http://apiservice/weatherforecast");
return response ?? Array.Empty<WeatherForecast>();
}
}
トラブルシューティング
よくある問題と解決方法
-
Docker Desktopが起動していない
エラー: Docker daemon is not running 解決: Docker Desktopを起動してください
-
ポートの競合
エラー: Address already in use 解決: 使用中のポートを確認し、必要に応じて変更
-
ワークロードがインストールされていない
# 再インストール dotnet workload clean dotnet workload install aspire
まとめ
今回は、.NET Aspireの基本概念と開発環境のセットアップ、最初のアプリケーション作成について学びました。重要なポイント:
- .NET Aspireの利点: 分散アプリケーション開発の複雑性を大幅に削減
- 統合された開発体験: ローカル開発からクラウドデプロイまでシームレス
- 組み込みの観測可能性: ロギング、メトリクス、トレーシングが標準装備
- 開発者フレンドリー: Visual Studioとの深い統合によるデバッグの容易さ
次回は、データベースやメッセージングなど、より実践的なサービス統合について解説します。
参考リンク
次回予告:「第2回:データベースとキャッシングの統合」では、SQL Server、PostgreSQL、Redisなどのデータストアを.NET Aspireアプリケーションに統合する方法を詳しく解説します。