Start Debugging

.NET 9 と .NET 10 でコンテナ上の gRPC が「難しい」と感じる: 修正できる 4 つの落とし穴

.NET 9 と .NET 10 でコンテナに gRPC をホストするときによくある 4 つの落とし穴: HTTP/2 のプロトコル不一致、TLS 終端の混乱、壊れたヘルスチェック、プロキシの設定ミス -- それぞれの修正方法付き。

今日また r/dotnet で話題になりました: 「なぜコンテナで gRPC サービスをホストするのはこんなに難しいのか?」。短い答えとしては、gRPC は HTTP/2 について強い意見を持っており、コンテナはネットワーク境界をより明示的にします。TLS をどこで終端するか、どのポートが HTTP/2 を話すか、前段にどのプロキシを置くかを決める必要に迫られます。

元の議論: https://www.reddit.com/r/dotnet/comments/1q93h2h/why_is_hosting_grpc_services_in_containers_so_hard/

落とし穴 1: コンテナのポートには到達できるが、HTTP/2 を話していない

gRPC はエンドツーエンドで HTTP/2 を要求します。プロキシが HTTP/1.1 にダウングレードすると、アプリのバグのように見える謎の “unavailable” エラーが発生します。

.NET 9 / .NET 10 では、サーバーの意図を明示的に宣言してください:

using Microsoft.AspNetCore.Server.Kestrel.Core;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    // Inside a container you usually run plaintext HTTP/2 and terminate TLS at the proxy.
    options.ListenAnyIP(8080, listen =>
    {
        listen.Protocols = HttpProtocols.Http2;
    });
});

builder.Services.AddGrpc();

var app = builder.Build();
app.MapGrpcService<GreeterService>();
app.MapGet("/", () => "gRPC service. Use a gRPC client.");
app.Run();

落とし穴 2: TLS 終端が不明確 (そして gRPC クライアントはそれを気にする)

多くのチームは「コンテナ = TLS」と考えがちです。実際には、境界で TLS を終端するほうがシンプルです:

Kestrel で TLS を終端する場合は、コンテナ内に証明書も必要で、適切なポートを公開する必要があります。実現可能ですが、可動部品が増えるだけです。

落とし穴 3: ヘルスチェックが間違ったものを調べている

Kubernetes の HTTP プローブや基本的なロードバランサーのプローブは、しばしば HTTP/1.1 です。gRPC のエンドポイントを直接プローブすると、サービスが正常でも失敗する可能性があります。

実用的な修正は 2 つあります:

落とし穴 4: プロキシと HTTP/2 のデフォルト設定に噛まれる

gRPC を「難しく」感じさせる最も簡単な方法は、上流に対して HTTP/2 で設定されていないプロキシを前段に置くことです。プロキシが次のように明示的に設定されていることを確認してください:

最後の項目が、Nginx のデフォルト設定の多くが gRPC でつまずく場所です。

退屈なままでいられるコンテナ構成

Kubernetes に触れる前に単一の参照点が欲しい場合は、まずローカルで検証することから始めてください: コンテナを起動し、grpcurl で叩き、その後プロキシを前段に置いて、引き続き HTTP/2 がエンドツーエンドでネゴシエートされることを確認します。

参考リンク: https://learn.microsoft.com/aspnet/core/grpc/

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< 戻る