ASP.NET Core の正常性チェック

作成者: Glenn CondronJuergen Gutsch

注意

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の ASP.NET Core 8.0 バージョンを参照してください。

ASP.NET Core からは、アプリ インフラストラクチャ コンポーネントの正常性を報告するための正常性チェック ミドルウェアとライブラリが提供されます。

正常性チェックは HTTP エンドポイントとしてアプリによって公開されます。 正常性チェック エンドポイントは、さまざまなリアルタイム監視シナリオに合わせて設定できます。

  • 正常性プローブは、アプリの状態を確認する目的でコンテナー オーケストレーターとロード バランサーによって使用できます。 たとえば、正常性チェックで問題が確認された場合、コンテナー オーケストレーターは実行中の展開を停止したり、コンテナーを再起動したりします。 ロード バランサーはアプリの異常に対処するため、問題のあるインスタンスから正常なインスタンスにトラフィック経路を変更することがあります。
  • メモリ、ディスク、その他の物理サーバー リソースの使用を監視し、正常性の状態を確認できます。
  • 正常性チェックでは、データベースや外部サービス エンドポイントなど、アプリの依存関係をテストし、それらが利用できることと正常に機能していることを確認できます。

正常性チェックは通常、アプリの状態を確認する目的で、外部の監視サービスまたはコンテナー オーケストレーターと共に使用されます。 正常性チェックをアプリに追加する前に、使用する監視システムを決定します。 監視システムからは、作成する正常性チェックの種類とそのエンドポイントの設定方法が指示されます。

基本的な正常性プローブ

多くのアプリでは、アプリが要求を処理できること (活動性) を報告する基本的な正常性チェック構成で十分にアプリの状態を検出できます。

基本の構成では、正常性チェック サービスを登録し、正常性チェック ミドルウェアを呼び出します。このミドルウェアが特定の URL エンドポイントにおける正常性を返します。 既定では、特定の依存関係またはサブシステムをテストする正常性チェックは登録されていません。 正常性エンドポイント URL で応答できる場合、そのアプリは正常であると見なされます。 既定の応答ライターは、プレーンテキストの応答として HealthStatus をクライアントに書き込みます。 HealthStatus は、HealthStatus.HealthyHealthStatus.Degraded、または HealthStatus.Unhealthy です。

正常性チェック サービスを Program.csAddHealthChecks に登録します。 MapHealthChecks を呼び出して、正常性チェック エンドポイントを作成します。

次の例では、/healthz に正常性チェック エンドポイントを作成しています。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker の HEALTHCHECK

Docker からは、組み込み HEALTHCHECK ディレクティブが提供されます。これを使用し、基本的な正常性チェック構成を使用するアプリの状態を確認できます。

HEALTHCHECK CMD curl --fail http://localhost:5000/healthz || exit

上の例では、curl を使用して、/healthz の正常性チェック エンドポイントに対して HTTP 要求を行っています。 curl は .NET Linux コンテナー イメージには含まれていませんが、必要なパッケージを Dockerfile にインストールすることによって追加できます。 Alpine Linux に基づくイメージを使用するコンテナーでは、curl の代わりに含まれている wget を使用できます。

正常性チェックを作成する

正常性チェックは IHealthCheck インターフェイスを実装することで作成されます。 CheckHealthAsync メソッドによって、HealthyDegradedUnhealthy のいずれかの正常性を示す HealthCheckResult が返されます。 結果は、構成可能なステータス コードを含むプレーンテキストの応答として書き込まれます。 構成については、「正常性チェック オプション」を参照してください。 HealthCheckResult からは、任意のキーと値のペアを返すこともできます。

次の例は、正常性チェックのレイアウトを示しています。

public class SampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

正常性チェックのロジックが CheckHealthAsync メソッドに配置されています。 前の例では、ダミー変数 isHealthytrue に設定されています。 isHealthy の値が false に設定されている場合、HealthCheckRegistration.FailureStatus 状態が返されます。

CheckHealthAsync がチェック中に例外をスローした場合、HealthReportEntry.StatusFailureStatus に設定された新しい HealthReportEntry が返されます。 この状態は AddCheck によって定義され (「正常性チェック サービスを登録する」を参照)、チェックに失敗した原因となった内部例外が含まれています。 Description は例外のメッセージに設定されます。

正常性チェック サービスを登録する

正常性チェック サービスを登録するには、Program.csAddCheck を呼び出します。

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>("Sample");

次の例にある AddCheck オーバーロードでは、正常性チェックでエラーが報告されると、レポートにエラー状態 (HealthStatus) が設定されます。 エラー状態が null (既定) に設定された場合、HealthStatus.Unhealthy が報告されます。 このオーバーロードはライブラリ作成者にとって便利です。この設定に正常性チェック実装が従う場合、正常性チェック エラーが発生したとき、ライブラリによって指示されるエラー状態がアプリによって適用されます。

"タグ" を使用して、正常性チェックをフィルター処理できます。 タグの詳細については、「正常性チェックをフィルター処理する」を参照してください。

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" });

AddCheck では、lambda 関数も実行できます。 この例では、正常性チェックにより常に正常な結果が返されます。

builder.Services.AddHealthChecks()
    .AddCheck("Sample", () => HealthCheckResult.Healthy("A healthy result."));

AddTypeActivatedCheck を呼び出して、正常性チェックの実装に引数を渡します。 次の例では、型がアクティブ化された正常性チェックは、コンストラクターに整数と文字列を受け取ります。

public class SampleHealthCheckWithArgs : IHealthCheck
{
    private readonly int _arg1;
    private readonly string _arg2;

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        // ...

        return Task.FromResult(HealthCheckResult.Healthy("A healthy result."));
    }
}

上記の正常性チェックを登録するには、整数と文字列を引数として渡して AddTypeActivatedCheck を呼び出します。

builder.Services.AddHealthChecks()
    .AddTypeActivatedCheck<SampleHealthCheckWithArgs>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" },
        args: new object[] { 1, "Arg" });

正常性チェックのルーティングを使用する

Program.cs で、エンドポイントの URL または相対パスを使用して、エンドポイント ビルダーで MapHealthChecks を呼び出します。

app.MapHealthChecks("/healthz");

ホストが必要

RequireHost を呼び出して、正常性チェック エンドポイントに許可されている 1 つ以上のホストを指定します。 ホストは、punycode ではなく Unicode にする必要があります。また、ポートを含めることができます。 コレクションが指定されていない場合は、任意のホストを使用できます。

app.MapHealthChecks("/healthz")
    .RequireHost("www.contoso.com:5001");

特定のポートでのみ応答するように正常性チェック エンドポイントを制限するには、RequireHost の呼び出しでポートを指定します。 この方法は通常、サービスを監視するためのポートを公開する目的で、コンテナー環境で使用されます。

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001");

警告

HttpRequest.HostRequireHost などのホスト ヘッダーに依存する API は、クライアントによるスプーフィングの対象になる可能性があります。

ホストとポートのスプーフィングを防ぐには、次のいずれかの方法を使用します。

承認されていないクライアントがポートをスプーフィングするのを防ぐには、RequireAuthorization を呼び出します。

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001")
    .RequireAuthorization();

詳細については、「RequireHost とルートが一致するホスト」を参照してください。

承認が必要

RequireAuthorization を呼び出して、正常性チェック要求エンドポイントで承認ミドルウェアを実行します。 RequireAuthorization のオーバーロードには 1 つ以上の承認ポリシーを使用できます。 ポリシーが指定されていない場合は、既定の承認ポリシーが使用されます。

app.MapHealthChecks("/healthz")
    .RequireAuthorization();

クロスオリジン要求 (CORS) の有効化

ブラウザーから手動で正常性チェックを実行することは一般的なシナリオではありませんが、正常性チェック エンドポイントで RequireCors を呼び出して CORS ミドルウェアを有効にすることができます。 RequireCors のオーバーロードには、CORS ポリシー ビルダーのデリゲート (CorsPolicyBuilder) またはポリシー名を使用できます。 詳細については、「ASP.NET Core でクロスオリジン要求 (CORS) を有効にする」を参照してください。

正常性チェック オプション

HealthCheckOptions では、正常性チェックの動作をカスタマイズできます。

正常性チェックをフィルター処理する

既定では、正常性チェック ミドルウェアによって、登録済みの正常性チェックがすべて実行されます。 正常性チェックのサブセットを実行するには、Predicate オプションにブール値を返す関数を指定します。

次の例では、正常性チェックのフィルター処理を行い、sample タグが付けられているものだけが実行されるようにします。

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("sample")
});

HTTP 状態コードをカスタマイズする

ResultStatusCodes を使用し、HTTP 状態コードに対する正常性状態のマッピングをカスタマイズします。 次の StatusCodes 代入はミドルウェアによって使用される既定値です。 要件に合わせて状態コード値を変更します。

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResultStatusCodes =
    {
        [HealthStatus.Healthy] = StatusCodes.Status200OK,
        [HealthStatus.Degraded] = StatusCodes.Status200OK,
        [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
    }
});

キャッシュ ヘッダーを非表示にする

AllowCachingResponses によって、応答キャッシュを禁止する目的で、正常性チェック ミドルウェアによって HTTP ヘッダーがプローブ応答に追加されるかどうかが制御されます。 値が false (既定) の場合、応答キャッシュを禁止する目的で、ミドルウェアによってヘッダー Cache-ControlExpiresPragma が設定またはオーバーライドされます。 値が true の場合、応答のキャッシュ ヘッダーがミドルウェアによって変更されることはありません。

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    AllowCachingResponses = true
});

出力をカスタマイズする

正常性チェック レポートの出力をカスタマイズするには、HealthCheckOptions.ResponseWriter プロパティを、応答の書き込み先のデリゲートに設定します。

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResponseWriter = WriteResponse
});

既定の委任では、文字列値 HealthReport.Status を含む、最小のプレーンテキスト応答が書き込まれます。 次のカスタム デリゲートでは、System.Text.Json を使用してカスタム JSON 応答が出力されます。

private static Task WriteResponse(HttpContext context, HealthReport healthReport)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions { Indented = true };

    using var memoryStream = new MemoryStream();
    using (var jsonWriter = new Utf8JsonWriter(memoryStream, options))
    {
        jsonWriter.WriteStartObject();
        jsonWriter.WriteString("status", healthReport.Status.ToString());
        jsonWriter.WriteStartObject("results");

        foreach (var healthReportEntry in healthReport.Entries)
        {
            jsonWriter.WriteStartObject(healthReportEntry.Key);
            jsonWriter.WriteString("status",
                healthReportEntry.Value.Status.ToString());
            jsonWriter.WriteString("description",
                healthReportEntry.Value.Description);
            jsonWriter.WriteStartObject("data");

            foreach (var item in healthReportEntry.Value.Data)
            {
                jsonWriter.WritePropertyName(item.Key);

                JsonSerializer.Serialize(jsonWriter, item.Value,
                    item.Value?.GetType() ?? typeof(object));
            }

            jsonWriter.WriteEndObject();
            jsonWriter.WriteEndObject();
        }

        jsonWriter.WriteEndObject();
        jsonWriter.WriteEndObject();
    }

    return context.Response.WriteAsync(
        Encoding.UTF8.GetString(memoryStream.ToArray()));
}

正常性チェック API には、複雑な JSON の戻り値の形式に対する組み込みのサポートが用意されていません。この形式は、選択した監視システムに固有のものであるためです。 必要に応じて、上記の例の応答をカスタマイズします。 System.Text.Json を使用した JSON シリアル化の詳細については、.NET で JSON をシリアル化および逆シリアル化する方法に関する記事をご覧ください。

データベース プローブ

正常性チェックでは、データベースが通常どおり応答しているかどうかを示すブール値テストとして実行されるよう、データベース クエリを指定できます。

ASP.NET Core アプリ用の正常性チェック ライブラリ AspNetCore.Diagnostics.HealthChecks には、SQL Server データベースに対して実行される正常性チェックが含まれています。 AspNetCore.Diagnostics.HealthChecks によってデータベースに対して SELECT 1 クエリが実行され、データベースへの接続が正常であることが確認されます。

警告

クエリでデータベース接続を確認するとき、すぐに返されるクエリを選択します。 このクエリ手法には、データベースをオーバーロードし、そのパフォーマンスを低下させるというリスクがあります。 ほとんどの場合、テスト クエリは実行する必要がありません。 データベースに正常に接続できれば十分です。 クエリを実行する必要があれば、SELECT 1 など、単純な SELECT クエリを選択してください。

この SQL Server 正常性チェックを使用するには、AspNetCore.HealthChecks.SqlServer NuGet パッケージへのパッケージ参照を含めます。 次の例では、SQL Server 正常性チェックを登録します。

var conStr = builder.Configuration.GetConnectionString("DefaultConnection");
if (string.IsNullOrEmpty(conStr))
{
    throw new InvalidOperationException(
                       "Could not find a connection string named 'DefaultConnection'.");
}
builder.Services.AddHealthChecks()
    .AddSqlServer(conStr);

Note

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

Entity Framework Core DbContext プローブ

DbContext チェックでは、EF CoreDbContext に対して構成されているデータベースとアプリとが通信できることが確認されます。 DbContext チェックは、次のようなアプリでサポートされています。

AddDbContextCheck によって DbContext の正常性チェックが登録されます。 DbContextTContext としてメソッドに指定されます。 オーバーロードはエラー状態、タグ、カスタム テスト クエリの設定に利用できます。

既定では:

  • DbContextHealthCheck は、EF Core の CanConnectAsyncメソッドを呼び出します。 AddDbContextCheck メソッドのオーバーロードを使用して正常性を確認するときに実行される操作をカスタマイズできます。
  • 正常性チェックの名前は TContext 型の名前になります。

次の例では、DbContext と、これに関連付けられている DbContextHealthCheck を登録します。

builder.Services.AddDbContext<SampleDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddHealthChecks()
    .AddDbContextCheck<SampleDbContext>();

対応性と活動性に区分されるプローブ

一部のホスティング シナリオでは、2 つのアプリ状態を区別する一組の正常性チェックが使用されます。

  • "対応性" は、アプリが通常どおり実行されているが、要求を受け取る準備ができていないのか、あるいはそうではないのかを示します。
  • "活動性" は、アプリがクラッシュしたため、再起動する必要があるのかどうかを示します。

次に例を示します。アプリでは、大きな構成ファイルをダウンロードしないと、要求を処理する準備ができません。 初回ダウンロードに失敗した場合、アプリを再起動することは望みません。アプリはファイルのダウンロードを数回再試行する可能性があるためです。 liveness probe を使用し、プロセスの活動性を記述します。他のチェックは実行されません。 また、構成ファイルのダウンロードが完了する前は、要求がアプリに送信されないようにします。 "対応性プローブ" を使用し、ダウンロードが成功し、要求を受け取る準備がアプリにできるまで、"準備できていない" 状態を示します。

次のバックグラウンド タスクでは、15 秒ほどかかるスタートアップ プロセスをシミュレートします。 完了すると、このタスクによって StartupHealthCheck.StartupCompleted プロパティが true に設定されます。

public class StartupBackgroundService : BackgroundService
{
    private readonly StartupHealthCheck _healthCheck;

    public StartupBackgroundService(StartupHealthCheck healthCheck)
        => _healthCheck = healthCheck;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Simulate the effect of a long-running task.
        await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);

        _healthCheck.StartupCompleted = true;
    }
}

StartupHealthCheck は、実行時間の長いスタートアップ タスクの完了をレポートし、バックグラウンド サービスによって設定される StartupCompleted プロパティを公開します。

public class StartupHealthCheck : IHealthCheck
{
    private volatile bool _isReady;

    public bool StartupCompleted
    {
        get => _isReady;
        set => _isReady = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        if (StartupCompleted)
        {
            return Task.FromResult(HealthCheckResult.Healthy("The startup task has completed."));
        }

        return Task.FromResult(HealthCheckResult.Unhealthy("That startup task is still running."));
    }
}

ホステッド サービスと共に Program.cs で正常性チェックが AddCheck に登録されます。 ホステッド サービスでは正常性チェックにプロパティを設定する必要があるため、正常性チェックはシングルトンとしてサービス コンテナーにも登録されます。

builder.Services.AddHostedService<StartupBackgroundService>();
builder.Services.AddSingleton<StartupHealthCheck>();

builder.Services.AddHealthChecks()
    .AddCheck<StartupHealthCheck>(
        "Startup",
        tags: new[] { "ready" });

2 つの異なる正常性チェック エンドポイントを作成するには、MapHealthChecks を 2 回呼び出します。

app.MapHealthChecks("/healthz/ready", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("ready")
});

app.MapHealthChecks("/healthz/live", new HealthCheckOptions
{
    Predicate = _ => false
});

前の例では、次の正常性チェック エンドポイントを作成しています。

  • 対応性チェックの場合は /healthz/ready。 対応性チェックでは、ready タグが付けられているものに正常性チェックが絞り込まれます。
  • 活動性チェックの場合は /healthz/live。 この活動性チェックでは、HealthCheckOptions.Predicate デリゲートで false を返すことによって、すべての正常性チェックを除外します。 正常性チェックのフィルター処理の詳細については、この記事の「正常性チェックをフィルター処理する」を参照してください。

スタートアップ タスクが完了する前に、/healthz/ready エンドポイントから Unhealthy状態がレポートされます。 スタートアップ タスクが完了したら、このエンドポイントから Healthy 状態がレポートされます。 /healthz/live エンドポイントは、すべてのチェックを除外し、すべての呼び出しに対して Healthy 状態をレポートします。

Kubernetes の例

対応性チェックと活動性チェックを使い分けることは、Kubernetes などの環境で便利です。 Kubernetes では、要求を受け入れる前に、基礎をなすデータベースの可用性テストなど、時間のかかるスタートアップ作業の実行がアプリに要求されることがあります。 別個のチェックを利用することで、アプリは機能しているがまだ準備ができていないか、あるいはアプリが起動に失敗したかをオーケストレーターは区別できます。 Kubernetes の対応性プローブと活動性プローブに関する詳細については、Kubernetes ドキュメントの「Configure Liveness and Readiness Probes」 (活動性プローブと対応性プローブを設定する) を参照してください。

次の例では、Kubernetes 対応性プローブの構成を確認できます。

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /healthz/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

正常性チェック ライブラリを配布する

正常性チェックをライブラリとして配布するには:

  1. スタンドアロン クラスとして IHealthCheck インターフェイスを実装する正常性チェックを記述します。 このクラスは、設定データにアクセスする目的で依存関係挿入 (DI)、型のアクティブ化、名前付きオプションに依存できます。

  2. 拡張メソッドを記述します。拡張メソッドを使用するアプリがその Program.cs メソッドで呼び出すパラメーターを指定します。 arg1arg2 をコンストラクター パラメーターとして受け取る、次の正常性チェックの例を考えてみましょう。

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);
    

    先のシグネチャは、正常性チェック プローブ ロジックを処理するためには、正常性チェックにカスタム データが必要であることを示しています。 正常性チェックが拡張メソッドに登録されたときに正常性チェック インスタンスを作成するための委任にデータが提供されます。 次の例では、呼び出し元によって以下が指定されます。

    • arg1: 正常性チェックの整数データ ポイント。
    • arg2: 正常性チェックの文字列引数。
    • name: 正常性チェック名 (省略可能)。 null の場合、既定値が使用されます。
    • failureStatus: エラー状態に対してレポートされる HealthStatus (省略可能)。 null の場合、HealthStatus.Unhealthy が使用されます。
    • tags: タグの IEnumerable<string> コレクション (省略可能)。
    public static class SampleHealthCheckBuilderExtensions
    {
        private const string DefaultName = "Sample";
    
        public static IHealthChecksBuilder AddSampleHealthCheck(
            this IHealthChecksBuilder healthChecksBuilder,
            int arg1,
            string arg2,
            string? name = null,
            HealthStatus? failureStatus = null,
            IEnumerable<string>? tags = default)
        {
            return healthChecksBuilder.Add(
                new HealthCheckRegistration(
                    name ?? DefaultName,
                    _ => new SampleHealthCheckWithArgs(arg1, arg2),
                    failureStatus,
                    tags));
        }
    }
    

正常性チェック パブリッシャー

サービス コンテナーに IHealthCheckPublisher が追加されると、正常性チェック システムにより定期的に正常性チェックが実行され、結果と共に PublishAsync が呼び出されます。 このプロセスは、正常性を判断する目的で監視システムを定期的に呼び出すことを各プロセスに求めるプッシュベースの監視システム シナリオで便利です。

HealthCheckPublisherOptions を使うと次を設定できます。

  • Delay:アプリが起動した後、IHealthCheckPublisher インスタンスを実行する前に適用される初期遅延です。 遅延はスタートアップ時に一度だけ適用され、後の繰り返しには適用されません。 既定値は 5 秒です。
  • Period:IHealthCheckPublisher を実行する期間です。 既定値は 30 秒です。
  • Predicate:Predicatenull (既定値) の場合、正常性チェック パブリッシャー サービスにより登録済みのすべての正常性チェックが実行されます。 正常性チェックのサブセットを実行するには、チェックのセットをフィルター処理する関数を指定します。 述語は期間ごとに評価されます。
  • Timeout:すべての IHealthCheckPublisher インスタンスに対する正常性チェックの実行のタイムアウトです。 タイムアウトなしで実行するには InfiniteTimeSpan を使います。 既定値は 30 秒です。

次の例は、正常性パブリッシャーのレイアウトを示しています。

public class SampleHealthCheckPublisher : IHealthCheckPublisher
{
    public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            // ...
        }
        else
        {
            // ...
        }

        return Task.CompletedTask;
    }
}

HealthCheckPublisherOptions クラスには、正常性チェック パブリッシャーの動作を構成するためのプロパティが用意されています。

次の例では、正常性チェック パブリッシャーをシングルトンとして登録し、HealthCheckPublisherOptions を構成します。

builder.Services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = healthCheck => healthCheck.Tags.Contains("sample");
});

builder.Services.AddSingleton<IHealthCheckPublisher, SampleHealthCheckPublisher>();

AspNetCore.Diagnostics.HealthChecks:

  • Application Insights など、いくつかのシステム用の発行元を含みます。
  • Microsoft によって保守もサポートも行われて "いません"。

個々の正常性チェック

Delay および Period は、それぞれの HealthCheckRegistration に個別に設定できます。 これは、いくつかの正常性チェックを HealthCheckPublisherOptions で設定されている期間とは異なるレートで実行したい場合に便利です。

次のコードは、SampleHealthCheck1 に対して DelayPeriod を設定します。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks()
   .Add(new HealthCheckRegistration(
       name: "SampleHealthCheck1",
       instance: new SampleHealthCheck(),
       failureStatus: null,
       tags: null,
       timeout: default)
   {
       Delay = TimeSpan.FromSeconds(40),
       Period = TimeSpan.FromSeconds(30)
   });

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

依存関係の挿入と正常性チェック

正常性チェック クラス内の特定の Type のインスタンスを使用するために、依存関係の挿入を使用することができます。 依存関係の挿入は、正常性チェックにオプションまたはグローバル構成を挿入する場合に役立ちます。 依存関係の挿入を使用することは、正常性チェックを構成するための一般的なシナリオでは "ありません"。 通常、各正常性チェックは実際のテストに完全に固有のものであり、IHealthChecksBuilder 拡張メソッドを使用して構成されます。

次の例は、依存関係の挿入を使用して構成オブジェクトを取得する正常性チェックのサンプルを示したものです。

public class SampleHealthCheckWithDI : IHealthCheck
{
    private readonly SampleHealthCheckWithDiConfig _config;

    public SampleHealthCheckWithDI(SampleHealthCheckWithDiConfig config)
        => _config = config;

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // use _config ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

SampleHealthCheckWithDiConfig と正常性チェックをサービス コンテナーに追加する必要があります。

builder.Services.AddSingleton<SampleHealthCheckWithDiConfig>(new SampleHealthCheckWithDiConfig
{
    BaseUriToCheck = new Uri("https://sample.contoso.com/api/")
});
builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheckWithDI>(
        "With Dependency Injection",
        tags: new[] { "inject" });

UseHealthChecks と MapHealthChecks

呼び出し元が正常性チェックにアクセスできるようにするには、次の 2 つの方法があります。

  • UseHealthChecks は、ミドルウェア パイプラインで正常性チェック要求を処理するためのミドルウェアを登録します。
  • MapHealthChecks は、正常性チェック エンドポイントを登録します。 エンドポイントは、アプリ内の他のエンドポイントと合わせてマッチされ実行されます。

UseHealthChecks 上で MapHealthChecks を使用する利点は、認可のようなエンドポイント認識ミドルウェアを使用し、マッチ ポリシーをより細かい粒度で制御できる点です。 MapHealthChecks 上で UseHealthChecks を使用する主な利点は、ミドルウェア パイプラインで正常性チェックが実行される場所を正確に制御できることです。

UseHealthChecks:

  • 要求が正常性チェック エンドポイントとマッチすると、パイプラインを終了させます。 ショートサーキットはログやその他のミドルウェアなどの不要な作業を防ぐため、多くの場合に望ましいものです。
  • 主に、パイプラインで正常性チェック ミドルウェアを構成するために使用されます。
  • null または空の PathString を持つポート上の任意のパスとマッチできます。 指定したポートに対して行われた任意の要求に対して正常性チェックの実行を許可します。
  • ソース コード

MapHealthChecks は次のことを許可します。

  • ShortCircuit を呼び出して、要求が正常性チェック エンドポイントとマッチした場合のパイプラインの終了。 たとえば、「 app.MapHealthChecks("/healthz").ShortCircuit(); 」のように入力します。 詳しくは、「ルーティング後のミドルウェアのショートサーキット」を参照してください。
  • 正常性チェック用の特定のルートまたはエンドポイントのマッピング。
  • 正常性チェック エンドポイントにアクセスできる URL またはパスのカスタマイズ。
  • ルートまたは構成が異なる複数の正常性チェック エンドポイントのマッピング。 複数エンドポイントのサポート:
    • さまざまな種類の正常性チェックまたはコンポーネントに対して個別のエンドポイントを有効にします。
    • アプリの正常性のさまざまな側面を区別したり、正常性チェックのサブセットに特定の構成を適用したりするために使用されます。
  • ソース コード

その他のリソース

注意

この記事は部分的に人工知能を活用して作成しました。 公開する前に作成者が内容を確認し、必要に応じて修正しました。 AI によって生成されたコンテンツを Microsoft Learn で使用するための原則に関するページを参照してください。

ASP.NET Core からは、アプリ インフラストラクチャ コンポーネントの正常性を報告するための正常性チェック ミドルウェアとライブラリが提供されます。

正常性チェックは HTTP エンドポイントとしてアプリによって公開されます。 正常性チェック エンドポイントは、さまざまなリアルタイム監視シナリオに合わせて設定できます。

  • 正常性プローブは、アプリの状態を確認する目的でコンテナー オーケストレーターとロード バランサーによって使用できます。 たとえば、正常性チェックで問題が確認された場合、コンテナー オーケストレーターは実行中の展開を停止したり、コンテナーを再起動したりします。 ロード バランサーはアプリの異常に対処するため、問題のあるインスタンスから正常なインスタンスにトラフィック経路を変更することがあります。
  • メモリ、ディスク、その他の物理サーバー リソースの使用を監視し、正常性の状態を確認できます。
  • 正常性チェックでは、データベースや外部サービス エンドポイントなど、アプリの依存関係をテストし、それらが利用できることと正常に機能していることを確認できます。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

サンプル アプリには、この記事で説明されているシナリオの例が含まれています。 所与のシナリオに対してサンプル アプリを実行するには、コマンド シェルでプロジェクトのフォルダーから dotnet run コマンドを使用します。 サンプル アプリの詳しい使用方法については、サンプル アプリの README.md ファイルとこの記事のシナリオ説明を参照してください。

前提条件

正常性チェックは通常、アプリの状態を確認する目的で、外部の監視サービスまたはコンテナー オーケストレーターと共に使用されます。 正常性チェックをアプリに追加する前に、使用する監視システムを決定します。 監視システムからは、作成する正常性チェックの種類とそのエンドポイントの設定方法が指示されます。

Microsoft.AspNetCore.Diagnostics.HealthChecks パッケージは、ASP.NET Core アプリに対して暗黙的に参照されます。 Entity Framework Core を使用して正常性チェックを実行するには、Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore パッケージへの参照を追加します。

サンプル アプリからは、いくつかのシナリオで正常性チェックを実演するスタートアップ コードが提供されます。 データベース プローブ シナリオでは、AspNetCore.Diagnostics.HealthChecks を使用して、データベース接続の正常性をチェックします。 DbContext プローブ シナリオでは、EF CoreDbContext を使用して、データベースがチェックされます。 データベース シナリオを探索するために、サンプル アプリでは次のことが行われます:

Note

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

もう 1 つの正常性チェックのシナリオでは、1 つの管理ポートに正常性チェックを絞り込む方法が実演されます。 このサンプル アプリでは、管理 URL と管理ポートを含む Properties/launchSettings.json ファイルを作成する必要があります。 詳細については、「ポート別のフィルター処理」セクションを参照してください。

基本的な正常性プローブ

多くのアプリでは、アプリが要求を処理できること (活動性) を報告する基本的な正常性チェック構成で十分にアプリの状態を検出できます。

基本の構成では、正常性チェック サービスを登録し、正常性チェック ミドルウェアを呼び出します。このミドルウェアが特定の URL エンドポイントにおける正常性を返します。 既定では、特定の依存関係またはサブシステムをテストする正常性チェックは登録されていません。 正常性エンドポイント URL で応答できる場合、そのアプリは正常であると見なされます。 既定の応答ライターによって、プレーンテキストの応答として状態 (HealthStatus) がクライアントに書き込まれます。このとき、状態として HealthStatus.HealthyHealthStatus.Degraded、または HealthStatus.Unhealthy が示されます。

正常性チェック サービスを Startup.ConfigureServicesAddHealthChecks に登録します。 Startup.ConfigureMapHealthChecks を呼び出して、正常性チェック エンドポイントを作成します。

サンプル アプリでは、正常性チェック エンドポイントは /health で作成されます (BasicStartup.cs)。

public class BasicStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHealthChecks();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHealthChecks("/health");
        });
    }
}

サンプル アプリを使用して基本的な構成シナリオを実行するには、コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario basic

Docker の例

Docker からは、組み込み HEALTHCHECK ディレクティブが提供されます。これを使用し、基本的な正常性チェック構成を使用するアプリの状態を確認できます。

HEALTHCHECK CMD curl --fail http://localhost:5000/health || exit

正常性チェックを作成する

正常性チェックは IHealthCheck インターフェイスを実装することで作成されます。 CheckHealthAsync メソッドによって、HealthyDegradedUnhealthy のいずれかの正常性を示す HealthCheckResult が返されます。 この結果が構成可能な状態コードと共にプレーンテキストの応答として書き込まれます (構成の説明は「正常性チェック オプション」セクションにあります)。 HealthCheckResult からは、任意のキーと値のペアを返すこともできます。

次の ExampleHealthCheck クラスからは、正常性チェックのレイアウトがどのようなものかがわかります。 正常性チェックのロジックが CheckHealthAsync メソッドに配置されています。 次の例では、ダミー変数 healthCheckResultHealthytrue に設定されます。 healthCheckResultHealthy の値が false に設定されている場合、HealthCheckRegistration.FailureStatus 状態が返されます。

public class ExampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var healthCheckResultHealthy = true;

        if (healthCheckResultHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(context.Registration.FailureStatus, 
            "An unhealthy result."));
    }
}

チェック中に CheckHealthAsync から例外がスローされた場合、新しい HealthReportEntry が、その HealthReportEntry.StatusFailureStatus に設定された状態で返されます。これは、AddCheck によって定義され (「正常性チェック サービスを登録する」セクションを参照)、最初にチェックの失敗の原因となった内部例外が含まれます。 Description は例外のメッセージに設定されます。

正常性チェック サービスを登録する

Startup.ConfigureServicesAddCheck によって ExampleHealthCheck 型が正常性チェック サービスに追加されます。

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>("example_health_check");

次の例にある AddCheck オーバーロードでは、正常性チェックでエラーが報告されると、レポートにエラー状態 (HealthStatus) が設定されます。 エラー状態が null (既定) に設定された場合、HealthStatus.Unhealthy が報告されます。 このオーバーロードはライブラリ作成者にとって便利です。この設定に正常性チェック実装が従う場合、正常性チェック エラーが発生したとき、ライブラリによって指示されるエラー状態がアプリによって適用されます。

タグを使用し、正常性チェックをフィルター処理できます (詳細は「正常性チェックをフィルター処理する」セクションにあります)。

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>(
        "example_health_check",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "example" });

AddCheck では、lambda 関数も実行できます。 次の例では、正常性チェック名に「Example」が指定されいます。このチェックでは状態として常に正常が返されます。

services.AddHealthChecks()
    .AddCheck("Example", () =>
        HealthCheckResult.Healthy("Example is OK!"), tags: new[] { "example" });

AddTypeActivatedCheck を呼び出して、正常性チェックの実装に引数を渡します。 次の例では、TestHealthCheckWithArgsCheckHealthAsync の呼び出し時に使用する整数と文字列を受け入れます。

private class TestHealthCheckWithArgs : IHealthCheck
{
    public TestHealthCheckWithArgs(int i, string s)
    {
        I = i;
        S = s;
    }

    public int I { get; set; }

    public string S { get; set; }

    public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, 
        CancellationToken cancellationToken = default)
    {
        ...
    }
}

TestHealthCheckWithArgs は実装に渡された整数と文字列を使用して AddTypeActivatedCheck を呼び出すことによって登録されます。

services.AddHealthChecks()
    .AddTypeActivatedCheck<TestHealthCheckWithArgs>(
        "test", 
        failureStatus: HealthStatus.Degraded, 
        tags: new[] { "example" }, 
        args: new object[] { 5, "string" });

正常性チェックのルーティングを使用する

Startup.Configure で、エンドポイントの URL または相対パスを使用して、エンドポイント ビルダーで MapHealthChecks を呼び出します。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
});

ホストが必要

RequireHost を呼び出して、正常性チェック エンドポイントに許可されている 1 つ以上のホストを指定します。 ホストは、punycode ではなく Unicode にする必要があります。また、ポートを含めることができます。 コレクションが指定されていない場合は、任意のホストを使用できます。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("www.contoso.com:5001");
});

詳細については、「ポート別のフィルター処理」セクションを参照してください。

承認が必要

RequireAuthorization を呼び出して、正常性チェック要求エンドポイントで承認ミドルウェアを実行します。 RequireAuthorization のオーバーロードには 1 つ以上の承認ポリシーを使用できます。 ポリシーが指定されていない場合は、既定の承認ポリシーが使用されます。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireAuthorization();
});

クロスオリジン要求 (CORS) の有効化

ブラウザーから手動で正常性チェックを実行することは一般的な使用シナリオではありませんが、正常性チェック エンドポイントで RequireCors を呼び出して CORS ミドルウェアを有効にすることができます。 RequireCors のオーバーロードには、CORS ポリシー ビルダーのデリゲート (CorsPolicyBuilder) またはポリシー名を使用できます。 ポリシーが指定されていない場合は、既定の CORS ポリシーが使用されます。 詳細については、「ASP.NET Core でクロスオリジン要求 (CORS) を有効にする」を参照してください。

正常性チェック オプション

HealthCheckOptions では、正常性チェックの動作をカスタマイズできます。

正常性チェックをフィルター処理する

既定では、正常性チェック ミドルウェアでは、登録されている正常性チェックがすべて実行されます。 正常性チェックのサブセットを実行するには、Predicate オプションにブール値を返す関数を指定します。 次の例では、関数の条件文にあるそのタグ (bar_tag) により Bar 正常性チェックが除外されます。true は、正常性チェックの Tags プロパティが foo_tagbaz_tag に一致した場合にのみ返されます。

Startup.ConfigureServicesの場合:

services.AddHealthChecks()
    .AddCheck("Foo", () =>
        HealthCheckResult.Healthy("Foo is OK!"), tags: new[] { "foo_tag" })
    .AddCheck("Bar", () =>
        HealthCheckResult.Unhealthy("Bar is unhealthy!"), tags: new[] { "bar_tag" })
    .AddCheck("Baz", () =>
        HealthCheckResult.Healthy("Baz is OK!"), tags: new[] { "baz_tag" });

Startup.Configure では、Predicate によって 'Bar' 正常性チェックが除外されます。 Foo と Baz のみが実行されます。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("foo_tag") ||
            check.Tags.Contains("baz_tag")
    });
});

HTTP 状態コードをカスタマイズする

ResultStatusCodes を使用し、HTTP 状態コードに対する正常性状態のマッピングをカスタマイズします。 次の StatusCodes 代入はミドルウェアによって使用される既定値です。 要件に合わせて状態コード値を変更します。

Startup.Configureの場合:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResultStatusCodes =
        {
            [HealthStatus.Healthy] = StatusCodes.Status200OK,
            [HealthStatus.Degraded] = StatusCodes.Status200OK,
            [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
        }
    });
});

キャッシュ ヘッダーを非表示にする

AllowCachingResponses によって、応答キャッシュを禁止する目的で、正常性チェック ミドルウェアによって HTTP ヘッダーがプローブ応答に追加されるかどうかが制御されます。 値が false (既定) の場合、応答キャッシュを禁止する目的で、ミドルウェアによってヘッダー Cache-ControlExpiresPragma が設定またはオーバーライドされます。 値が true の場合、応答のキャッシュ ヘッダーがミドルウェアによって変更されることはありません。

Startup.Configureの場合:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        AllowCachingResponses = true
    });
});

出力をカスタマイズする

Startup.Configure で、HealthCheckOptions.ResponseWriter オプションを、応答を書き込むためのデリゲートに設定します。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
});

既定の委任では、文字列値 HealthReport.Status を含む、最小のプレーンテキスト応答が書き込まれます。 次のカスタム デリゲートでは、カスタム JSON 応答が出力されます。

サンプル アプリの最初の例は、System.Text.Json の使用方法を示しています。

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions
    {
        Indented = true
    };

    using (var stream = new MemoryStream())
    {
        using (var writer = new Utf8JsonWriter(stream, options))
        {
            writer.WriteStartObject();
            writer.WriteString("status", result.Status.ToString());
            writer.WriteStartObject("results");
            foreach (var entry in result.Entries)
            {
                writer.WriteStartObject(entry.Key);
                writer.WriteString("status", entry.Value.Status.ToString());
                writer.WriteString("description", entry.Value.Description);
                writer.WriteStartObject("data");
                foreach (var item in entry.Value.Data)
                {
                    writer.WritePropertyName(item.Key);
                    JsonSerializer.Serialize(
                        writer, item.Value, item.Value?.GetType() ??
                        typeof(object));
                }
                writer.WriteEndObject();
                writer.WriteEndObject();
            }
            writer.WriteEndObject();
            writer.WriteEndObject();
        }

        var json = Encoding.UTF8.GetString(stream.ToArray());

        return context.Response.WriteAsync(json);
    }
}

2 番目の例では、Newtonsoft.Json の使用方法を示します。

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json";

    var json = new JObject(
        new JProperty("status", result.Status.ToString()),
        new JProperty("results", new JObject(result.Entries.Select(pair =>
            new JProperty(pair.Key, new JObject(
                new JProperty("status", pair.Value.Status.ToString()),
                new JProperty("description", pair.Value.Description),
                new JProperty("data", new JObject(pair.Value.Data.Select(
                    p => new JProperty(p.Key, p.Value))))))))));

    return context.Response.WriteAsync(
        json.ToString(Formatting.Indented));
}

サンプル アプリでは、CustomWriterStartup.csSYSTEM_TEXT_JSONプリプロセッサ ディレクティブをコメント アウトして、Newtonsoft.Json バージョンの WriteResponse を有効にします。

正常性チェック API には、複雑な JSON の戻り値の形式に対する組み込みのサポートが用意されていません。この形式は、選択した監視システムに固有のものであるためです。 必要に応じて、上記の例の応答をカスタマイズします。 System.Text.Json を使用した JSON シリアル化の詳細については、.NET で JSON をシリアル化および逆シリアル化する方法に関する記事をご覧ください。

データベース プローブ

正常性チェックでは、データベースが通常どおり応答しているかどうかを示すブール値テストとして実行されるよう、データベース クエリを指定できます。

このサンプル アプリでは、ASP.NET Core アプリ用の正常性チェック ライブラリ AspNetCore.Diagnostics.HealthChecks を使用して、SQL Server データベースの正常性チェックを実行します。 AspNetCore.Diagnostics.HealthChecks によってデータベースに対して SELECT 1 クエリが実行され、データベースへの接続が正常であることが確認されます。

警告

クエリでデータベース接続を確認するとき、すぐに返されるクエリを選択します。 このクエリ手法には、データベースをオーバーロードし、そのパフォーマンスを低下させるというリスクがあります。 ほとんどの場合、テスト クエリは実行する必要がありません。 データベースに正常に接続できれば十分です。 クエリを実行する必要があれば、SELECT 1 など、単純な SELECT クエリを選択してください。

AspNetCore.HealthChecks.SqlServer へのパッケージ参照を含めます。

サンプル アプリの appsettings.json ファイルに有効なデータベース接続文字列を指定します。 このアプリでは HealthCheckSample という名前の SQL Server データベースが使用されます。

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=HealthCheckSample;Trusted_Connection=True;MultipleActiveResultSets=true;ConnectRetryCount=0"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "Console": {
      "IncludeScopes": "true"
    }
  },
  "AllowedHosts": "*"
}

正常性チェック サービスを Startup.ConfigureServicesAddHealthChecks に登録します。 サンプル アプリでは、データベースの接続文字列 (DbHealthStartup.cs) を利用して AddSqlServer メソッドを呼び出します。

services.AddHealthChecks()
    .AddSqlServer(Configuration["ConnectionStrings:DefaultConnection"]);

正常性チェック エンドポイントを作成するには、Startup.ConfigureMapHealthChecks を呼び出します。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

サンプル アプリを使用してデータベース プローブ シナリオを実行するには、コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario db

Note

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

Entity Framework Core DbContext プローブ

DbContext チェックでは、EF CoreDbContext に対して構成されているデータベースとアプリとが通信できることが確認されます。 DbContext チェックは、次のようなアプリでサポートされています。

AddDbContextCheck<TContext> によって DbContext の正常性チェックが登録されます。 DbContextTContext としてメソッドに指定されます。 オーバーロードはエラー状態、タグ、カスタム テスト クエリの設定に利用できます。

既定では:

  • DbContextHealthCheck は、EF Core の CanConnectAsyncメソッドを呼び出します。 AddDbContextCheck メソッドのオーバーロードを使用して正常性を確認するときに実行される操作をカスタマイズできます。
  • 正常性チェックの名前は TContext 型の名前になります。

サンプル アプリでは、AppDbContextAddDbContextCheck に提供され、Startup.ConfigureServices でサービスとして登録されます (DbContextHealthStartup.cs)。

services.AddHealthChecks()
    .AddDbContextCheck<AppDbContext>();

services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(
        Configuration["ConnectionStrings:DefaultConnection"]);
});

正常性チェック エンドポイントを作成するには、Startup.ConfigureMapHealthChecks を呼び出します。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

サンプル アプリを利用して DbContext プローブ シナリオを実行するには、接続文字列によって指定されるデータベースが SQL Server インスタンスに存在しないことを確認します。 データベースが存在する場合、それを削除します。

コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario dbcontext

アプリの実行後、ブラウザーで /health エンドポイントに要求することで正常性状態を確認します。 データベースと AppDbContext は存在しません。そこで、アプリによって次の応答が返されます。

Unhealthy

サンプル アプリにデータベースを作成させます。 /createdatabase に要求を行います。 アプリからの応答は次のようになります。

Creating the database...
Done!
Navigate to /health to see the health status.

/health エンドポイントに要求を行います。 データベースとコンテキストが存在します。そのため、アプリによって次の応答が返されます。

Healthy

サンプル アプリにデータベースを削除させます。 /deletedatabase に要求を行います。 アプリからの応答は次のようになります。

Deleting the database...
Done!
Navigate to /health to see the health status.

/health エンドポイントに要求を行います。 アプリから異常という応答が返されます。

Unhealthy

対応性と活動性に区分されるプローブ

一部のホスティング シナリオでは、2 つのアプリ状態を区別する一組の正常性チェックが使用されます。

  • "対応性" は、アプリが通常どおり実行されているが、要求を受け取る準備ができていないのか、あるいはそうではないのかを示します。
  • "活動性" は、アプリがクラッシュしたため、再起動する必要があるのかどうかを示します。

次に例を示します。アプリでは、大きな構成ファイルをダウンロードしないと、要求を処理する準備ができません。 初回ダウンロードに失敗した場合、アプリを再起動することは望みません。アプリはファイルのダウンロードを数回再試行する可能性があるためです。 liveness probe を使用し、プロセスの活動性を記述します。他のチェックは実行されません。 また、構成ファイルのダウンロードが完了する前は、要求がアプリに送信されないようにします。 "対応性プローブ" を使用し、ダウンロードが成功し、要求を受け取る準備がアプリにできるまで、"準備できていない" 状態を示します。

サンプル アプリには、ホステッド サービスの長時間実行スタートアップ タスクの完了を報告する正常性チェックが含まれています。 StartupHostedServiceHealthCheck によって StartupTaskCompleted というプロパティが公開されます。ホステッド サービスでは長時間実行タスクの完了時にこのプロパティを true に設定できます (StartupHostedServiceHealthCheck.cs)。

public class StartupHostedServiceHealthCheck : IHealthCheck
{
    private volatile bool _startupTaskCompleted = false;

    public string Name => "slow_dependency_check";

    public bool StartupTaskCompleted
    {
        get => _startupTaskCompleted;
        set => _startupTaskCompleted = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        if (StartupTaskCompleted)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("The startup task is finished."));
        }

        return Task.FromResult(
            HealthCheckResult.Unhealthy("The startup task is still running."));
    }
}

長時間実行バックグラウンド タスクはホステッド サービスによって開始されます (Services/StartupHostedService)。 タスクが終わると、StartupHostedServiceHealthCheck.StartupTaskCompletedtrue に設定されます。

public class StartupHostedService : IHostedService, IDisposable
{
    private readonly int _delaySeconds = 15;
    private readonly ILogger _logger;
    private readonly StartupHostedServiceHealthCheck _startupHostedServiceHealthCheck;

    public StartupHostedService(ILogger<StartupHostedService> logger,
        StartupHostedServiceHealthCheck startupHostedServiceHealthCheck)
    {
        _logger = logger;
        _startupHostedServiceHealthCheck = startupHostedServiceHealthCheck;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is starting.");

        // Simulate the effect of a long-running startup task.
        Task.Run(async () =>
        {
            await Task.Delay(_delaySeconds * 1000);

            _startupHostedServiceHealthCheck.StartupTaskCompleted = true;

            _logger.LogInformation("Startup Background Service has started.");
        });

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is stopping.");

        return Task.CompletedTask;
    }

    public void Dispose()
    {
    }
}

ホステッド サービスと共に Startup.ConfigureServices で正常性チェックが AddCheck に登録されます。 ホステッド サービスでは正常性チェックにプロパティを設定する必要があるため、正常性チェックはサービス コンテナーにも登録されます (LivenessProbeStartup.cs)。

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

正常性チェック エンドポイントを作成するには、Startup.ConfigureMapHealthChecks を呼び出します。 サンプル アプリでは、正常性チェック エンドポイントは次の場所に作成されます。

  • 対応性チェックの場合は /health/ready。 対応性チェックでは、ready タグが与えられているものに正常性チェックが絞り込まれます。
  • 活動性チェックの場合は /health/live。 活動性チェックでは、HealthCheckOptions.Predicatefalse を返すことで StartupHostedServiceHealthCheck が除外されます (詳細については、「正常性チェックをフィルター処理する」を参照してください)

次のコード例の内容:

  • 対応性チェックでは、登録されているすべてのチェックが 'ready' タグと共に使用されます。
  • Predicate では、すべてのチェックが除外され、200-Ok が返されます。
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

サンプル アプリを使用して対応性/活動性構成シナリオを実行するには、コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario liveness

ブラウザーで、15 秒が経過するまで /health/ready に数回アクセスします。 正常性チェックにより最初の 15 秒に対して Unhealthy が報告されます。 15 秒後、エンドポイントから Healthy が報告されます。これは、ホステッド サービスによる長時間実行タスクが完了したことを反映しています。

この例では、2 秒間の遅延で最初の対応性チェックを実行する正常性チェック パブリッシャー (IHealthCheckPublisher の実装) も作成されます。 詳細については、「正常性チェック パブリッシャー」セクションをご覧ください。

Kubernetes の例

対応性チェックと活動性チェックを使い分けることは、Kubernetes などの環境で便利です。 Kubernetes では、要求を受け入れる前に、基礎をなすデータベースの可用性テストなど、時間のかかるスタートアップ作業の実行がアプリに要求されることがあります。 別個のチェックを利用することで、アプリは機能しているがまだ準備ができていないか、あるいはアプリが起動に失敗したかをオーケストレーターは区別できます。 Kubernetes の対応性プローブと活動性プローブに関する詳細については、Kubernetes ドキュメントの「Configure Liveness and Readiness Probes」 (活動性プローブと対応性プローブを設定する) を参照してください。

次の例では、Kubernetes 対応性プローブの構成を確認できます。

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /health/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

カスタム応答ライターを含むメトリック ベースのプローブ

このサンプル アプリでは、カスタム応答ライターを含む、メモリ正常性チェックを確認できます。

与えられたしきい値を超えるメモリがアプリで使用された場合、MemoryHealthCheck からは劣化状態が報告されます (このサンプル アプリでは 1 GB)。 HealthCheckResult にはアプリのガベージ コレクター (GC) 情報が含まれています (MemoryHealthCheck.cs)。

public class MemoryHealthCheck : IHealthCheck
{
    private readonly IOptionsMonitor<MemoryCheckOptions> _options;

    public MemoryHealthCheck(IOptionsMonitor<MemoryCheckOptions> options)
    {
        _options = options;
    }

    public string Name => "memory_check";

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var options = _options.Get(context.Registration.Name);

        // Include GC information in the reported diagnostics.
        var allocated = GC.GetTotalMemory(forceFullCollection: false);
        var data = new Dictionary<string, object>()
        {
            { "AllocatedBytes", allocated },
            { "Gen0Collections", GC.CollectionCount(0) },
            { "Gen1Collections", GC.CollectionCount(1) },
            { "Gen2Collections", GC.CollectionCount(2) },
        };
        var status = (allocated < options.Threshold) ?
            HealthStatus.Healthy : context.Registration.FailureStatus;

        return Task.FromResult(new HealthCheckResult(
            status,
            description: "Reports degraded status if allocated bytes " +
                $">= {options.Threshold} bytes.",
            exception: null,
            data: data));
    }
}

正常性チェック サービスを Startup.ConfigureServicesAddHealthChecks に登録します。 AddCheck に渡して正常性チェックを有効にする代わりに、MemoryHealthCheck がサービスとして登録されます。 IHealthCheck が登録されたサービスはすべて、正常性チェック サービスとミドルウェアで利用できます。 正常性チェック サービスはシングルトン サービスとして登録することをお勧めします。

サンプル アプリの CustomWriterStartup.cs 内:

services.AddHealthChecks()
    .AddMemoryHealthCheck("memory");

正常性チェック エンドポイントを作成するには、Startup.ConfigureMapHealthChecks を呼び出します。 WriteResponse デリゲートが ResponseWriter プロパティに与えられることで、正常性チェックの実行時に、カスタム JSON 応答が出力されます。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
}

WriteResponse デリゲートによって、CompositeHealthCheckResult が JSON オブジェクトに書式設定され、正常性チェック応答の JSON 出力が生成されます。 詳細については、「出力をカスタマイズする」セクションをご覧ください。

サンプル アプリを使用してカスタム応答ライターを含むメトリックベースのプローブを実行するには、コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario writer

Note

AspNetCore.Diagnostics.HealthChecks には、ディスク ストレージや最大値活動性のチェックなど、メトリックベースの正常性チェック シナリオが含まれます。

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

ポート別のフィルター処理

MapHealthChecks でポートを指定する URL パターンを使用して RequireHost を呼び出し、指定されたポートに正常性チェック要求を制限します。 この方法は通常、サービスを監視するためのポートを公開する目的で、コンテナー環境で使用されます。

サンプル アプリによって、環境変数構成プロバイダーを使用してポートが設定されます。 ポートは launchSettings.json ファイルに設定され、環境変数を介して構成プロバイダーに渡されます。 管理ポートで要求を待つようにサーバーを設定する必要もあります。

サンプル アプリを使用し、管理ポート設定を実演するには、Properties フォルダーで launchSettings.json ファイルを作成します。

サンプル アプリの次の Properties/launchSettings.json ファイルは、サンプル アプリのプロジェクト ファイルに含まれていないため、手動で作成する必要があります。

{
  "profiles": {
    "SampleApp": {
      "commandName": "Project",
      "commandLineArgs": "",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_URLS": "http://localhost:5000/;http://localhost:5001/",
        "ASPNETCORE_MANAGEMENTPORT": "5001"
      },
      "applicationUrl": "http://localhost:5000/"
    }
  }
}

正常性チェック サービスを Startup.ConfigureServicesAddHealthChecks に登録します。 Startup.ConfigureMapHealthChecks を呼び出して、正常性チェック エンドポイントを作成します。

サンプル アプリでは、Startup.Configure のエンドポイントで RequireHost を呼び出すと、構成の管理ポートが指定されます。

endpoints.MapHealthChecks("/health")
    .RequireHost($"*:{Configuration["ManagementPort"]}");

エンドポイントは、Startup.Configure のサンプル アプリで作成されます。 次のコード例の内容:

  • 対応性チェックでは、登録されているすべてのチェックが 'ready' タグと共に使用されます。
  • Predicate では、すべてのチェックが除外され、200-Ok が返されます。
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

Note

管理ポートをコードに明示的に設定することで、サンプル アプリで launchSettings.json ファイルを作成することを回避できます。 HostBuilder が作成される Program.cs で、ListenAnyIP の呼び出しを追加し、アプリの管理ポート エンドポイントを用意します。 ManagementPortStartup.csConfigure で、RequireHost を使用して管理ポートを指定します。

Program.cs:

return new HostBuilder()
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseKestrel()
            .ConfigureKestrel(serverOptions =>
            {
                serverOptions.ListenAnyIP(5001);
            })
            .UseStartup(startupType);
    })
    .Build();

ManagementPortStartup.cs:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("*:5001");
});

サンプル アプリを使用して管理ポート構成シナリオを実行するには、コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario port

正常性チェック ライブラリを配布する

正常性チェックをライブラリとして配布するには:

  1. スタンドアロン クラスとして IHealthCheck インターフェイスを実装する正常性チェックを記述します。 このクラスは、設定データにアクセスする目的で依存関係挿入 (DI)、型のアクティブ化、名前付きオプションに依存できます。

    CheckHealthAsync の正常性チェックのロジックでは、次のようになります。

    • data1data2 は、プローブの正常性チェック ロジックを実行するためにメソッドで使用されます。
    • AccessViolationException が処理されます。

    AccessViolationException が発生すると、HealthCheckResult とともに FailureStatus が返され、ユーザーは正常性チェックの失敗状態を構成できます。

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    namespace SampleApp
    {
        public class ExampleHealthCheck : IHealthCheck
        {
            private readonly string _data1;
            private readonly int? _data2;
    
            public ExampleHealthCheck(string data1, int? data2)
            {
                _data1 = data1 ?? throw new ArgumentNullException(nameof(data1));
                _data2 = data2 ?? throw new ArgumentNullException(nameof(data2));
            }
    
            public async Task<HealthCheckResult> CheckHealthAsync(
                HealthCheckContext context, CancellationToken cancellationToken)
            {
                try
                {
                    return HealthCheckResult.Healthy();
                }
                catch (AccessViolationException ex)
                {
                    return new HealthCheckResult(
                        context.Registration.FailureStatus,
                        description: "An access violation occurred during the check.",
                        exception: ex,
                        data: null);
                }
            }
        }
    }
    
  2. 拡張メソッドを記述します。拡張メソッドを使用するアプリがその Startup.Configure メソッドで呼び出すパラメーターを指定します。 次の例では、次の正常性チェック メソッド シグネチャを想定します。

    ExampleHealthCheck(string, string, int )
    

    先のシグネチャは、正常性チェック プローブ ロジックを処理する目的で ExampleHealthCheck に追加データが要求されることを示しています。 正常性チェックが拡張メソッドに登録されたときに正常性チェック インスタンスを作成するための委任にデータが提供されます。 次の例では、呼び出し元によって次が任意で指定されます。

    • 正常性チェック名 (name)。 null の場合、example_health_check が使用されます。
    • 正常性チェックの文字列データ ポイント (data1)。
    • 正常性チェックの整数データ ポイント (data2)。 null の場合、1 が使用されます。
    • エラー状態 (HealthStatus)。 既定値は、null です。 null の場合、エラー状態に対して HealthStatus.Unhealthy が報告されます。
    • タグ (IEnumerable<string>)。
    using System.Collections.Generic;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    public static class ExampleHealthCheckBuilderExtensions
    {
        const string DefaultName = "example_health_check";
    
        public static IHealthChecksBuilder AddExampleHealthCheck(
            this IHealthChecksBuilder builder,
            string name = default,
            string data1,
            int data2 = 1,
            HealthStatus? failureStatus = default,
            IEnumerable<string> tags = default)
        {
            return builder.Add(new HealthCheckRegistration(
                name ?? DefaultName,
                sp => new ExampleHealthCheck(data1, data2),
                failureStatus,
                tags));
        }
    }
    

正常性チェック パブリッシャー

サービス コンテナーに IHealthCheckPublisher が追加されると、正常性チェック システムにより定期的に正常性チェックが実行され、結果と共に PublishAsync が呼び出されます。 これは、正常性を判断する目的で監視システムを定期的に呼び出すことを各プロセスに求めるプッシュベースの監視システム シナリオで便利です。

IHealthCheckPublisher インターフェイスには単一メソッドが与えられます。

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions を使うと次を設定できます。

  • Delay:アプリが起動した後、IHealthCheckPublisher インスタンスを実行する前に適用される初期遅延です。 遅延はスタートアップ時に一度だけ適用され、以降の繰り返しには適用されません。 既定値は 5 秒です。
  • Period:IHealthCheckPublisher を実行する期間です。 既定値は 30 秒です。
  • Predicate:Predicatenull (既定値) の場合、正常性チェック パブリッシャー サービスにより登録済みのすべての正常性チェックが実行されます。 正常性チェックのサブセットを実行するには、チェックのセットをフィルター処理する関数を指定します。 述語は期間ごとに評価されます。
  • Timeout:すべての IHealthCheckPublisher インスタンスに対する正常性チェックの実行のタイムアウトです。 タイムアウトなしで実行するには InfiniteTimeSpan を使います。 既定値は 30 秒です。

サンプル アプリでは、ReadinessPublisherIHealthCheckPublisher の実装です。 正常性チェックの状態は、チェックごとに以下のログ レベルでログに記録されます。

public class ReadinessPublisher : IHealthCheckPublisher
{
    private readonly ILogger _logger;

    public ReadinessPublisher(ILogger<ReadinessPublisher> logger)
    {
        _logger = logger;
    }

    // The following example is for demonstration purposes only. Health Checks
    // Middleware already logs health checks results. A real-world readiness
    // check in a production app might perform a set of more expensive or
    // time-consuming checks to determine if other resources are responding
    // properly.
    public Task PublishAsync(HealthReport report,
        CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            _logger.LogInformation("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }
        else
        {
            _logger.LogError("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }

        cancellationToken.ThrowIfCancellationRequested();

        return Task.CompletedTask;
    }
}

サンプル アプリの LivenessProbeStartup の例では、対応性チェック StartupHostedService にはスタートアップの遅延が 2 秒間あり、30 秒ごとにチェックが実行されます。 IHealthCheckPublisher の実装をアクティブ化するために、サンプルでは ReadinessPublisher をシングルトン サービスとして依存関係の挿入 (DI) コンテナーに登録しています。

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

Note

AspNetCore.Diagnostics.HealthChecks には、Application Insights など、いくつかのシステムのパブリッシャーが含まれます。

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

MapWhen で正常性チェックを制限する

MapWhen を使用して、正常性チェック エンドポイントの要求パイプラインを条件付きで分岐します。

次の例では、api/HealthCheck エンドポイントに対して GET 要求が受信された場合に、MapWhen が要求パイプラインを分岐して正常性チェック ミドルウェアをアクティブ化します。

app.MapWhen(
    context => context.Request.Method == HttpMethod.Get.Method && 
        context.Request.Path.StartsWith("/api/HealthCheck"),
    builder => builder.UseHealthChecks());

app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
});

詳細については、「ASP.NET Core のミドルウェア」を参照してください。

ASP.NET Core からは、アプリ インフラストラクチャ コンポーネントの正常性を報告するための正常性チェック ミドルウェアとライブラリが提供されます。

正常性チェックは HTTP エンドポイントとしてアプリによって公開されます。 正常性チェック エンドポイントは、さまざまなリアルタイム監視シナリオに合わせて設定できます。

  • 正常性プローブは、アプリの状態を確認する目的でコンテナー オーケストレーターとロード バランサーによって使用できます。 たとえば、正常性チェックで問題が確認された場合、コンテナー オーケストレーターは実行中の展開を停止したり、コンテナーを再起動したりします。 ロード バランサーはアプリの異常に対処するため、問題のあるインスタンスから正常なインスタンスにトラフィック経路を変更することがあります。
  • メモリ、ディスク、その他の物理サーバー リソースの使用を監視し、正常性の状態を確認できます。
  • 正常性チェックでは、データベースや外部サービス エンドポイントなど、アプリの依存関係をテストし、それらが利用できることと正常に機能していることを確認できます。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

サンプル アプリには、この記事で説明されているシナリオの例が含まれています。 所与のシナリオに対してサンプル アプリを実行するには、コマンド シェルでプロジェクトのフォルダーから dotnet run コマンドを使用します。 サンプル アプリの詳しい使用方法については、サンプル アプリの README.md ファイルとこの記事のシナリオ説明を参照してください。

前提条件

正常性チェックは通常、アプリの状態を確認する目的で、外部の監視サービスまたはコンテナー オーケストレーターと共に使用されます。 正常性チェックをアプリに追加する前に、使用する監視システムを決定します。 監視システムからは、作成する正常性チェックの種類とそのエンドポイントの設定方法が指示されます。

Microsoft.AspNetCore.Diagnostics.HealthChecks パッケージは、ASP.NET Core アプリに対して暗黙的に参照されます。 Entity Framework Core を使用して正常性チェックを実行するには、Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore パッケージへのパッケージ参照を追加します。

サンプル アプリからは、いくつかのシナリオで正常性チェックを実演するスタートアップ コードが提供されます。 データベース プローブ シナリオでは、AspNetCore.Diagnostics.HealthChecks を使用して、データベース接続の正常性をチェックします。 DbContext プローブ シナリオでは、EF CoreDbContext を使用して、データベースがチェックされます。 データベース シナリオを探索するために、サンプル アプリでは次のことが行われます:

Note

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

もう 1 つの正常性チェックのシナリオでは、1 つの管理ポートに正常性チェックを絞り込む方法が実演されます。 このサンプル アプリでは、管理 URL と管理ポートを含む Properties/launchSettings.json ファイルを作成する必要があります。 詳細については、「ポート別のフィルター処理」セクションを参照してください。

基本的な正常性プローブ

多くのアプリでは、アプリが要求を処理できること (活動性) を報告する基本的な正常性チェック構成で十分にアプリの状態を検出できます。

基本の構成では、正常性チェック サービスを登録し、正常性チェック ミドルウェアを呼び出します。このミドルウェアが特定の URL エンドポイントにおける正常性を返します。 既定では、特定の依存関係またはサブシステムをテストする正常性チェックは登録されていません。 正常性エンドポイント URL で応答できる場合、そのアプリは正常であると見なされます。 既定の応答ライターによって、プレーンテキストの応答として状態 (HealthStatus) がクライアントに書き込まれます。このとき、状態として HealthStatus.HealthyHealthStatus.Degraded、または HealthStatus.Unhealthy が示されます。

正常性チェック サービスを Startup.ConfigureServicesAddHealthChecks に登録します。 Startup.ConfigureMapHealthChecks を呼び出して、正常性チェック エンドポイントを作成します。

サンプル アプリでは、正常性チェック エンドポイントは /health で作成されます (BasicStartup.cs)。

public class BasicStartup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHealthChecks();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHealthChecks("/health");
        });
    }
}

サンプル アプリを使用して基本的な構成シナリオを実行するには、コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario basic

Docker の例

Docker からは、組み込み HEALTHCHECK ディレクティブが提供されます。これを使用し、基本的な正常性チェック構成を使用するアプリの状態を確認できます。

HEALTHCHECK CMD curl --fail http://localhost:5000/health || exit

正常性チェックを作成する

正常性チェックは IHealthCheck インターフェイスを実装することで作成されます。 CheckHealthAsync メソッドによって、HealthyDegradedUnhealthy のいずれかの正常性を示す HealthCheckResult が返されます。 この結果が構成可能な状態コードと共にプレーンテキストの応答として書き込まれます (構成の説明は「正常性チェック オプション」セクションにあります)。 HealthCheckResult からは、任意のキーと値のペアを返すこともできます。

次の ExampleHealthCheck クラスからは、正常性チェックのレイアウトがどのようなものかがわかります。 正常性チェックのロジックが CheckHealthAsync メソッドに配置されています。 次の例では、ダミー変数 healthCheckResultHealthytrue に設定されます。 healthCheckResultHealthy の値が false に設定されている場合、HealthCheckResult.Unhealthy 状態が返されます。

public class ExampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var healthCheckResultHealthy = true;

        if (healthCheckResultHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            HealthCheckResult.Unhealthy("An unhealthy result."));
    }
}

正常性チェック サービスを登録する

Startup.ConfigureServicesAddCheck によって ExampleHealthCheck 型が正常性チェック サービスに追加されます。

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>("example_health_check");

次の例にある AddCheck オーバーロードでは、正常性チェックでエラーが報告されると、レポートにエラー状態 (HealthStatus) が設定されます。 エラー状態が null (既定) に設定された場合、HealthStatus.Unhealthy が報告されます。 このオーバーロードはライブラリ作成者にとって便利です。この設定に正常性チェック実装が従う場合、正常性チェック エラーが発生したとき、ライブラリによって指示されるエラー状態がアプリによって適用されます。

タグを使用し、正常性チェックをフィルター処理できます (詳細は「正常性チェックをフィルター処理する」セクションにあります)。

services.AddHealthChecks()
    .AddCheck<ExampleHealthCheck>(
        "example_health_check",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "example" });

AddCheck では、lambda 関数も実行できます。 次の例では、正常性チェック名に「Example」が指定されいます。このチェックでは状態として常に正常が返されます。

services.AddHealthChecks()
    .AddCheck("Example", () =>
        HealthCheckResult.Healthy("Example is OK!"), tags: new[] { "example" });

AddTypeActivatedCheck を呼び出して、正常性チェックの実装に引数を渡します。 次の例では、TestHealthCheckWithArgsCheckHealthAsync の呼び出し時に使用する整数と文字列を受け入れます。

private class TestHealthCheckWithArgs : IHealthCheck
{
    public TestHealthCheckWithArgs(int i, string s)
    {
        I = i;
        S = s;
    }

    public int I { get; set; }

    public string S { get; set; }

    public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, 
        CancellationToken cancellationToken = default)
    {
        ...
    }
}

TestHealthCheckWithArgs は実装に渡された整数と文字列を使用して AddTypeActivatedCheck を呼び出すことによって登録されます。

services.AddHealthChecks()
    .AddTypeActivatedCheck<TestHealthCheckWithArgs>(
        "test", 
        failureStatus: HealthStatus.Degraded, 
        tags: new[] { "example" }, 
        args: new object[] { 5, "string" });

正常性チェックのルーティングを使用する

Startup.Configure で、エンドポイントの URL または相対パスを使用して、エンドポイント ビルダーで MapHealthChecks を呼び出します。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
});

ホストが必要

RequireHost を呼び出して、正常性チェック エンドポイントに許可されている 1 つ以上のホストを指定します。 ホストは、punycode ではなく Unicode にする必要があります。また、ポートを含めることができます。 コレクションが指定されていない場合は、任意のホストを使用できます。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("www.contoso.com:5001");
});

詳細については、「ポート別のフィルター処理」セクションを参照してください。

承認が必要

RequireAuthorization を呼び出して、正常性チェック要求エンドポイントで承認ミドルウェアを実行します。 RequireAuthorization のオーバーロードには 1 つ以上の承認ポリシーを使用できます。 ポリシーが指定されていない場合は、既定の承認ポリシーが使用されます。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireAuthorization();
});

クロスオリジン要求 (CORS) の有効化

ブラウザーから手動で正常性チェックを実行することは一般的な使用シナリオではありませんが、正常性チェック エンドポイントで RequireCors を呼び出して CORS ミドルウェアを有効にすることができます。 RequireCors のオーバーロードには、CORS ポリシー ビルダーのデリゲート (CorsPolicyBuilder) またはポリシー名を使用できます。 ポリシーが指定されていない場合は、既定の CORS ポリシーが使用されます。 詳細については、「ASP.NET Core でクロスオリジン要求 (CORS) を有効にする」を参照してください。

正常性チェック オプション

HealthCheckOptions では、正常性チェックの動作をカスタマイズできます。

正常性チェックをフィルター処理する

既定では、正常性チェック ミドルウェアでは、登録されている正常性チェックがすべて実行されます。 正常性チェックのサブセットを実行するには、Predicate オプションにブール値を返す関数を指定します。 次の例では、関数の条件文にあるそのタグ (bar_tag) により Bar 正常性チェックが除外されます。true は、正常性チェックの Tags プロパティが foo_tagbaz_tag に一致した場合にのみ返されます。

Startup.ConfigureServicesの場合:

services.AddHealthChecks()
    .AddCheck("Foo", () =>
        HealthCheckResult.Healthy("Foo is OK!"), tags: new[] { "foo_tag" })
    .AddCheck("Bar", () =>
        HealthCheckResult.Unhealthy("Bar is unhealthy!"), tags: new[] { "bar_tag" })
    .AddCheck("Baz", () =>
        HealthCheckResult.Healthy("Baz is OK!"), tags: new[] { "baz_tag" });

Startup.Configure では、Predicate によって 'Bar' 正常性チェックが除外されます。 Foo と Baz のみが実行されます。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("foo_tag") ||
            check.Tags.Contains("baz_tag")
    });
});

HTTP 状態コードをカスタマイズする

ResultStatusCodes を使用し、HTTP 状態コードに対する正常性状態のマッピングをカスタマイズします。 次の StatusCodes 代入はミドルウェアによって使用される既定値です。 要件に合わせて状態コード値を変更します。

Startup.Configureの場合:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResultStatusCodes =
        {
            [HealthStatus.Healthy] = StatusCodes.Status200OK,
            [HealthStatus.Degraded] = StatusCodes.Status200OK,
            [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
        }
    });
});

キャッシュ ヘッダーを非表示にする

AllowCachingResponses によって、応答キャッシュを禁止する目的で、正常性チェック ミドルウェアによって HTTP ヘッダーがプローブ応答に追加されるかどうかが制御されます。 値が false (既定) の場合、応答キャッシュを禁止する目的で、ミドルウェアによってヘッダー Cache-ControlExpiresPragma が設定またはオーバーライドされます。 値が true の場合、応答のキャッシュ ヘッダーがミドルウェアによって変更されることはありません。

Startup.Configureの場合:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        AllowCachingResponses = true
    });
});

出力をカスタマイズする

Startup.Configure で、HealthCheckOptions.ResponseWriter オプションを、応答を書き込むためのデリゲートに設定します。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
});

既定の委任では、文字列値 HealthReport.Status を含む、最小のプレーンテキスト応答が書き込まれます。 次のカスタム デリゲートでは、カスタム JSON 応答が出力されます。

サンプル アプリの最初の例は、System.Text.Json の使用方法を示しています。

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions
    {
        Indented = true
    };

    using (var stream = new MemoryStream())
    {
        using (var writer = new Utf8JsonWriter(stream, options))
        {
            writer.WriteStartObject();
            writer.WriteString("status", result.Status.ToString());
            writer.WriteStartObject("results");
            foreach (var entry in result.Entries)
            {
                writer.WriteStartObject(entry.Key);
                writer.WriteString("status", entry.Value.Status.ToString());
                writer.WriteString("description", entry.Value.Description);
                writer.WriteStartObject("data");
                foreach (var item in entry.Value.Data)
                {
                    writer.WritePropertyName(item.Key);
                    JsonSerializer.Serialize(
                        writer, item.Value, item.Value?.GetType() ??
                        typeof(object));
                }
                writer.WriteEndObject();
                writer.WriteEndObject();
            }
            writer.WriteEndObject();
            writer.WriteEndObject();
        }

        var json = Encoding.UTF8.GetString(stream.ToArray());

        return context.Response.WriteAsync(json);
    }
}

2 番目の例は、Newtonsoft.Json の使用方法を示しています。

private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json";

    var json = new JObject(
        new JProperty("status", result.Status.ToString()),
        new JProperty("results", new JObject(result.Entries.Select(pair =>
            new JProperty(pair.Key, new JObject(
                new JProperty("status", pair.Value.Status.ToString()),
                new JProperty("description", pair.Value.Description),
                new JProperty("data", new JObject(pair.Value.Data.Select(
                    p => new JProperty(p.Key, p.Value))))))))));

    return context.Response.WriteAsync(
        json.ToString(Formatting.Indented));
}

サンプル アプリでは、CustomWriterStartup.csSYSTEM_TEXT_JSONプリプロセッサ ディレクティブをコメント アウトして、Newtonsoft.Json バージョンの WriteResponse を有効にします。

正常性チェック API には、複雑な JSON の戻り値の形式に対する組み込みのサポートが用意されていません。この形式は、選択した監視システムに固有のものであるためです。 必要に応じて、上記の例の応答をカスタマイズします。 System.Text.Json を使用した JSON シリアル化の詳細については、.NET で JSON をシリアル化および逆シリアル化する方法に関する記事をご覧ください。

データベース プローブ

正常性チェックでは、データベースが通常どおり応答しているかどうかを示すブール値テストとして実行されるよう、データベース クエリを指定できます。

このサンプル アプリでは、ASP.NET Core アプリ用の正常性チェック ライブラリ AspNetCore.Diagnostics.HealthChecks を使用して、SQL Server データベースの正常性チェックを実行します。 AspNetCore.Diagnostics.HealthChecks によってデータベースに対して SELECT 1 クエリが実行され、データベースへの接続が正常であることが確認されます。

警告

クエリでデータベース接続を確認するとき、すぐに返されるクエリを選択します。 このクエリ手法には、データベースをオーバーロードし、そのパフォーマンスを低下させるというリスクがあります。 ほとんどの場合、テスト クエリは実行する必要がありません。 データベースに正常に接続できれば十分です。 クエリを実行する必要があれば、SELECT 1 など、単純な SELECT クエリを選択してください。

AspNetCore.HealthChecks.SqlServer へのパッケージ参照を含めます。

サンプル アプリの appsettings.json ファイルに有効なデータベース接続文字列を指定します。 このアプリでは HealthCheckSample という名前の SQL Server データベースが使用されます。

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=HealthCheckSample;Trusted_Connection=True;MultipleActiveResultSets=true;ConnectRetryCount=0"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "Console": {
      "IncludeScopes": "true"
    }
  },
  "AllowedHosts": "*"
}

正常性チェック サービスを Startup.ConfigureServicesAddHealthChecks に登録します。 サンプル アプリでは、データベースの接続文字列 (DbHealthStartup.cs) を利用して AddSqlServer メソッドを呼び出します。

services.AddHealthChecks()
    .AddSqlServer(Configuration["ConnectionStrings:DefaultConnection"]);

正常性チェック エンドポイントを作成するには、Startup.ConfigureMapHealthChecks を呼び出します。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

サンプル アプリを使用してデータベース プローブ シナリオを実行するには、コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario db

Note

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

Entity Framework Core DbContext プローブ

DbContext チェックでは、EF CoreDbContext に対して構成されているデータベースとアプリとが通信できることが確認されます。 DbContext チェックは、次のようなアプリでサポートされています。

AddDbContextCheck<TContext> によって DbContext の正常性チェックが登録されます。 DbContextTContext としてメソッドに指定されます。 オーバーロードはエラー状態、タグ、カスタム テスト クエリの設定に利用できます。

既定では:

  • DbContextHealthCheck は、EF Core の CanConnectAsyncメソッドを呼び出します。 AddDbContextCheck メソッドのオーバーロードを使用して正常性を確認するときに実行される操作をカスタマイズできます。
  • 正常性チェックの名前は TContext 型の名前になります。

サンプル アプリでは、AppDbContextAddDbContextCheck に提供され、Startup.ConfigureServices でサービスとして登録されます (DbContextHealthStartup.cs)。

services.AddHealthChecks()
    .AddDbContextCheck<AppDbContext>();

services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(
        Configuration["ConnectionStrings:DefaultConnection"]);
});

正常性チェック エンドポイントを作成するには、Startup.ConfigureMapHealthChecks を呼び出します。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
}

サンプル アプリを利用して DbContext プローブ シナリオを実行するには、接続文字列によって指定されるデータベースが SQL Server インスタンスに存在しないことを確認します。 データベースが存在する場合、それを削除します。

コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario dbcontext

アプリの実行後、ブラウザーで /health エンドポイントに要求することで正常性状態を確認します。 データベースと AppDbContext は存在しません。そこで、アプリによって次の応答が返されます。

Unhealthy

サンプル アプリにデータベースを作成させます。 /createdatabase に要求を行います。 アプリからの応答は次のようになります。

Creating the database...
Done!
Navigate to /health to see the health status.

/health エンドポイントに要求を行います。 データベースとコンテキストが存在します。そのため、アプリによって次の応答が返されます。

Healthy

サンプル アプリにデータベースを削除させます。 /deletedatabase に要求を行います。 アプリからの応答は次のようになります。

Deleting the database...
Done!
Navigate to /health to see the health status.

/health エンドポイントに要求を行います。 アプリから異常という応答が返されます。

Unhealthy

対応性と活動性に区分されるプローブ

一部のホスティング シナリオでは、2 つのアプリ状態を区別する一組の正常性チェックが使用されます。

  • "対応性" は、アプリが通常どおり実行されているが、要求を受け取る準備ができていないのか、あるいはそうではないのかを示します。
  • "活動性" は、アプリがクラッシュしたため、再起動する必要があるのかどうかを示します。

次に例を示します。アプリでは、大きな構成ファイルをダウンロードしないと、要求を処理する準備ができません。 初回ダウンロードに失敗した場合、アプリを再起動することは望みません。アプリはファイルのダウンロードを数回再試行する可能性があるためです。 liveness probe を使用し、プロセスの活動性を記述します。他のチェックは実行されません。 また、構成ファイルのダウンロードが完了する前は、要求がアプリに送信されないようにします。 "対応性プローブ" を使用し、ダウンロードが成功し、要求を受け取る準備がアプリにできるまで、"準備できていない" 状態を示します。

サンプル アプリには、ホステッド サービスの長時間実行スタートアップ タスクの完了を報告する正常性チェックが含まれています。 StartupHostedServiceHealthCheck によって StartupTaskCompleted というプロパティが公開されます。ホステッド サービスでは長時間実行タスクの完了時にこのプロパティを true に設定できます (StartupHostedServiceHealthCheck.cs)。

public class StartupHostedServiceHealthCheck : IHealthCheck
{
    private volatile bool _startupTaskCompleted = false;

    public string Name => "slow_dependency_check";

    public bool StartupTaskCompleted
    {
        get => _startupTaskCompleted;
        set => _startupTaskCompleted = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        if (StartupTaskCompleted)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("The startup task is finished."));
        }

        return Task.FromResult(
            HealthCheckResult.Unhealthy("The startup task is still running."));
    }
}

長時間実行バックグラウンド タスクはホステッド サービスによって開始されます (Services/StartupHostedService)。 タスクが終わると、StartupHostedServiceHealthCheck.StartupTaskCompletedtrue に設定されます。

public class StartupHostedService : IHostedService, IDisposable
{
    private readonly int _delaySeconds = 15;
    private readonly ILogger _logger;
    private readonly StartupHostedServiceHealthCheck _startupHostedServiceHealthCheck;

    public StartupHostedService(ILogger<StartupHostedService> logger,
        StartupHostedServiceHealthCheck startupHostedServiceHealthCheck)
    {
        _logger = logger;
        _startupHostedServiceHealthCheck = startupHostedServiceHealthCheck;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is starting.");

        // Simulate the effect of a long-running startup task.
        Task.Run(async () =>
        {
            await Task.Delay(_delaySeconds * 1000);

            _startupHostedServiceHealthCheck.StartupTaskCompleted = true;

            _logger.LogInformation("Startup Background Service has started.");
        });

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Startup Background Service is stopping.");

        return Task.CompletedTask;
    }

    public void Dispose()
    {
    }
}

ホステッド サービスと共に Startup.ConfigureServices で正常性チェックが AddCheck に登録されます。 ホステッド サービスでは正常性チェックにプロパティを設定する必要があるため、正常性チェックはサービス コンテナーにも登録されます (LivenessProbeStartup.cs)。

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

正常性チェック エンドポイントを作成するには、Startup.ConfigureMapHealthChecks を呼び出します。 サンプル アプリでは、正常性チェック エンドポイントは次の場所に作成されます。

  • 対応性チェックの場合は /health/ready。 対応性チェックでは、ready タグが与えられているものに正常性チェックが絞り込まれます。
  • 活動性チェックの場合は /health/live。 活動性チェックでは、HealthCheckOptions.Predicatefalse を返すことで StartupHostedServiceHealthCheck が除外されます (詳細については、「正常性チェックをフィルター処理する」を参照してください)

次のコード例の内容:

  • 対応性チェックでは、登録されているすべてのチェックが 'ready' タグと共に使用されます。
  • Predicate では、すべてのチェックが除外され、200-Ok が返されます。
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

サンプル アプリを使用して対応性/活動性構成シナリオを実行するには、コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario liveness

ブラウザーで、15 秒が経過するまで /health/ready に数回アクセスします。 正常性チェックにより最初の 15 秒に対して Unhealthy が報告されます。 15 秒後、エンドポイントから Healthy が報告されます。これは、ホステッド サービスによる長時間実行タスクが完了したことを反映しています。

この例では、2 秒間の遅延で最初の対応性チェックを実行する正常性チェック パブリッシャー (IHealthCheckPublisher の実装) も作成されます。 詳細については、「正常性チェック パブリッシャー」セクションをご覧ください。

Kubernetes の例

対応性チェックと活動性チェックを使い分けることは、Kubernetes などの環境で便利です。 Kubernetes では、要求を受け入れる前に、基礎をなすデータベースの可用性テストなど、時間のかかるスタートアップ作業の実行がアプリに要求されることがあります。 別個のチェックを利用することで、アプリは機能しているがまだ準備ができていないか、あるいはアプリが起動に失敗したかをオーケストレーターは区別できます。 Kubernetes の対応性プローブと活動性プローブに関する詳細については、Kubernetes ドキュメントの「Configure Liveness and Readiness Probes」 (活動性プローブと対応性プローブを設定する) を参照してください。

次の例では、Kubernetes 対応性プローブの構成を確認できます。

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /health/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

カスタム応答ライターを含むメトリック ベースのプローブ

このサンプル アプリでは、カスタム応答ライターを含む、メモリ正常性チェックを確認できます。

与えられたしきい値を超えるメモリがアプリで使用された場合、MemoryHealthCheck からは劣化状態が報告されます (このサンプル アプリでは 1 GB)。 HealthCheckResult にはアプリのガベージ コレクター (GC) 情報が含まれています (MemoryHealthCheck.cs)。

public class MemoryHealthCheck : IHealthCheck
{
    private readonly IOptionsMonitor<MemoryCheckOptions> _options;

    public MemoryHealthCheck(IOptionsMonitor<MemoryCheckOptions> options)
    {
        _options = options;
    }

    public string Name => "memory_check";

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        var options = _options.Get(context.Registration.Name);

        // Include GC information in the reported diagnostics.
        var allocated = GC.GetTotalMemory(forceFullCollection: false);
        var data = new Dictionary<string, object>()
        {
            { "AllocatedBytes", allocated },
            { "Gen0Collections", GC.CollectionCount(0) },
            { "Gen1Collections", GC.CollectionCount(1) },
            { "Gen2Collections", GC.CollectionCount(2) },
        };
        var status = (allocated < options.Threshold) ?
            HealthStatus.Healthy : context.Registration.FailureStatus;

        return Task.FromResult(new HealthCheckResult(
            status,
            description: "Reports degraded status if allocated bytes " +
                $">= {options.Threshold} bytes.",
            exception: null,
            data: data));
    }
}

正常性チェック サービスを Startup.ConfigureServicesAddHealthChecks に登録します。 AddCheck に渡して正常性チェックを有効にする代わりに、MemoryHealthCheck がサービスとして登録されます。 IHealthCheck が登録されたサービスはすべて、正常性チェック サービスとミドルウェアで利用できます。 正常性チェック サービスはシングルトン サービスとして登録することをお勧めします。

サンプル アプリの CustomWriterStartup.cs 内:

services.AddHealthChecks()
    .AddMemoryHealthCheck("memory");

正常性チェック エンドポイントを作成するには、Startup.ConfigureMapHealthChecks を呼び出します。 WriteResponse デリゲートが ResponseWriter プロパティに与えられることで、正常性チェックの実行時に、カスタム JSON 応答が出力されます。

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        ResponseWriter = WriteResponse
    });
}

WriteResponse デリゲートによって、CompositeHealthCheckResult が JSON オブジェクトに書式設定され、正常性チェック応答の JSON 出力が生成されます。 詳細については、「出力をカスタマイズする」セクションをご覧ください。

サンプル アプリを使用してカスタム応答ライターを含むメトリックベースのプローブを実行するには、コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario writer

Note

AspNetCore.Diagnostics.HealthChecks には、ディスク ストレージや最大値活動性のチェックなど、メトリックベースの正常性チェック シナリオが含まれます。

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

ポート別のフィルター処理

MapHealthChecks でポートを指定する URL パターンを使用して RequireHost を呼び出し、指定されたポートに正常性チェック要求を制限します。 この方法は通常、サービスを監視するためのポートを公開する目的で、コンテナー環境で使用されます。

サンプル アプリによって、環境変数構成プロバイダーを使用してポートが設定されます。 ポートは launchSettings.json ファイルに設定され、環境変数を介して構成プロバイダーに渡されます。 管理ポートで要求を待つようにサーバーを設定する必要もあります。

サンプル アプリを使用し、管理ポート設定を実演するには、Properties フォルダーで launchSettings.json ファイルを作成します。

サンプル アプリの次の Properties/launchSettings.json ファイルは、サンプル アプリのプロジェクト ファイルに含まれていないため、手動で作成する必要があります。

{
  "profiles": {
    "SampleApp": {
      "commandName": "Project",
      "commandLineArgs": "",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_URLS": "http://localhost:5000/;http://localhost:5001/",
        "ASPNETCORE_MANAGEMENTPORT": "5001"
      },
      "applicationUrl": "http://localhost:5000/"
    }
  }
}

正常性チェック サービスを Startup.ConfigureServicesAddHealthChecks に登録します。 Startup.ConfigureMapHealthChecks を呼び出して、正常性チェック エンドポイントを作成します。

サンプル アプリでは、Startup.Configure のエンドポイントで RequireHost を呼び出すと、構成の管理ポートが指定されます。

endpoints.MapHealthChecks("/health")
    .RequireHost($"*:{Configuration["ManagementPort"]}");

エンドポイントは、Startup.Configure のサンプル アプリで作成されます。 次のコード例の内容:

  • 対応性チェックでは、登録されているすべてのチェックが 'ready' タグと共に使用されます。
  • Predicate では、すべてのチェックが除外され、200-Ok が返されます。
app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("ready"),
    });

    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = (_) => false
    });
}

Note

管理ポートをコードに明示的に設定することで、サンプル アプリで launchSettings.json ファイルを作成することを回避できます。 HostBuilder が作成される Program.cs で、ListenAnyIP の呼び出しを追加し、アプリの管理ポート エンドポイントを用意します。 ManagementPortStartup.csConfigure で、RequireHost を使用して管理ポートを指定します。

Program.cs:

return new HostBuilder()
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseKestrel()
            .ConfigureKestrel(serverOptions =>
            {
                serverOptions.ListenAnyIP(5001);
            })
            .UseStartup(startupType);
    })
    .Build();

ManagementPortStartup.cs:

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health").RequireHost("*:5001");
});

サンプル アプリを使用して管理ポート構成シナリオを実行するには、コマンド シェルでプロジェクトのフォルダーから次のコマンドを実行します。

dotnet run --scenario port

正常性チェック ライブラリを配布する

正常性チェックをライブラリとして配布するには:

  1. スタンドアロン クラスとして IHealthCheck インターフェイスを実装する正常性チェックを記述します。 このクラスは、設定データにアクセスする目的で依存関係挿入 (DI)、型のアクティブ化、名前付きオプションに依存できます。

    CheckHealthAsync の正常性チェックのロジックでは、次のようになります。

    • data1data2 は、プローブの正常性チェック ロジックを実行するためにメソッドで使用されます。
    • AccessViolationException が処理されます。

    AccessViolationException が発生すると、HealthCheckResult とともに FailureStatus が返され、ユーザーは正常性チェックの失敗状態を構成できます。

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    namespace SampleApp
    {
        public class ExampleHealthCheck : IHealthCheck
        {
            private readonly string _data1;
            private readonly int? _data2;
    
            public ExampleHealthCheck(string data1, int? data2)
            {
                _data1 = data1 ?? throw new ArgumentNullException(nameof(data1));
                _data2 = data2 ?? throw new ArgumentNullException(nameof(data2));
            }
    
            public async Task<HealthCheckResult> CheckHealthAsync(
                HealthCheckContext context, CancellationToken cancellationToken)
            {
                try
                {
                    return HealthCheckResult.Healthy();
                }
                catch (AccessViolationException ex)
                {
                    return new HealthCheckResult(
                        context.Registration.FailureStatus,
                        description: "An access violation occurred during the check.",
                        exception: ex,
                        data: null);
                }
            }
        }
    }
    
  2. 拡張メソッドを記述します。拡張メソッドを使用するアプリがその Startup.Configure メソッドで呼び出すパラメーターを指定します。 次の例では、次の正常性チェック メソッド シグネチャを想定します。

    ExampleHealthCheck(string, string, int )
    

    先のシグネチャは、正常性チェック プローブ ロジックを処理する目的で ExampleHealthCheck に追加データが要求されることを示しています。 正常性チェックが拡張メソッドに登録されたときに正常性チェック インスタンスを作成するための委任にデータが提供されます。 次の例では、呼び出し元によって次が任意で指定されます。

    • 正常性チェック名 (name)。 null の場合、example_health_check が使用されます。
    • 正常性チェックの文字列データ ポイント (data1)。
    • 正常性チェックの整数データ ポイント (data2)。 null の場合、1 が使用されます。
    • エラー状態 (HealthStatus)。 既定値は、null です。 null の場合、エラー状態に対して HealthStatus.Unhealthy が報告されます。
    • タグ (IEnumerable<string>)。
    using System.Collections.Generic;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    public static class ExampleHealthCheckBuilderExtensions
    {
        const string DefaultName = "example_health_check";
    
        public static IHealthChecksBuilder AddExampleHealthCheck(
            this IHealthChecksBuilder builder,
            string name = default,
            string data1,
            int data2 = 1,
            HealthStatus? failureStatus = default,
            IEnumerable<string> tags = default)
        {
            return builder.Add(new HealthCheckRegistration(
                name ?? DefaultName,
                sp => new ExampleHealthCheck(data1, data2),
                failureStatus,
                tags));
        }
    }
    

正常性チェック パブリッシャー

サービス コンテナーに IHealthCheckPublisher が追加されると、正常性チェック システムにより定期的に正常性チェックが実行され、結果と共に PublishAsync が呼び出されます。 これは、正常性を判断する目的で監視システムを定期的に呼び出すことを各プロセスに求めるプッシュベースの監視システム シナリオで便利です。

IHealthCheckPublisher インターフェイスには単一メソッドが与えられます。

Task PublishAsync(HealthReport report, CancellationToken cancellationToken);

HealthCheckPublisherOptions を使うと次を設定できます。

  • Delay:アプリが起動した後、IHealthCheckPublisher インスタンスを実行する前に適用される初期遅延です。 遅延はスタートアップ時に一度だけ適用され、以降の繰り返しには適用されません。 既定値は 5 秒です。
  • Period:IHealthCheckPublisher を実行する期間です。 既定値は 30 秒です。
  • Predicate:Predicatenull (既定値) の場合、正常性チェック パブリッシャー サービスにより登録済みのすべての正常性チェックが実行されます。 正常性チェックのサブセットを実行するには、チェックのセットをフィルター処理する関数を指定します。 述語は期間ごとに評価されます。
  • Timeout:すべての IHealthCheckPublisher インスタンスに対する正常性チェックの実行のタイムアウトです。 タイムアウトなしで実行するには InfiniteTimeSpan を使います。 既定値は 30 秒です。

サンプル アプリでは、ReadinessPublisherIHealthCheckPublisher の実装です。 正常性チェックの状態は、チェックごとに以下のログ レベルでログに記録されます。

public class ReadinessPublisher : IHealthCheckPublisher
{
    private readonly ILogger _logger;

    public ReadinessPublisher(ILogger<ReadinessPublisher> logger)
    {
        _logger = logger;
    }

    // The following example is for demonstration purposes only. Health Checks
    // Middleware already logs health checks results. A real-world readiness
    // check in a production app might perform a set of more expensive or
    // time-consuming checks to determine if other resources are responding
    // properly.
    public Task PublishAsync(HealthReport report,
        CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            _logger.LogInformation("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }
        else
        {
            _logger.LogError("{Timestamp} Readiness Probe Status: {Result}",
                DateTime.UtcNow, report.Status);
        }

        cancellationToken.ThrowIfCancellationRequested();

        return Task.CompletedTask;
    }
}

サンプル アプリの LivenessProbeStartup の例では、対応性チェック StartupHostedService にはスタートアップの遅延が 2 秒間あり、30 秒ごとにチェックが実行されます。 IHealthCheckPublisher の実装をアクティブ化するために、サンプルでは ReadinessPublisher をシングルトン サービスとして依存関係の挿入 (DI) コンテナーに登録しています。

services.AddHostedService<StartupHostedService>();
services.AddSingleton<StartupHostedServiceHealthCheck>();

services.AddHealthChecks()
    .AddCheck<StartupHostedServiceHealthCheck>(
        "hosted_service_startup",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "ready" });

services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = (check) => check.Tags.Contains("ready");
});

services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();

Note

AspNetCore.Diagnostics.HealthChecks には、Application Insights など、いくつかのシステムのパブリッシャーが含まれます。

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

MapWhen で正常性チェックを制限する

MapWhen を使用して、正常性チェック エンドポイントの要求パイプラインを条件付きで分岐します。

次の例では、api/HealthCheck エンドポイントに対して GET 要求が受信された場合に、MapWhen が要求パイプラインを分岐して正常性チェック ミドルウェアをアクティブ化します。

app.MapWhen(
    context => context.Request.Method == HttpMethod.Get.Method && 
        context.Request.Path.StartsWith("/api/HealthCheck"),
    builder => builder.UseHealthChecks());

app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
});

詳細については、「ASP.NET Core のミドルウェア」を参照してください。

ASP.NET Core からは、アプリ インフラストラクチャ コンポーネントの正常性を報告するための正常性チェック ミドルウェアとライブラリが提供されます。

正常性チェックは HTTP エンドポイントとしてアプリによって公開されます。 正常性チェック エンドポイントは、さまざまなリアルタイム監視シナリオに合わせて設定できます。

  • 正常性プローブは、アプリの状態を確認する目的でコンテナー オーケストレーターとロード バランサーによって使用できます。 たとえば、正常性チェックで問題が確認された場合、コンテナー オーケストレーターは実行中の展開を停止したり、コンテナーを再起動したりします。 ロード バランサーはアプリの異常に対処するため、問題のあるインスタンスから正常なインスタンスにトラフィック経路を変更することがあります。
  • メモリ、ディスク、その他の物理サーバー リソースの使用を監視し、正常性の状態を確認できます。
  • 正常性チェックでは、データベースや外部サービス エンドポイントなど、アプリの依存関係をテストし、それらが利用できることと正常に機能していることを確認できます。

正常性チェックは通常、アプリの状態を確認する目的で、外部の監視サービスまたはコンテナー オーケストレーターと共に使用されます。 正常性チェックをアプリに追加する前に、使用する監視システムを決定します。 監視システムからは、作成する正常性チェックの種類とそのエンドポイントの設定方法が指示されます。

基本的な正常性プローブ

多くのアプリでは、アプリが要求を処理できること (活動性) を報告する基本的な正常性チェック構成で十分にアプリの状態を検出できます。

基本の構成では、正常性チェック サービスを登録し、正常性チェック ミドルウェアを呼び出します。このミドルウェアが特定の URL エンドポイントにおける正常性を返します。 既定では、特定の依存関係またはサブシステムをテストする正常性チェックは登録されていません。 正常性エンドポイント URL で応答できる場合、そのアプリは正常であると見なされます。 既定の応答ライターは、プレーンテキストの応答として HealthStatus をクライアントに書き込みます。 HealthStatus は、HealthStatus.HealthyHealthStatus.Degraded、または HealthStatus.Unhealthy です。

正常性チェック サービスを Program.csAddHealthChecks に登録します。 MapHealthChecks を呼び出して、正常性チェック エンドポイントを作成します。

次の例では、/healthz に正常性チェック エンドポイントを作成しています。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/healthz");

app.Run();

Docker の HEALTHCHECK

Docker からは、組み込み HEALTHCHECK ディレクティブが提供されます。これを使用し、基本的な正常性チェック構成を使用するアプリの状態を確認できます。

HEALTHCHECK CMD curl --fail http://localhost:5000/healthz || exit

上の例では、curl を使用して、/healthz の正常性チェック エンドポイントに対して HTTP 要求を行っています。 curl は .NET Linux コンテナー イメージには含まれていませんが、必要なパッケージを Dockerfile にインストールすることによって追加できます。 Alpine Linux に基づくイメージを使用するコンテナーでは、curl の代わりに含まれている wget を使用できます。

正常性チェックを作成する

正常性チェックは IHealthCheck インターフェイスを実装することで作成されます。 CheckHealthAsync メソッドによって、HealthyDegradedUnhealthy のいずれかの正常性を示す HealthCheckResult が返されます。 結果は、構成可能なステータス コードを含むプレーンテキストの応答として書き込まれます。 構成については、「正常性チェック オプション」を参照してください。 HealthCheckResult からは、任意のキーと値のペアを返すこともできます。

次の例は、正常性チェックのレイアウトを示しています。

public class SampleHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

正常性チェックのロジックが CheckHealthAsync メソッドに配置されています。 前の例では、ダミー変数 isHealthytrue に設定されています。 isHealthy の値が false に設定されている場合、HealthCheckRegistration.FailureStatus 状態が返されます。

CheckHealthAsync がチェック中に例外をスローした場合、HealthReportEntry.StatusFailureStatus に設定された新しい HealthReportEntry が返されます。 この状態は AddCheck によって定義され (「正常性チェック サービスを登録する」を参照)、チェックに失敗した原因となった内部例外が含まれています。 Description は例外のメッセージに設定されます。

正常性チェック サービスを登録する

正常性チェック サービスを登録するには、Program.csAddCheck を呼び出します。

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>("Sample");

次の例にある AddCheck オーバーロードでは、正常性チェックでエラーが報告されると、レポートにエラー状態 (HealthStatus) が設定されます。 エラー状態が null (既定) に設定された場合、HealthStatus.Unhealthy が報告されます。 このオーバーロードはライブラリ作成者にとって便利です。この設定に正常性チェック実装が従う場合、正常性チェック エラーが発生したとき、ライブラリによって指示されるエラー状態がアプリによって適用されます。

"タグ" を使用して、正常性チェックをフィルター処理できます。 タグの詳細については、「正常性チェックをフィルター処理する」を参照してください。

builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheck>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" });

AddCheck では、lambda 関数も実行できます。 この例では、正常性チェックにより常に正常な結果が返されます。

builder.Services.AddHealthChecks()
    .AddCheck("Sample", () => HealthCheckResult.Healthy("A healthy result."));

AddTypeActivatedCheck を呼び出して、正常性チェックの実装に引数を渡します。 次の例では、型がアクティブ化された正常性チェックは、コンストラクターに整数と文字列を受け取ります。

public class SampleHealthCheckWithArgs : IHealthCheck
{
    private readonly int _arg1;
    private readonly string _arg2;

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        // ...

        return Task.FromResult(HealthCheckResult.Healthy("A healthy result."));
    }
}

上記の正常性チェックを登録するには、整数と文字列を引数として渡して AddTypeActivatedCheck を呼び出します。

builder.Services.AddHealthChecks()
    .AddTypeActivatedCheck<SampleHealthCheckWithArgs>(
        "Sample",
        failureStatus: HealthStatus.Degraded,
        tags: new[] { "sample" },
        args: new object[] { 1, "Arg" });

正常性チェックのルーティングを使用する

Program.cs で、エンドポイントの URL または相対パスを使用して、エンドポイント ビルダーで MapHealthChecks を呼び出します。

app.MapHealthChecks("/healthz");

ホストが必要

RequireHost を呼び出して、正常性チェック エンドポイントに許可されている 1 つ以上のホストを指定します。 ホストは、punycode ではなく Unicode にする必要があります。また、ポートを含めることができます。 コレクションが指定されていない場合は、任意のホストを使用できます。

app.MapHealthChecks("/healthz")
    .RequireHost("www.contoso.com:5001");

特定のポートでのみ応答するように正常性チェック エンドポイントを制限するには、RequireHost の呼び出しでポートを指定します。 この方法は通常、サービスを監視するためのポートを公開する目的で、コンテナー環境で使用されます。

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001");

警告

HttpRequest.HostRequireHost などのホスト ヘッダーに依存する API は、クライアントによるスプーフィングの対象になる可能性があります。

ホストとポートのスプーフィングを防ぐには、次のいずれかの方法を使用します。

承認されていないクライアントがポートをスプーフィングするのを防ぐには、RequireAuthorization を呼び出します。

app.MapHealthChecks("/healthz")
    .RequireHost("*:5001")
    .RequireAuthorization();

詳細については、「RequireHost とルートが一致するホスト」を参照してください。

承認が必要

RequireAuthorization を呼び出して、正常性チェック要求エンドポイントで承認ミドルウェアを実行します。 RequireAuthorization のオーバーロードには 1 つ以上の承認ポリシーを使用できます。 ポリシーが指定されていない場合は、既定の承認ポリシーが使用されます。

app.MapHealthChecks("/healthz")
    .RequireAuthorization();

クロスオリジン要求 (CORS) の有効化

ブラウザーから手動で正常性チェックを実行することは一般的なシナリオではありませんが、正常性チェック エンドポイントで RequireCors を呼び出して CORS ミドルウェアを有効にすることができます。 RequireCors のオーバーロードには、CORS ポリシー ビルダーのデリゲート (CorsPolicyBuilder) またはポリシー名を使用できます。 詳細については、「ASP.NET Core でクロスオリジン要求 (CORS) を有効にする」を参照してください。

正常性チェック オプション

HealthCheckOptions では、正常性チェックの動作をカスタマイズできます。

正常性チェックをフィルター処理する

既定では、正常性チェック ミドルウェアによって、登録済みの正常性チェックがすべて実行されます。 正常性チェックのサブセットを実行するには、Predicate オプションにブール値を返す関数を指定します。

次の例では、正常性チェックのフィルター処理を行い、sample タグが付けられているものだけが実行されるようにします。

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("sample")
});

HTTP 状態コードをカスタマイズする

ResultStatusCodes を使用し、HTTP 状態コードに対する正常性状態のマッピングをカスタマイズします。 次の StatusCodes 代入はミドルウェアによって使用される既定値です。 要件に合わせて状態コード値を変更します。

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResultStatusCodes =
    {
        [HealthStatus.Healthy] = StatusCodes.Status200OK,
        [HealthStatus.Degraded] = StatusCodes.Status200OK,
        [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
    }
});

キャッシュ ヘッダーを非表示にする

AllowCachingResponses によって、応答キャッシュを禁止する目的で、正常性チェック ミドルウェアによって HTTP ヘッダーがプローブ応答に追加されるかどうかが制御されます。 値が false (既定) の場合、応答キャッシュを禁止する目的で、ミドルウェアによってヘッダー Cache-ControlExpiresPragma が設定またはオーバーライドされます。 値が true の場合、応答のキャッシュ ヘッダーがミドルウェアによって変更されることはありません。

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    AllowCachingResponses = true
});

出力をカスタマイズする

正常性チェック レポートの出力をカスタマイズするには、HealthCheckOptions.ResponseWriter プロパティを、応答の書き込み先のデリゲートに設定します。

app.MapHealthChecks("/healthz", new HealthCheckOptions
{
    ResponseWriter = WriteResponse
});

既定の委任では、文字列値 HealthReport.Status を含む、最小のプレーンテキスト応答が書き込まれます。 次のカスタム デリゲートでは、System.Text.Json を使用してカスタム JSON 応答が出力されます。

private static Task WriteResponse(HttpContext context, HealthReport healthReport)
{
    context.Response.ContentType = "application/json; charset=utf-8";

    var options = new JsonWriterOptions { Indented = true };

    using var memoryStream = new MemoryStream();
    using (var jsonWriter = new Utf8JsonWriter(memoryStream, options))
    {
        jsonWriter.WriteStartObject();
        jsonWriter.WriteString("status", healthReport.Status.ToString());
        jsonWriter.WriteStartObject("results");

        foreach (var healthReportEntry in healthReport.Entries)
        {
            jsonWriter.WriteStartObject(healthReportEntry.Key);
            jsonWriter.WriteString("status",
                healthReportEntry.Value.Status.ToString());
            jsonWriter.WriteString("description",
                healthReportEntry.Value.Description);
            jsonWriter.WriteStartObject("data");

            foreach (var item in healthReportEntry.Value.Data)
            {
                jsonWriter.WritePropertyName(item.Key);

                JsonSerializer.Serialize(jsonWriter, item.Value,
                    item.Value?.GetType() ?? typeof(object));
            }

            jsonWriter.WriteEndObject();
            jsonWriter.WriteEndObject();
        }

        jsonWriter.WriteEndObject();
        jsonWriter.WriteEndObject();
    }

    return context.Response.WriteAsync(
        Encoding.UTF8.GetString(memoryStream.ToArray()));
}

正常性チェック API には、複雑な JSON の戻り値の形式に対する組み込みのサポートが用意されていません。この形式は、選択した監視システムに固有のものであるためです。 必要に応じて、上記の例の応答をカスタマイズします。 System.Text.Json を使用した JSON シリアル化の詳細については、.NET で JSON をシリアル化および逆シリアル化する方法に関する記事をご覧ください。

データベース プローブ

正常性チェックでは、データベースが通常どおり応答しているかどうかを示すブール値テストとして実行されるよう、データベース クエリを指定できます。

ASP.NET Core アプリ用の正常性チェック ライブラリ AspNetCore.Diagnostics.HealthChecks には、SQL Server データベースに対して実行される正常性チェックが含まれています。 AspNetCore.Diagnostics.HealthChecks によってデータベースに対して SELECT 1 クエリが実行され、データベースへの接続が正常であることが確認されます。

警告

クエリでデータベース接続を確認するとき、すぐに返されるクエリを選択します。 このクエリ手法には、データベースをオーバーロードし、そのパフォーマンスを低下させるというリスクがあります。 ほとんどの場合、テスト クエリは実行する必要がありません。 データベースに正常に接続できれば十分です。 クエリを実行する必要があれば、SELECT 1 など、単純な SELECT クエリを選択してください。

この SQL Server 正常性チェックを使用するには、AspNetCore.HealthChecks.SqlServer NuGet パッケージへのパッケージ参照を含めます。 次の例では、SQL Server 正常性チェックを登録します。

builder.Services.AddHealthChecks()
    .AddSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection"));

Note

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

Entity Framework Core DbContext プローブ

DbContext チェックでは、EF CoreDbContext に対して構成されているデータベースとアプリとが通信できることが確認されます。 DbContext チェックは、次のようなアプリでサポートされています。

AddDbContextCheck によって DbContext の正常性チェックが登録されます。 DbContextTContext としてメソッドに指定されます。 オーバーロードはエラー状態、タグ、カスタム テスト クエリの設定に利用できます。

既定では:

  • DbContextHealthCheck は、EF Core の CanConnectAsyncメソッドを呼び出します。 AddDbContextCheck メソッドのオーバーロードを使用して正常性を確認するときに実行される操作をカスタマイズできます。
  • 正常性チェックの名前は TContext 型の名前になります。

次の例では、DbContext と、これに関連付けられている DbContextHealthCheck を登録します。

builder.Services.AddDbContext<SampleDbContext>(options =>
    options.UseSqlServer(
        builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddHealthChecks()
    .AddDbContextCheck<SampleDbContext>();

対応性と活動性に区分されるプローブ

一部のホスティング シナリオでは、2 つのアプリ状態を区別する一組の正常性チェックが使用されます。

  • "対応性" は、アプリが通常どおり実行されているが、要求を受け取る準備ができていないのか、あるいはそうではないのかを示します。
  • "活動性" は、アプリがクラッシュしたため、再起動する必要があるのかどうかを示します。

次に例を示します。アプリでは、大きな構成ファイルをダウンロードしないと、要求を処理する準備ができません。 初回ダウンロードに失敗した場合、アプリを再起動することは望みません。アプリはファイルのダウンロードを数回再試行する可能性があるためです。 liveness probe を使用し、プロセスの活動性を記述します。他のチェックは実行されません。 また、構成ファイルのダウンロードが完了する前は、要求がアプリに送信されないようにします。 "対応性プローブ" を使用し、ダウンロードが成功し、要求を受け取る準備がアプリにできるまで、"準備できていない" 状態を示します。

次のバックグラウンド タスクでは、15 秒ほどかかるスタートアップ プロセスをシミュレートします。 完了すると、このタスクによって StartupHealthCheck.StartupCompleted プロパティが true に設定されます。

public class StartupBackgroundService : BackgroundService
{
    private readonly StartupHealthCheck _healthCheck;

    public StartupBackgroundService(StartupHealthCheck healthCheck)
        => _healthCheck = healthCheck;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Simulate the effect of a long-running task.
        await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);

        _healthCheck.StartupCompleted = true;
    }
}

StartupHealthCheck は、実行時間の長いスタートアップ タスクの完了をレポートし、バックグラウンド サービスによって設定される StartupCompleted プロパティを公開します。

public class StartupHealthCheck : IHealthCheck
{
    private volatile bool _isReady;

    public bool StartupCompleted
    {
        get => _isReady;
        set => _isReady = value;
    }

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        if (StartupCompleted)
        {
            return Task.FromResult(HealthCheckResult.Healthy("The startup task has completed."));
        }

        return Task.FromResult(HealthCheckResult.Unhealthy("That startup task is still running."));
    }
}

ホステッド サービスと共に Program.cs で正常性チェックが AddCheck に登録されます。 ホステッド サービスでは正常性チェックにプロパティを設定する必要があるため、正常性チェックはシングルトンとしてサービス コンテナーにも登録されます。

builder.Services.AddHostedService<StartupBackgroundService>();
builder.Services.AddSingleton<StartupHealthCheck>();

builder.Services.AddHealthChecks()
    .AddCheck<StartupHealthCheck>(
        "Startup",
        tags: new[] { "ready" });

2 つの異なる正常性チェック エンドポイントを作成するには、MapHealthChecks を 2 回呼び出します。

app.MapHealthChecks("/healthz/ready", new HealthCheckOptions
{
    Predicate = healthCheck => healthCheck.Tags.Contains("ready")
});

app.MapHealthChecks("/healthz/live", new HealthCheckOptions
{
    Predicate = _ => false
});

前の例では、次の正常性チェック エンドポイントを作成しています。

  • 対応性チェックの場合は /healthz/ready。 対応性チェックでは、ready タグが付けられているものに正常性チェックが絞り込まれます。
  • 活動性チェックの場合は /healthz/live。 この活動性チェックでは、HealthCheckOptions.Predicate デリゲートで false を返すことによって、すべての正常性チェックを除外します。 正常性チェックのフィルター処理の詳細については、この記事の「正常性チェックをフィルター処理する」を参照してください。

スタートアップ タスクが完了する前に、/healthz/ready エンドポイントから Unhealthy状態がレポートされます。 スタートアップ タスクが完了したら、このエンドポイントから Healthy 状態がレポートされます。 /healthz/live エンドポイントは、すべてのチェックを除外し、すべての呼び出しに対して Healthy 状態をレポートします。

Kubernetes の例

対応性チェックと活動性チェックを使い分けることは、Kubernetes などの環境で便利です。 Kubernetes では、要求を受け入れる前に、基礎をなすデータベースの可用性テストなど、時間のかかるスタートアップ作業の実行がアプリに要求されることがあります。 別個のチェックを利用することで、アプリは機能しているがまだ準備ができていないか、あるいはアプリが起動に失敗したかをオーケストレーターは区別できます。 Kubernetes の対応性プローブと活動性プローブに関する詳細については、Kubernetes ドキュメントの「Configure Liveness and Readiness Probes」 (活動性プローブと対応性プローブを設定する) を参照してください。

次の例では、Kubernetes 対応性プローブの構成を確認できます。

spec:
  template:
  spec:
    readinessProbe:
      # an http probe
      httpGet:
        path: /healthz/ready
        port: 80
      # length of time to wait for a pod to initialize
      # after pod startup, before applying health checking
      initialDelaySeconds: 30
      timeoutSeconds: 1
    ports:
      - containerPort: 80

正常性チェック ライブラリを配布する

正常性チェックをライブラリとして配布するには:

  1. スタンドアロン クラスとして IHealthCheck インターフェイスを実装する正常性チェックを記述します。 このクラスは、設定データにアクセスする目的で依存関係挿入 (DI)、型のアクティブ化、名前付きオプションに依存できます。

  2. 拡張メソッドを記述します。拡張メソッドを使用するアプリがその Program.cs メソッドで呼び出すパラメーターを指定します。 arg1arg2 をコンストラクター パラメーターとして受け取る、次の正常性チェックの例を考えてみましょう。

    public SampleHealthCheckWithArgs(int arg1, string arg2)
        => (_arg1, _arg2) = (arg1, arg2);
    

    先のシグネチャは、正常性チェック プローブ ロジックを処理するためには、正常性チェックにカスタム データが必要であることを示しています。 正常性チェックが拡張メソッドに登録されたときに正常性チェック インスタンスを作成するための委任にデータが提供されます。 次の例では、呼び出し元によって以下が指定されます。

    • arg1: 正常性チェックの整数データ ポイント。
    • arg2: 正常性チェックの文字列引数。
    • name: 正常性チェック名 (省略可能)。 null の場合、既定値が使用されます。
    • failureStatus: エラー状態に対してレポートされる HealthStatus (省略可能)。 null の場合、HealthStatus.Unhealthy が使用されます。
    • tags: タグの IEnumerable<string> コレクション (省略可能)。
    public static class SampleHealthCheckBuilderExtensions
    {
        private const string DefaultName = "Sample";
    
        public static IHealthChecksBuilder AddSampleHealthCheck(
            this IHealthChecksBuilder healthChecksBuilder,
            int arg1,
            string arg2,
            string? name = null,
            HealthStatus? failureStatus = null,
            IEnumerable<string>? tags = default)
        {
            return healthChecksBuilder.Add(
                new HealthCheckRegistration(
                    name ?? DefaultName,
                    _ => new SampleHealthCheckWithArgs(arg1, arg2),
                    failureStatus,
                    tags));
        }
    }
    

正常性チェック パブリッシャー

サービス コンテナーに IHealthCheckPublisher が追加されると、正常性チェック システムにより定期的に正常性チェックが実行され、結果と共に PublishAsync が呼び出されます。 このプロセスは、正常性を判断する目的で監視システムを定期的に呼び出すことを各プロセスに求めるプッシュベースの監視システム シナリオで便利です。

HealthCheckPublisherOptions を使うと次を設定できます。

  • Delay:アプリが起動した後、IHealthCheckPublisher インスタンスを実行する前に適用される初期遅延です。 遅延はスタートアップ時に一度だけ適用され、後の繰り返しには適用されません。 既定値は 5 秒です。
  • Period:IHealthCheckPublisher を実行する期間です。 既定値は 30 秒です。
  • Predicate:Predicatenull (既定値) の場合、正常性チェック パブリッシャー サービスにより登録済みのすべての正常性チェックが実行されます。 正常性チェックのサブセットを実行するには、チェックのセットをフィルター処理する関数を指定します。 述語は期間ごとに評価されます。
  • Timeout:すべての IHealthCheckPublisher インスタンスに対する正常性チェックの実行のタイムアウトです。 タイムアウトなしで実行するには InfiniteTimeSpan を使います。 既定値は 30 秒です。

次の例は、正常性パブリッシャーのレイアウトを示しています。

public class SampleHealthCheckPublisher : IHealthCheckPublisher
{
    public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            // ...
        }
        else
        {
            // ...
        }

        return Task.CompletedTask;
    }
}

HealthCheckPublisherOptions クラスには、正常性チェック パブリッシャーの動作を構成するためのプロパティが用意されています。

次の例では、正常性チェック パブリッシャーをシングルトンとして登録し、HealthCheckPublisherOptions を構成します。

builder.Services.Configure<HealthCheckPublisherOptions>(options =>
{
    options.Delay = TimeSpan.FromSeconds(2);
    options.Predicate = healthCheck => healthCheck.Tags.Contains("sample");
});

builder.Services.AddSingleton<IHealthCheckPublisher, SampleHealthCheckPublisher>();

Note

AspNetCore.Diagnostics.HealthChecks には、Application Insights など、いくつかのシステムのパブリッシャーが含まれます。

Microsoft は、AspNetCore.Diagnostics.HealthChecks の保守管理もサポートも行っていません。

依存関係の挿入と正常性チェック

正常性チェック クラス内の特定の Type のインスタンスを使用するために、依存関係の挿入を使用することができます。 依存関係の挿入は、正常性チェックにオプションまたはグローバル構成を挿入する場合に役立ちます。 依存関係の挿入を使用することは、正常性チェックを構成するための一般的なシナリオでは "ありません"。 通常、各正常性チェックは実際のテストに完全に固有のものであり、IHealthChecksBuilder 拡張メソッドを使用して構成されます。

次の例は、依存関係の挿入を使用して構成オブジェクトを取得する正常性チェックのサンプルを示したものです。

public class SampleHealthCheckWithDI : IHealthCheck
{
    private readonly SampleHealthCheckWithDiConfig _config;

    public SampleHealthCheckWithDI(SampleHealthCheckWithDiConfig config)
        => _config = config;

    public Task<HealthCheckResult> CheckHealthAsync(
        HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        var isHealthy = true;

        // use _config ...

        if (isHealthy)
        {
            return Task.FromResult(
                HealthCheckResult.Healthy("A healthy result."));
        }

        return Task.FromResult(
            new HealthCheckResult(
                context.Registration.FailureStatus, "An unhealthy result."));
    }
}

SampleHealthCheckWithDiConfig と正常性チェックをサービス コンテナーに追加する必要があります。

builder.Services.AddSingleton<SampleHealthCheckWithDiConfig>(new SampleHealthCheckWithDiConfig
{
    BaseUriToCheck = new Uri("https://sample.contoso.com/api/")
});
builder.Services.AddHealthChecks()
    .AddCheck<SampleHealthCheckWithDI>(
        "With Dependency Injection",
        tags: new[] { "inject" });

UseHealthChecks と MapHealthChecks

呼び出し元が正常性チェックにアクセスできるようにするには、次の 2 つの方法があります。

  • UseHealthChecks は、ミドルウェア パイプラインで正常性チェック要求を処理するためのミドルウェアを登録します。
  • MapHealthChecks は、正常性チェック エンドポイントを登録します。 エンドポイントは、アプリ内の他のエンドポイントと合わせてマッチされ実行されます。

UseHealthChecks 上で MapHealthChecks を使用する利点は、認可のようなエンドポイント認識ミドルウェアを使用し、マッチ ポリシーをより細かい粒度で制御できる点です。 MapHealthChecks 上で UseHealthChecks を使用する主な利点は、ミドルウェア パイプラインで正常性チェックが実行される場所を正確に制御できることです。

UseHealthChecks:

  • 要求が正常性チェック エンドポイントとマッチすると、パイプラインを終了させます。 ショートサーキットはログやその他のミドルウェアなどの不要な作業を防ぐため、多くの場合に望ましいものです。
  • 主に、パイプラインで正常性チェック ミドルウェアを構成するために使用されます。
  • null または空の PathString を持つポート上の任意のパスとマッチできます。 指定したポートに対して行われた任意の要求に対して正常性チェックの実行を許可します。
  • ソース コード

MapHealthChecks は次のことを許可します。

  • 正常性チェック用の特定のルートまたはエンドポイントのマッピング。
  • 正常性チェック エンドポイントにアクセスできる URL またはパスのカスタマイズ。
  • ルートまたは構成が異なる複数の正常性チェック エンドポイントのマッピング。 複数エンドポイントのサポート:
    • さまざまな種類の正常性チェックまたはコンポーネントに対して個別のエンドポイントを有効にします。
    • アプリの正常性のさまざまな側面を区別したり、正常性チェックのサブセットに特定の構成を適用したりするために使用されます。
  • ソース コード

その他のリソース

注意

この記事は部分的に人工知能を活用して作成しました。 公開する前に作成者が内容を確認し、必要に応じて修正しました。 AI によって生成されたコンテンツを Microsoft Learn で使用するための原則に関するページを参照してください。