Akka.NET 管理とサービスディスカバリ
このスキルを使用するタイミング
以下の場合にこのスキルを使用します:
- Akka.NET クラスタを Kubernetes やクラウド環境にデプロイする場合
- 静的シードノードを動的サービスディスカバリに置き換える場合
- 自動形成のためのクラスタブートストラップを設定する場合
- ロードバランサー用のヘルスエンドポイントを設定する場合
- Azure Table Storage、Kubernetes API、または設定ベースのディスカバリと統合する場合
参照ファイル
- discovery-providers.md: 完全なコードとデプロイ YAML を含む Config、Kubernetes、Azure ディスカバリの設定
- configuration-reference.md: 強く型付けされた設定モデルクラス
概要
Akka.Management は、クラスタ管理のための HTTP エンドポイントを提供し、Akka.Cluster.Bootstrap と統合することで、静的シードノードの代わりにサービスディスカバリを使用した動的クラスタ形成を可能にします。
Akka.Management を使用する理由
| アプローチ | 長所 | 短所 |
|---|---|---|
| 静的シードノード | シンプル、依存関係なし | スケールしない、既知の IP が必要 |
| Akka.Management | 動的ディスカバリ、N ノードにスケール | 設定が多い、外部依存関係あり |
静的シードノードを使用する場合: 開発環境、単一ノードデプロイ、固定インフラストラクチャ。
Akka.Management を使用する場合: Kubernetes、オートスケーリンググループ、動的環境、本番クラスタ。
アーキテクチャ
┌─────────────────────────────────────────────────────────────┐
│ クラスタブートストラップ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ ノード 1 │ │ ノード 2 │ │ ノード 3 │ │
│ │ │ │ │ │ │ │
│ │ Management │◄──►│ Management │◄──►│ Management │ │
│ │ HTTP :8558 │ │ HTTP :8558 │ │ HTTP :8558 │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └──────────────────┼──────────────────┘ │
│ │ │
│ ┌───────▼───────┐ │
│ │ ディスカバリ │ │
│ │ プロバイダ │ │
│ └───────────────┘ │
│ │ │
└────────────────────────────┼────────────────────────────────┘
│
┌──────────────┼──────────────┐
│ │ │
┌─────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐
│ Kubernetes│ │ Azure │ │ Config │
│ API │ │ Tables │ │ (HOCON) │
└───────────┘ └────────────┘ └────────────┘
必須 NuGet パッケージ
<ItemGroup>
<!-- コア管理 -->
<PackageReference Include="Akka.Management" />
<PackageReference Include="Akka.Management.Cluster.Bootstrap" />
<!-- ディスカバリプロバイダから1つを選択 -->
<PackageReference Include="Akka.Discovery.KubernetesApi" /> <!-- Kubernetes用 -->
<PackageReference Include="Akka.Discovery.Azure" /> <!-- Azure用 -->
<PackageReference Include="Akka.Discovery.Config.Hosting" /> <!-- 静的設定用 -->
</ItemGroup>
Akka.Hosting 設定
モード選択による基本設定
public static class AkkaConfiguration
{
public static IServiceCollection ConfigureAkka(
this IServiceCollection services,
Action<AkkaConfigurationBuilder, IServiceProvider>? additionalConfig = null)
{
services.AddOptions<AkkaSettings>()
.BindConfiguration("AkkaSettings")
.ValidateDataAnnotations()
.ValidateOnStart();
return services.AddAkka("MySystem", (builder, sp) =>
{
var settings = sp.GetRequiredService<IOptions<AkkaSettings>>().Value;
var configuration = sp.GetRequiredService<IConfiguration>();
ConfigureNetwork(builder, settings, configuration);
ConfigureHealthChecks(builder);
additionalConfig?.Invoke(builder, sp);
});
}
private static void ConfigureNetwork(
AkkaConfigurationBuilder builder,
AkkaSettings settings,
IConfiguration configuration)
{
if (settings.ExecutionMode == AkkaExecutionMode.LocalTest)
return;
builder.WithRemoting(settings.RemoteOptions);
if (settings.ClusterBootstrapOptions.Enabled)
ConfigureAkkaManagement(builder, settings, configuration);
else
builder.WithClustering(settings.ClusterOptions);
}
}
Akka.Management 設定
private static void ConfigureAkkaManagement(
AkkaConfigurationBuilder builder,
AkkaSettings settings,
IConfiguration configuration)
{
var mgmtOptions = settings.AkkaManagementOptions;
var bootstrapOptions = settings.ClusterBootstrapOptions;
// 重要: Akka.Management 使用時はシードノードをクリア
settings.ClusterOptions.SeedNodes = [];
builder
.WithClustering(settings.ClusterOptions)
.WithAkkaManagement(setup =>
{
setup.Http.HostName = mgmtOptions.HostName;
setup.Http.Port = mgmtOptions.Port;
setup.Http.BindHostName = "0.0.0.0";
setup.Http.BindPort = mgmtOptions.Port;
})
.WithClusterBootstrap(options =>
{
options.ContactPointDiscovery.ServiceName = bootstrapOptions.ServiceName;
options.ContactPointDiscovery.PortName = bootstrapOptions.PortName;
options.ContactPointDiscovery.RequiredContactPointsNr = bootstrapOptions.RequiredContactPointsNr;
options.ContactPointDiscovery.Interval = bootstrapOptions.ContactPointProbingInterval;
options.ContactPointDiscovery.StableMargin = bootstrapOptions.StableMargin;
options.ContactPointDiscovery.ContactWithAllContactPoints = bootstrapOptions.ContactWithAllContactPoints;
options.ContactPoint.FilterOnFallbackPort = bootstrapOptions.FilterOnFallbackPort;
options.ContactPoint.ProbeInterval = bootstrapOptions.BootstrapperDiscoveryPingInterval;
});
// ディスカバリプロバイダを設定
ConfigureDiscovery(builder, settings, configuration);
}
Config、Kubernetes、Azure ディスカバリの完全な設定コードについては、discovery-providers.md を参照してください。
完全な強く型付けされた設定モデルクラスについては、configuration-reference.md を参照してください。
ヘルスエンドポイント
Akka.Management は、ロードバランサーやオーケストレーター向けにヘルスエンドポイントを公開します:
| エンドポイント | 目的 | 200 を返す条件 |
|---|---|---|
/alive | 生存確認 | ActorSystem が実行中 |
/ready | 準備完了確認 | クラスタメンバーが Up 状態 |
/cluster/members | デバッグ | クラスタメンバーシップを返す |
ASP.NET Core ヘルスチェック統合
// Akka ヘルスチェックを登録
builder.Services.AddHealthChecks();
// Akka 設定内で
builder
.WithActorSystemLivenessCheck() // "akka-liveness" ヘルスチェックを追加
.WithAkkaClusterReadinessCheck(); // "akka-cluster-readiness" ヘルスチェックを追加
// エンドポイントをマッピング
app.MapHealthChecks("/health/live", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("liveness")
});
app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("readiness")
});
トラブルシューティング
クラスタが形成されない
症状: ノードが個別のシングルノードクラスタのままになる。
チェックリスト:
- 全ノードが同じ
ServiceNameを使用している RequiredContactPointsNrが実際のレプリカ数と一致している- ディスカバリプロバイダが正しく設定されている
- ネットワークが管理ポート (8558) へのトラフィックを許可している
- Kubernetes の場合: RBAC 権限が設定されている
スプリットブレイン
症状: 1つのクラスタではなく、複数のクラスタが形成される。
解決策:
ContactWithAllContactPoints = trueを設定- 遅い環境では
StableMarginを増やす - Aspire の場合:
FilterOnFallbackPort = false(動的ポート) - Kubernetes の場合:
FilterOnFallbackPort = true(固定ポート)
Azure ディスカバリの問題
症状: ノードが Azure Tables 経由で相互に発見できない。
チェックリスト:
- 接続文字列が有効である
- ストレージアカウントがテーブル操作を許可している
- 全ノードが同じ
ServiceNameを使用している - ファイアウォールが Azure Storage へのアクセスを許可している
Aspire 統合
詳細な Aspire 固有のパターンについては、akka-net-aspire-configuration スキルを参照してください。
Aspire のクイックリファレンス:
// AppHost 内
appBuilder
.WithEndpoint(name: "remote", protocol: ProtocolType.Tcp,
env: "AkkaSettings__RemoteOptions__Port")
.WithEndpoint(name: "management", protocol: ProtocolType.Tcp,
env: "AkkaSettings__AkkaManagementOptions__Port")
.WithEnvironment("AkkaSettings__ClusterBootstrapOptions__Enabled", "true")
.WithEnvironment("AkkaSettings__ClusterBootstrapOptions__DiscoveryMethod", "AzureTableStorage")
.WithEnvironment("AkkaSettings__ClusterBootstrapOptions__FilterOnFallbackPort", "false");
まとめ: 何をいつ使うか
| シナリオ | ディスカバリ方法 | FilterOnFallbackPort |
|---|---|---|
| ローカル開発(単一ノード) | なし(シードノードを使用) | N/A |
| Aspire マルチノード | AzureTableStorage | false |
| Kubernetes | Kubernetes | true |
| Azure VM/VMSS | AzureTableStorage | true |
| 固定インフラストラクチャ | Config | true |
| AWS ECS/EC2 | AWS ディスカバリプラグイン | true |