ASP.NET Core의 상태 검사

작성자: Glenn Condron

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 Core DbContext를 사용하여 데이터베이스를 검사합니다. 데이터베이스 시나리오를 탐색하려면 샘플 앱:

참고

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

다른 상태 검사 시나리오는 관리 포트에 대해 상태 검사를 필터링하는 방법을 보여줍니다. 샘플 앱을 사용하려면 관리 URL과 관리 포트가 포함된 Properties/launchSettings.json 파일을 만들어야 합니다. 자세한 내용은 포트별 필터링 섹션을 참조하세요.

기본 상태 프로브

많은 앱의 경우, 요청을 처리할 수 있는 앱의 가용성(활동성)을 보고하는 기본 상태 검사 구성으로 앱 상태를 충분히 파악할 수 있습니다.

기본 구성은 상태 검사 서비스를 등록하고 상태 검사 미들웨어를 호출하여 URL 엔드포인트에서 상태 응답을 사용하여 응답합니다. 기본적으로 특정 종속성이나 하위 시스템을 테스트하기 위해 특정 상태 검사가 등록되지 않습니다. 상태 엔드포인트 URL에서 응답할 수 있는 경우 앱 상태가 좋은 것으로 간주됩니다. 기본 응답 기록기는 상태(HealthStatus)를 클라이언트에 대한 일반 텍스트 응답으로 기록하여 HealthStatus.Healthy, HealthStatus.Degraded 또는 HealthStatus.Unhealthy 상태를 나타냅니다.

Startup.ConfigureServicesAddHealthChecks에 상태 검사 서비스를 등록합니다. Startup.Configure에서 MapHealthChecks를 호출하여 상태 검사 엔드포인트를 만듭니다.

샘플 앱에서 상태 검사 엔드포인트는 /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 메서드는 상태를 Healthy, Degraded 또는 Unhealthy로 나타내는 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가 예외를 throw하는 경우, HealthReportEntry.StatusFailureStatus로 설정된 새 HealthReportEntry가 반환됩니다. 이는 AddCheck로 정의되며(상태 검사 서비스 등록 섹션 참조) 처음에 검사가 실패한 원인이 된 내부 예외를 포함합니다. Description은 예외의 메시지로 설정됩니다.

상태 검사 서비스 등록

ExampleHealthCheck 형식은 Startup.ConfigureServicesAddCheck으로 상태 검사 서비스에 추가됩니다.

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는 람다 함수를 실행할 수도 있습니다. 다음 예제에서 상태 검사 이름은 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를 호출하여 상태 검사 엔드포인트에 대해 허용된 호스트를 하나 이상 지정합니다. 호스트는 punycode가 아닌 유니코드여야 하고 포트를 포함할 수 있습니다. 컬렉션을 제공하지 않으면 모든 호스트가 허용됩니다.

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

자세한 내용은 포트별 필터링 섹션을 참조하세요.

권한 부여 필요

RequireAuthorization을 호출하여 상태 검사 요청 엔드포인트에서 권한 부여 미들웨어를 실행합니다. RequireAuthorization 오버로드는 하나 이상의 권한 부여 정책을 허용합니다. 정책을 제공하지 않으면 기본 권한 부여 정책이 사용됩니다.

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

원본 간 요청(CORS) 사용

브라우저에서 수동으로 상태 검사를 수행하는 것이 일반적이지는 않지만, 상태 검사 엔드포인트에 RequireCors를 호출하여 CORS 미들웨어를 사용하도록 설정할 수 있습니다. RequireCors 오버로드는 CORS 정책 작성기 대리자(CorsPolicyBuilder) 또는 정책 이름을 허용합니다. 정책을 제공하지 않으면 기본 CORS 정책이 사용됩니다. 자세한 내용은 ASP.NET Core에서 CORS (원본 간 요청) 사용를 참조하세요.

상태 검사 옵션

HealthCheckOptions는 다음과 같은 상태 검사 동작을 사용자 지정할 수 있는 기회를 제공합니다.

상태 검사 필터링

기본적으로 상태 검사 미들웨어는 등록된 모든 상태 검사를 실행합니다. 상태 검사 하위 세트를 실행하려면 Predicate 옵션에 부울 값을 반환하는 함수를 제공합니다. 다음 예제에서는 상태 검사의 Tags 속성이 foo_tag 또는 baz_tag와 일치하는 경우에만 true가 반환되는 함수의 조건문에서 태그(bar_tag)에 의해 Bar 상태 검사가 필터링됩니다.

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-Control, ExpiresPragma 헤더를 설정하거나 재정의합니다. 값이 true인 경우 미들웨어는 응답 캐시 헤더를 수정하지 않습니다.

Startup.Configure의 경우

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

출력 사용자 지정

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);
    }
}

두 번째 예제에서는 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));
}

샘플 앱에서 WriteResponse 버전의 Newtonsoft.Json을 사용할 수 있도록 CustomWriterStartup.csSYSTEM_TEXT_JSON 전처리기 지시문을 주석 처리합니다.

상태 검사 API는 사용자가 선택한 모니터링 시스템에만 적용되는 형식이므로 복합 JSON 반환 형식에 대한 기본 제공 지원을 제공하지 않습니다. 앞의 예제에서 응답을 필요에 따라 사용자 지정합니다. System.Text.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.Configure에서 MapHealthChecks를 호출하여 만듭니다.

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

샘플 앱을 사용하여 데이터베이스 프로브 시나리오를 실행하려면 명령 셸의 프로젝트 폴더에서 다음 명령을 실행합니다.

dotnet run --scenario db

참고

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

Entity Framework Core DbContext 프로브

DbContext 검사는 앱이 EF Core DbContext에 대해 구성된 데이터베이스와 통신할 수 있음을 확인합니다. DbContext 검사는 다음과 같은 앱에서 지원됩니다.

AddDbContextCheck<TContext>DbContext에 대한 상태 검사를 등록합니다. DbContext는 메서드에 TContext로 제공됩니다. 오버로드는 오류 상태, 태그 및 사용자 지정 테스트 쿼리를 구성할 수 있습니다.

기본적으로 다음과 같습니다.

  • 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.Configure에서 MapHealthChecks를 호출하여 만듭니다.

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

별도의 준비 상태 및 활동성 프로브

일부 호스팅 시나리오에서 두 개의 앱 상태를 구분하는 한 쌍의 상태 검사가 사용됩니다.

  • ‘준비 상태’는 앱이 정상적으로 실행 중이지만 요청을 받을 준비가 되지 않았음을 나타냅니다.
  • ‘활동성’은 앱의 작동이 중단되어 다시 시작해야 함을 나타냅니다.

다음 예제를 참조하세요. 앱이 요청을 처리할 준비가 되려면 먼저 대용량 구성 파일을 다운로드해야 합니다. 앱에서 파일 다운로드를 여러 번 다시 시도할 수 있으므로 초기 다운로드가 실패하더라도 앱을 다시 시작하지 않는 것이 좋습니다. ‘활동성 프로브’를 사용하여 프로세스의 활동성을 설명하며, 추가 검사를 수행하지 않습니다. 또한 구성 파일이 다운로드되기 전에는 앱에 요청을 보내지 못하게 합니다. ‘준비 상태 프로브’를 사용하여 다운로드에 성공하여 앱이 요청을 받을 준비가 될 때까지 “준비되지 않음” 상태를 표시합니다.

샘플 앱에는 호스팅된 서비스에서 장기 실행 시작 작업 완료를 보고하는 상태 검사가 있습니다. StartupHostedServiceHealthCheck는 장기 실행 작업이 완료되면(StartupHostedServiceHealthCheck.cs) 호스팅된 서비스를 true로 설정할 수 있는 속성 StartupTaskCompleted를 노출합니다.

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.ConfigureServicesAddCheck에 등록됩니다. 호스팅된 서비스가 상태 검사에서 속성을 설정해야 하기 때문에 상태 확인도 서비스 컨테이너(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.Configure에서 MapHealthChecks를 호출하여 만듭니다. 샘플 앱에서 상태 검사 엔드포인트는 다음 위치에 만들어집니다.

  • 준비 상태 검사를 위해 /health/ready. 준비 상태 검사는 ready 태그가 있는 상태 검사에서 상태 검사를 필터링합니다.
  • 활동성 검사를 위해 /health/live. 활동성 검사는 HealthCheckOptions.Predicate에서 false를 반환하여 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 설명서의 활동성 및 준비 상태 프로브 구성을 참조하세요.

다음 예제는 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

사용자 지정 응답 기록기가 있는 메트릭 기반 프로브

샘플 앱은 사용자 지정 응답 기록기가 있는 메모리 상태를 보여줍니다.

앱이 일정한 메모리 임계값(샘플 앱의 경우 1GB)을 초과하여 사용하는 경우 MemoryHealthCheck는 성능이 저하된 상태를 보고합니다. 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 등록된 서비스는 상태 검사 서비스 및 미들웨어에 사용할 수 있습니다. 상태 확인 서비스를 Singleton 서비스로 등록하는 것이 좋습니다.

샘플 앱의 CustomWriterStartup.cs에서:

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

상태 검사 엔드포인트는 Startup.Configure에서 MapHealthChecks를 호출하여 만듭니다. 상태 검사를 실행하는 경우 WriteResponse 대리자가 사용자 지정 JSON 응답을 출력하는 출력에 대한 <Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions.ResponseWriter> 속성에 제공됩니다.

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

WriteResponse 대리자는 CompositeHealthCheckResult를 JSON 객체로 형식 지정하고 상태 검사 응답을 위해 JSON 출력을 생성합니다. 자세한 내용은 출력 사용자 지정 섹션을 참조하세요.

샘플 앱을 사용하여 사용자 지정 응답 기록기 출력으로 메트릭 기반 프로브를 실행하려면 명령 셸의 프로젝트 폴더에서 다음 명령을 실행합니다.

dotnet run --scenario writer

참고

AspNetCore.Diagnostics.HealthChecks에는 디스크 스토리지 및 최댓값 활동성 검사를 포함하여 메트릭 기반 상태 확인 시나리오가 포함됩니다.

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

포트별 필터링

지정된 포트에 대한 상태 검사 요청을 제한하는 포트를 지정하는 URL 패턴을 사용하여 MapHealthChecksRequireHost를 호출합니다. 이는 일반적으로 컨테이너 환경에서 서비스 모니터링을 위해 포트를 노출하는 데 사용됩니다.

샘플 앱은 환경 변수 구성 공급자를 사용하여 포트를 구성합니다. 포트는 launchSettings.json 파일에서 설정되고 환경 변수를 통해 구성 공급자에게 전달됩니다. 또한 관리 포트에서 요청을 수신하도록 서버를 구성해야 합니다.

샘플 앱을 사용하여 관리 포트 구성을 보여주려면 launchSettings.json 파일을 Properties 폴더에 만듭니다.

샘플 앱의 다음 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.Configure에서 MapHealthChecks를 호출하여 상태 검사 엔드포인트를 만듭니다.

샘플 앱에서 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
    });
}

참고

코드에서 관리 포트를 명시적으로 설정하여 샘플 앱에 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이 발생하는 경우 사용자가 상태 검사 실패 상태를 구성할 수 있도록 FailureStatusHealthCheckResult와 함께 반환됩니다.

    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 구현을 활성화하기 위해 샘플은 DI(종속성 주입) 컨테이너에서 ReadinessPublisher를 싱글톤 서비스로 등록합니다.

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>();

참고

AspNetCore.Diagnostics.HealthChecksApplication Insights를 포함하여 몇몇 시스템에 대한 게시자를 포함합니다.

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

MapWhen으로 상태 검사 제한

MapWhen을 사용하여 상태 검사 엔드포인트에 대한 요청 파이프라인을 조건부로 분기합니다.

다음 예제에서 MapWhenapi/HealthCheck 엔드포인트에 대한 GET 요청을 받는 경우 상태 검사 미들웨어를 활성화하도록 요청 파이프라인을 분기합니다.

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 Core DbContext를 사용하여 데이터베이스를 검사합니다. 데이터베이스 시나리오를 탐색하려면 샘플 앱:

참고

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

다른 상태 검사 시나리오는 관리 포트에 대해 상태 검사를 필터링하는 방법을 보여줍니다. 샘플 앱을 사용하려면 관리 URL과 관리 포트가 포함된 Properties/launchSettings.json 파일을 만들어야 합니다. 자세한 내용은 포트별 필터링 섹션을 참조하세요.

기본 상태 프로브

많은 앱의 경우, 요청을 처리할 수 있는 앱의 가용성(활동성)을 보고하는 기본 상태 검사 구성으로 앱 상태를 충분히 파악할 수 있습니다.

기본 구성은 상태 검사 서비스를 등록하고 상태 검사 미들웨어를 호출하여 URL 엔드포인트에서 상태 응답을 사용하여 응답합니다. 기본적으로 특정 종속성이나 하위 시스템을 테스트하기 위해 특정 상태 검사가 등록되지 않습니다. 상태 엔드포인트 URL에서 응답할 수 있는 경우 앱 상태가 좋은 것으로 간주됩니다. 기본 응답 기록기는 상태(HealthStatus)를 클라이언트에 대한 일반 텍스트 응답으로 기록하여 HealthStatus.Healthy, HealthStatus.Degraded 또는 HealthStatus.Unhealthy 상태를 나타냅니다.

Startup.ConfigureServicesAddHealthChecks에 상태 검사 서비스를 등록합니다. Startup.Configure에서 MapHealthChecks를 호출하여 상태 검사 엔드포인트를 만듭니다.

샘플 앱에서 상태 검사 엔드포인트는 /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 메서드는 상태를 Healthy, Degraded 또는 Unhealthy로 나타내는 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."));
    }
}

상태 검사 서비스 등록

ExampleHealthCheck 형식은 Startup.ConfigureServicesAddCheck으로 상태 검사 서비스에 추가됩니다.

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는 람다 함수를 실행할 수도 있습니다. 다음 예제에서 상태 검사 이름은 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를 호출하여 상태 검사 엔드포인트에 대해 허용된 호스트를 하나 이상 지정합니다. 호스트는 punycode가 아닌 유니코드여야 하고 포트를 포함할 수 있습니다. 컬렉션을 제공하지 않으면 모든 호스트가 허용됩니다.

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

자세한 내용은 포트별 필터링 섹션을 참조하세요.

권한 부여 필요

RequireAuthorization을 호출하여 상태 검사 요청 엔드포인트에서 권한 부여 미들웨어를 실행합니다. RequireAuthorization 오버로드는 하나 이상의 권한 부여 정책을 허용합니다. 정책을 제공하지 않으면 기본 권한 부여 정책이 사용됩니다.

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

원본 간 요청(CORS) 사용

브라우저에서 수동으로 상태 검사를 수행하는 것이 일반적이지는 않지만, 상태 검사 엔드포인트에 RequireCors를 호출하여 CORS 미들웨어를 사용하도록 설정할 수 있습니다. RequireCors 오버로드는 CORS 정책 작성기 대리자(CorsPolicyBuilder) 또는 정책 이름을 허용합니다. 정책을 제공하지 않으면 기본 CORS 정책이 사용됩니다. 자세한 내용은 ASP.NET Core에서 CORS (원본 간 요청) 사용를 참조하세요.

상태 검사 옵션

HealthCheckOptions는 다음과 같은 상태 검사 동작을 사용자 지정할 수 있는 기회를 제공합니다.

상태 검사 필터링

기본적으로 상태 검사 미들웨어는 등록된 모든 상태 검사를 실행합니다. 상태 검사 하위 세트를 실행하려면 Predicate 옵션에 부울 값을 반환하는 함수를 제공합니다. 다음 예제에서는 상태 검사의 Tags 속성이 foo_tag 또는 baz_tag와 일치하는 경우에만 true가 반환되는 함수의 조건문에서 태그(bar_tag)에 의해 Bar 상태 검사가 필터링됩니다.

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-Control, ExpiresPragma 헤더를 설정하거나 재정의합니다. 값이 true인 경우 미들웨어는 응답 캐시 헤더를 수정하지 않습니다.

Startup.Configure의 경우

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

출력 사용자 지정

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);
    }
}

두 번째 예제에서는 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));
}

샘플 앱에서 Newtonsoft.Json 버전의 WriteResponse을 사용할 수 있도록 CustomWriterStartup.csSYSTEM_TEXT_JSON 전처리기 지시문을 주석으로 처리합니다.

상태 검사 API는 사용자가 선택한 모니터링 시스템에만 적용되는 형식이므로 복합 JSON 반환 형식에 대한 기본 제공 지원을 제공하지 않습니다. 앞의 예제에서 응답을 필요에 따라 사용자 지정합니다. System.Text.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.Configure에서 MapHealthChecks를 호출하여 만듭니다.

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

샘플 앱을 사용하여 데이터베이스 프로브 시나리오를 실행하려면 명령 셸의 프로젝트 폴더에서 다음 명령을 실행합니다.

dotnet run --scenario db

참고

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

Entity Framework Core DbContext 프로브

DbContext 검사는 앱이 EF Core DbContext에 대해 구성된 데이터베이스와 통신할 수 있음을 확인합니다. DbContext 검사는 다음과 같은 앱에서 지원됩니다.

AddDbContextCheck<TContext>DbContext에 대한 상태 검사를 등록합니다. DbContext는 메서드에 TContext로 제공됩니다. 오버로드는 오류 상태, 태그 및 사용자 지정 테스트 쿼리를 구성할 수 있습니다.

기본적으로 다음과 같습니다.

  • 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.Configure에서 MapHealthChecks를 호출하여 만듭니다.

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

별도의 준비 상태 및 활동성 프로브

일부 호스팅 시나리오에서 두 개의 앱 상태를 구분하는 한 쌍의 상태 검사가 사용됩니다.

  • ‘준비 상태’는 앱이 정상적으로 실행 중이지만 요청을 받을 준비가 되지 않았음을 나타냅니다.
  • ‘활동성’은 앱의 작동이 중단되어 다시 시작해야 함을 나타냅니다.

다음 예제를 참조하세요. 앱이 요청을 처리할 준비가 되려면 먼저 대용량 구성 파일을 다운로드해야 합니다. 앱에서 파일 다운로드를 여러 번 다시 시도할 수 있으므로 초기 다운로드가 실패하더라도 앱을 다시 시작하지 않는 것이 좋습니다. ‘활동성 프로브’를 사용하여 프로세스의 활동성을 설명하며, 추가 검사를 수행하지 않습니다. 또한 구성 파일이 다운로드되기 전에는 앱에 요청을 보내지 못하게 합니다. ‘준비 상태 프로브’를 사용하여 다운로드에 성공하여 앱이 요청을 받을 준비가 될 때까지 “준비되지 않음” 상태를 표시합니다.

샘플 앱에는 호스팅된 서비스에서 장기 실행 시작 작업 완료를 보고하는 상태 검사가 있습니다. StartupHostedServiceHealthCheck는 장기 실행 작업이 완료되면(StartupHostedServiceHealthCheck.cs) 호스팅된 서비스를 true로 설정할 수 있는 속성 StartupTaskCompleted를 노출합니다.

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.ConfigureServicesAddCheck에 등록됩니다. 호스팅된 서비스가 상태 검사에서 속성을 설정해야 하기 때문에 상태 확인도 서비스 컨테이너(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.Configure에서 MapHealthChecks를 호출하여 만듭니다. 샘플 앱에서 상태 검사 엔드포인트는 다음 위치에 만들어집니다.

  • 준비 상태 검사를 위해 /health/ready. 준비 상태 검사는 ready 태그가 있는 상태 검사에서 상태 검사를 필터링합니다.
  • 활동성 검사를 위해 /health/live. 활동성 검사는 HealthCheckOptions.Predicate에서 false를 반환하여 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 설명서의 활동성 및 준비 상태 프로브 구성을 참조하세요.

다음 예제는 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

사용자 지정 응답 기록기가 있는 메트릭 기반 프로브

샘플 앱은 사용자 지정 응답 기록기가 있는 메모리 상태를 보여줍니다.

앱이 일정한 메모리 임계값(샘플 앱의 경우 1GB)을 초과하여 사용하는 경우 MemoryHealthCheck는 성능이 저하된 상태를 보고합니다. 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 등록된 서비스는 상태 검사 서비스 및 미들웨어에 사용할 수 있습니다. 상태 확인 서비스를 Singleton 서비스로 등록하는 것이 좋습니다.

샘플 앱의 CustomWriterStartup.cs에서:

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

상태 검사 엔드포인트는 Startup.Configure에서 MapHealthChecks를 호출하여 만듭니다. 상태 검사를 실행하는 경우 WriteResponse 대리자가 사용자 지정 JSON 응답을 출력하는 출력에 대한 <Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions.ResponseWriter> 속성에 제공됩니다.

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

WriteResponse 대리자는 CompositeHealthCheckResult를 JSON 객체로 형식 지정하고 상태 검사 응답을 위해 JSON 출력을 생성합니다. 자세한 내용은 출력 사용자 지정 섹션을 참조하세요.

샘플 앱을 사용하여 사용자 지정 응답 기록기 출력으로 메트릭 기반 프로브를 실행하려면 명령 셸의 프로젝트 폴더에서 다음 명령을 실행합니다.

dotnet run --scenario writer

참고

AspNetCore.Diagnostics.HealthChecks에는 디스크 스토리지 및 최댓값 활동성 검사를 포함하여 메트릭 기반 상태 확인 시나리오가 포함됩니다.

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

포트별 필터링

지정된 포트에 대한 상태 검사 요청을 제한하는 포트를 지정하는 URL 패턴을 사용하여 MapHealthChecksRequireHost를 호출합니다. 이는 일반적으로 컨테이너 환경에서 서비스 모니터링을 위해 포트를 노출하는 데 사용됩니다.

샘플 앱은 환경 변수 구성 공급자를 사용하여 포트를 구성합니다. 포트는 launchSettings.json 파일에서 설정되고 환경 변수를 통해 구성 공급자에게 전달됩니다. 또한 관리 포트에서 요청을 수신하도록 서버를 구성해야 합니다.

샘플 앱을 사용하여 관리 포트 구성을 보여주려면 launchSettings.json 파일을 Properties 폴더에 만듭니다.

샘플 앱의 다음 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.Configure에서 MapHealthChecks를 호출하여 상태 검사 엔드포인트를 만듭니다.

샘플 앱에서 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
    });
}

참고

코드에서 관리 포트를 명시적으로 설정하여 샘플 앱에 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이 발생하는 경우 사용자가 상태 검사 실패 상태를 구성할 수 있도록 FailureStatusHealthCheckResult와 함께 반환됩니다.

    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 구현을 활성화하기 위해 샘플은 DI(종속성 주입) 컨테이너에서 ReadinessPublisher를 싱글톤 서비스로 등록합니다.

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>();

참고

AspNetCore.Diagnostics.HealthChecksApplication Insights를 포함하여 몇몇 시스템에 대한 게시자를 포함합니다.

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

MapWhen으로 상태 검사 제한

MapWhen을 사용하여 상태 검사 엔드포인트에 대한 요청 파이프라인을 조건부로 분기합니다.

다음 예제에서 MapWhenapi/HealthCheck 엔드포인트에 대한 GET 요청을 받는 경우 상태 검사 미들웨어를 활성화하도록 요청 파이프라인을 분기합니다.

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.App 메타패키지를 참조하거나 Microsoft.AspNetCore.Diagnostics.HealthChecks 패키지에 대한 패키지 참조를 추가합니다.

샘플 앱은 여러 시나리오의 상태 검사를 보여주는 시작 코드를 제공합니다. 데이터베이스 프로브 시나리오는 AspNetCore.Diagnostics.HealthChecks를 사용하여 데이터베이스 연결의 상태를 검사합니다. DbContext 프로브 시나리오는 EF Core DbContext를 사용하여 데이터베이스를 검사합니다. 데이터베이스 시나리오를 탐색하려면 샘플 앱:

참고

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

다른 상태 검사 시나리오는 관리 포트에 대해 상태 검사를 필터링하는 방법을 보여줍니다. 샘플 앱을 사용하려면 관리 URL과 관리 포트가 포함된 Properties/launchSettings.json 파일을 만들어야 합니다. 자세한 내용은 포트별 필터링 섹션을 참조하세요.

기본 상태 프로브

많은 앱의 경우, 요청을 처리할 수 있는 앱의 가용성(활동성)을 보고하는 기본 상태 검사 구성으로 앱 상태를 충분히 파악할 수 있습니다.

기본 구성은 상태 검사 서비스를 등록하고 상태 검사 미들웨어를 호출하여 URL 엔드포인트에서 상태 응답을 사용하여 응답합니다. 기본적으로 특정 종속성이나 하위 시스템을 테스트하기 위해 특정 상태 검사가 등록되지 않습니다. 상태 엔드포인트 URL에서 응답할 수 있는 경우 앱 상태가 좋은 것으로 간주됩니다. 기본 응답 기록기는 상태(HealthStatus)를 클라이언트에 대한 일반 텍스트 응답으로 기록하여 HealthStatus.Healthy, HealthStatus.Degraded 또는 HealthStatus.Unhealthy 상태를 나타냅니다.

Startup.ConfigureServicesAddHealthChecks에 상태 검사 서비스를 등록합니다. Startup.Configure의 요청 처리 파이프라인에 있는 UseHealthChecks로 상태 검사 미들웨어용 엔드포인트를 추가합니다.

샘플 앱에서 상태 검사 엔드포인트는 /health(BasicStartup.cs)에 만들어집니다.

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

    public void Configure(IApplicationBuilder app)
    {
        app.UseHealthChecks("/health");
    }
}

샘플 앱을 사용하여 기본 구성 시나리오를 실행하려면 명령 셸의 프로젝트 폴더에서 다음 명령을 실행합니다.

dotnet run --scenario basic

Docker 예

Docker는 기본 상태 검사 구성을 사용하는 앱의 상태를 검사하는 데 사용할 수 있는 기본 제공 HEALTHCHECK 지시문을 제공합니다.

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

상태 검사 만들기

상태 검사는 IHealthCheck 인터페이스를 구현하여 만듭니다. CheckHealthAsync 메서드는 상태를 Healthy, Degraded 또는 Unhealthy로 나타내는 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("The check indicates a healthy result."));
        }

        return Task.FromResult(
            HealthCheckResult.Unhealthy("The check indicates an unhealthy result."));
    }
}

상태 검사 서비스 등록

ExampleHealthCheck 형식은 AddCheckStartup.ConfigureServices의 상태 검사 서비스에 추가됩니다.

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는 람다 함수를 실행할 수도 있습니다. 다음 Startup.ConfigureServices 예제에서 상태 검사 이름은 Example로 지정되고 검사는 항상 정상 상태를 반환합니다.

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

상태 검사 미들웨어 사용

Startup.Configure에서 엔드포인트 URL 또는 상대 경로를 사용하여 처리 파이프라인에서 UseHealthChecks를 호출합니다.

app.UseHealthChecks("/health");

상태 검사가 특정 포트에서 수신 대기해야 하는 경우 UseHealthChecks의 오버로드를 사용하여 포트를 설정합니다(포트별 필터링 섹션에 자세히 설명되어 있음).

app.UseHealthChecks("/health", port: 8000);

상태 검사 옵션

HealthCheckOptions는 다음과 같은 상태 검사 동작을 사용자 지정할 수 있는 기회를 제공합니다.

상태 검사 필터링

기본적으로 상태 검사 미들웨어는 등록된 모든 상태 검사를 실행합니다. 상태 검사 하위 세트를 실행하려면 Predicate 옵션에 부울 값을 반환하는 함수를 제공합니다. 다음 예제에서는 상태 검사의 Tags 속성이 foo_tag 또는 baz_tag와 일치하는 경우에만 true가 반환되는 함수의 조건문에서 태그(bar_tag)에 의해 Bar 상태 검사가 필터링됩니다.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Diagnostics.HealthChecks;

public void ConfigureServices(IServiceCollection services)
{
    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" });
}

public void Configure(IApplicationBuilder app)
{
    app.UseHealthChecks("/health", new HealthCheckOptions()
    {
        Predicate = (check) => check.Tags.Contains("foo_tag") ||
            check.Tags.Contains("baz_tag")
    });
}

HTTP 상태 코드 사용자 지정

ResultStatusCodes를 사용하여 상태를 HTTP 상태 코드에 매핑하는 작업을 사용자 지정할 수 있습니다. 다음 StatusCodes 할당은 미들웨어에서 사용되는 기본값입니다. 요구 사항에 맞게 상태 코드 값을 변경합니다.

Startup.Configure의 경우

//using Microsoft.AspNetCore.Diagnostics.HealthChecks;
//using Microsoft.Extensions.Diagnostics.HealthChecks;

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

캐시 헤더 표시 안 함

AllowCachingResponses는 응답 캐싱을 방지하기 위해 상태 검사 미들웨어가 HTTP 헤더를 프로브 응답에 추가할지 여부를 제어합니다. 값이 false(기본값)인 경우 미들웨어는 응답 캐싱을 방지하기 위해 Cache-Control, ExpiresPragma 헤더를 설정하거나 재정의합니다. 값이 true인 경우 미들웨어는 응답 캐시 헤더를 수정하지 않습니다.

Startup.Configure의 경우

//using Microsoft.AspNetCore.Diagnostics.HealthChecks;
//using Microsoft.Extensions.Diagnostics.HealthChecks;

app.UseHealthChecks("/health", new HealthCheckOptions()
{
    AllowCachingResponses = false
});

출력 사용자 지정

ResponseWriter 옵션은 응답을 기록하는 데 사용되는 대리자를 가져오거나 설정합니다. 기본 대리자는 HealthReport.Status의 문자열 값을 사용하여 최소 일반 텍스트 응답을 기록합니다.

Startup.Configure의 경우

// using Microsoft.AspNetCore.Diagnostics.HealthChecks;
// using Microsoft.Extensions.Diagnostics.HealthChecks;

app.UseHealthChecks("/health", new HealthCheckOptions()
{
    ResponseWriter = WriteResponse
});

기본 대리자는 HealthReport.Status의 문자열 값을 사용하여 최소 일반 텍스트 응답을 기록합니다. 다음 사용자 지정 대리자 WriteResponse는 사용자 지정 JSON 응답을 출력합니다.

private static Task WriteResponse(HttpContext httpContext, HealthReport result)
{
    httpContext.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 httpContext.Response.WriteAsync(
        json.ToString(Formatting.Indented));
}

상태 검사 시스템은 사용자가 선택한 모니터링 시스템에만 적용되는 형식이므로 복합 JSON 반환 형식에 대한 기본 제공 지원을 제공하지 않습니다. 필요에 따라 앞의 예제에서 JObject를 자유롭게 사용자 지정할 수 있습니다.

데이터베이스 프로브

상태 검사는 데이터베이스 쿼리를 지정하여 데이터베이스가 정상적으로 응답하는지를 나타내기 위해 부울 테스트로서 실행할 수 있습니다.

샘플 앱은 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": "Debug"
    },
    "Console": {
      "IncludeScopes": "true"
    }
  }
}

Startup.ConfigureServicesAddHealthChecks에 상태 검사 서비스를 등록합니다. 샘플 앱은 데이터베이스의 연결 문자열(DbHealthStartup.cs)을 사용하여 AddSqlServer 메서드를 호출합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddHealthChecks()
        .AddSqlServer(Configuration["ConnectionStrings:DefaultConnection"]);
}

Startup.Configure의 앱 처리 파이프라인에서 상태 검사 미들웨어를 호출합니다.

app.UseHealthChecks("/health");

샘플 앱을 사용하여 데이터베이스 프로브 시나리오를 실행하려면 명령 셸의 프로젝트 폴더에서 다음 명령을 실행합니다.

dotnet run --scenario db

참고

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

Entity Framework Core DbContext 프로브

DbContext 검사는 앱이 EF Core DbContext에 대해 구성된 데이터베이스와 통신할 수 있음을 확인합니다. DbContext 검사는 다음과 같은 앱에서 지원됩니다.

AddDbContextCheck<TContext>DbContext에 대한 상태 검사를 등록합니다. DbContext는 메서드에 TContext로 제공됩니다. 오버로드는 오류 상태, 태그 및 사용자 지정 테스트 쿼리를 구성할 수 있습니다.

기본적으로 다음과 같습니다.

  • DbContextHealthCheck는 EF Core의 CanConnectAsync 메서드를 호출합니다. AddDbContextCheck 메서드 오버로드를 사용하여 상태를 검사할 때 실행되는 작업을 사용자 정의할 수 있습니다.
  • 상태 검사의 이름은 TContext 형식의 이름입니다.

샘플 앱에서 AppDbContextAddDbContextCheck에 제공되고 Startup.ConfigureServices의 서비스로서 등록됩니다(DbContextHealthStartup.cs).

public void ConfigureServices(IServiceCollection services)
{
    services.AddHealthChecks()
        .AddDbContextCheck<AppDbContext>();

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

샘플 앱에서 UseHealthChecksStartup.Configure에서 상태 검사 미들웨어를 추가합니다.

app.UseHealthChecks("/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

별도의 준비 상태 및 활동성 프로브

일부 호스팅 시나리오에서 두 개의 앱 상태를 구분하는 한 쌍의 상태 검사가 사용됩니다.

  • ‘준비 상태’는 앱이 정상적으로 실행 중이지만 요청을 받을 준비가 되지 않았음을 나타냅니다.
  • ‘활동성’은 앱의 작동이 중단되어 다시 시작해야 함을 나타냅니다.

다음 예제를 참조하세요. 앱이 요청을 처리할 준비가 되려면 먼저 대용량 구성 파일을 다운로드해야 합니다. 앱에서 파일 다운로드를 여러 번 다시 시도할 수 있으므로 초기 다운로드가 실패하더라도 앱을 다시 시작하지 않는 것이 좋습니다. ‘활동성 프로브’를 사용하여 프로세스의 활동성을 설명하며, 추가 검사를 수행하지 않습니다. 또한 구성 파일이 다운로드되기 전에는 앱에 요청을 보내지 못하게 합니다. ‘준비 상태 프로브’를 사용하여 다운로드에 성공하여 앱이 요청을 받을 준비가 될 때까지 “준비되지 않음” 상태를 표시합니다.

샘플 앱에는 호스팅된 서비스에서 장기 실행 시작 작업 완료를 보고하는 상태 검사가 있습니다. StartupHostedServiceHealthCheck는 장기 실행 작업이 완료되면(StartupHostedServiceHealthCheck.cs) 호스팅된 서비스를 true로 설정할 수 있는 속성 StartupTaskCompleted를 노출합니다.

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.ConfigureServicesAddCheck에 등록됩니다. 호스팅된 서비스가 상태 검사에서 속성을 설정해야 하기 때문에 상태 확인도 서비스 컨테이너(LivenessProbeStartup.cs)에 등록됩니다.

public void ConfigureServices(IServiceCollection services)
{
    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");
    });

    // The following workaround permits adding an IHealthCheckPublisher 
    // instance to the service container when one or more other hosted 
    // services have already been added to the app. This workaround
    // won't be required with the release of ASP.NET Core 3.0. For more 
    // information, see: https://github.com/aspnet/Extensions/issues/639.
    services.TryAddEnumerable(
        ServiceDescriptor.Singleton(typeof(IHostedService), 
            typeof(HealthCheckPublisherOptions).Assembly
                .GetType(HealthCheckServiceAssembly)));

    services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();
}

Startup.Configure의 앱 처리 파이프라인에서 상태 검사 미들웨어를 호출합니다. 샘플 앱에서 상태 검사 엔드포인트는 활동성 검사의 경우 /health/ready에, 준비 상태 검사의 경우 /health/live에 만들어집니다. 준비 상태 검사는 ready 태그가 있는 상태 검사에서 상태 검사를 필터링합니다. 활동성 검사는 HealthCheckOptions.Predicate에서 false를 반환하여 StartupHostedServiceHealthCheck를 필터링합니다(자세한 내용은 상태 검사 필터링 참조).

app.UseHealthChecks("/health/ready", new HealthCheckOptions()
{
    Predicate = (check) => check.Tags.Contains("ready"), 
});

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

샘플 앱을 사용하여 준비 상태/활동성 구성 시나리오를 실행하려면 명령 셸의 프로젝트 폴더에서 다음 명령을 실행합니다.

dotnet run --scenario liveness

브라우저에서 15초가 경과할 때까지 /health/ready를 여러 번 방문합니다. 상태 검사는 첫 15초 동안 Unhealthy 를 보고합니다. 15초 후, 엔드포인트는 Healthy 를 보고하여 호스트된 서비스에 의해 장기 실행 작업이 완료되었음을 나타냅니다.

이 예제에서는 2초 지연을 사용하여 첫 번째 준비 검사를 실행하는 상태 검사 게시자(IHealthCheckPublisher 구현)도 만듭니다. 자세한 내용은 상태 검사 게시자 섹션을 참조하세요.

Kubernetes 예제

별도의 준비 상태 및 활동성 검사를 사용하는 것은 Kubernetes와 같은 환경에서 유용합니다. Kubernetes에서 앱은 기본 데이터베이스 가용성 테스트와 같이 요청을 수락하기 전에 시간이 많이 걸리는 시작 작업을 수행해야 할 수도 있습니다. 별도의 검사를 사용하면 오케스트레이터가 앱이 작동하고 있지만 아직 준비가 되지 않았는지 또는 앱이 시작되지 않았는지 구분할 수 있습니다. Kubernetes의 준비 상태 및 활동성 프로브에 대한 자세한 내용은 Kubernetes 설명서의 활동성 및 준비 상태 프로브 구성을 참조하세요.

다음 예제는 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

사용자 지정 응답 기록기가 있는 메트릭 기반 프로브

샘플 앱은 사용자 지정 응답 기록기가 있는 메모리 상태를 보여줍니다.

앱이 일정한 메모리 임계값(샘플 앱의 경우 1GB)을 초과하여 사용하는 경우 MemoryHealthCheck는 비정상적인 상태를 보고합니다. 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 : HealthStatus.Unhealthy;

        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 등록된 서비스는 상태 검사 서비스 및 미들웨어에 사용할 수 있습니다. 상태 확인 서비스를 Singleton 서비스로 등록하는 것이 좋습니다.

샘플 앱(CustomWriterStartup.cs)에서:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHealthChecks()
        .AddMemoryHealthCheck("memory");
}

Startup.Configure의 앱 처리 파이프라인에서 상태 검사 미들웨어를 호출합니다. 상태 검사가 실행될 때 사용자 정의 JSON 응답을 출력하기 위해 ResponseWriter 속성에 WriteResponse 대리자가 제공됩니다.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseHealthChecks("/health", new HealthCheckOptions()
    {
        // This custom writer formats the detailed status as JSON.
        ResponseWriter = WriteResponse
    });
}

WriteResponse 메서드는 CompositeHealthCheckResult를 JSON 객체로 형식 지정하고 상태 검사 응답을 위해 JSON 출력을 생성합니다.

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

    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 httpContext.Response.WriteAsync(
        json.ToString(Formatting.Indented));
}

샘플 앱을 사용하여 사용자 지정 응답 기록기 출력으로 메트릭 기반 프로브를 실행하려면 명령 셸의 프로젝트 폴더에서 다음 명령을 실행합니다.

dotnet run --scenario writer

참고

AspNetCore.Diagnostics.HealthChecks에는 디스크 스토리지 및 최댓값 활동성 검사를 포함하여 메트릭 기반 상태 확인 시나리오가 포함됩니다.

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

포트별 필터링

포트와 함께 UseHealthChecks를 호출하면 지정된 포트에 대한 상태 검사 요청을 제한합니다. 이는 일반적으로 컨테이너 환경에서 서비스 모니터링을 위해 포트를 노출하는 데 사용됩니다.

샘플 앱은 환경 변수 구성 공급자를 사용하여 포트를 구성합니다. 포트는 launchSettings.json 파일에서 설정되고 환경 변수를 통해 구성 공급자에게 전달됩니다. 또한 관리 포트에서 요청을 수신하도록 서버를 구성해야 합니다.

샘플 앱을 사용하여 관리 포트 구성을 보여주려면 launchSettings.json 파일을 Properties 폴더에 만듭니다.

샘플 앱의 다음 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에 상태 검사 서비스를 등록합니다. UseHealthChecks에 대한 호출은 관리 포트를 지정합니다(ManagementPortStartup.cs).

public class ManagementPortStartup
{
    public ManagementPortStartup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

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

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseHealthChecks("/health", port: Configuration["ManagementPort"]);

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync(
                "Navigate to " + 
                $"http://localhost:{Configuration["ManagementPort"]}/health " +
                "to see the health status.");
        });
    }
}

참고

코드에서 URL과 관리 포트를 명시적으로 설정하여 샘플 앱에 launchSettings.json 파일을 만들지 않도록 할 수 있습니다. WebHostBuilder가 만들어진 Program.cs 에서 UseUrls에 호출을 추가하고 앱의 정상적인 응답 엔드포인트와 관리 포트 엔드포인트를 제공합니다. UseHealthChecks가 호출되는 ManagementPortStartup.cs 에서 관리 포트를 명시적으로 지정합니다.

Program.cs:

return new WebHostBuilder()
    .UseConfiguration(config)
    .UseUrls("http://localhost:5000/;http://localhost:5001/")
    .ConfigureLogging(builder =>
    {
        builder.SetMinimumLevel(LogLevel.Trace);
        builder.AddConfiguration(config);
        builder.AddConsole();
    })
    .UseKestrel()
    .UseStartup(startupType)
    .Build();

ManagementPortStartup.cs:

app.UseHealthChecks("/health", port: 5001);

샘플 앱을 사용하여 관리 포트 구성 시나리오를 실행하려면 명령 셸의 프로젝트 폴더에서 다음 명령을 실행합니다.

dotnet run --scenario port

상태 검사 라이브러리 배포

상태 검사를 라이브러리로 배포하려면 다음과 같이 수행합니다.

  1. IHealthCheck 인터페이스를 독립 실행형 클래스로 구현하는 상태 검사를 기록합니다. 클래스는 DI(종속성 주입), 유형 활성화 및 명명된 옵션에 의존하여 구성 데이터에 액세스할 수 있습니다.

    CheckHealthAsync의 상태 검사 논리에서:

    • data1data2는 메서드에서 프로브의 상태 검사 논리를 실행하는 데 사용됩니다.
    • AccessViolationException이 처리됩니다.

    AccessViolationException이 발생하는 경우 사용자가 상태 검사 실패 상태를 구성할 수 있도록 FailureStatusHealthCheckResult와 함께 반환됩니다.

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Diagnostics.HealthChecks;
    
    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초입니다.

경고

ASP.NET Core 2.2 릴리스에서 IHealthCheckPublisher 구현은 Period 설정을 적용하지 않으며, Delay 값을 설정합니다. 이 문제는 ASP.NET Core 3.0에서 해결되었습니다.

샘플 앱에서 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 구현을 활성화하기 위해 샘플은 DI(종속성 주입) 컨테이너에서 ReadinessPublisher를 싱글톤 서비스로 등록합니다.

public void ConfigureServices(IServiceCollection services)
{
    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");
    });

    // The following workaround permits adding an IHealthCheckPublisher 
    // instance to the service container when one or more other hosted 
    // services have already been added to the app. This workaround
    // won't be required with the release of ASP.NET Core 3.0. For more 
    // information, see: https://github.com/aspnet/Extensions/issues/639.
    services.TryAddEnumerable(
        ServiceDescriptor.Singleton(typeof(IHostedService), 
            typeof(HealthCheckPublisherOptions).Assembly
                .GetType(HealthCheckServiceAssembly)));

    services.AddSingleton<IHealthCheckPublisher, ReadinessPublisher>();
}

참고

다음 해결 방법에서는 하나 이상의 다른 호스트 서비스가 이미 앱에 추가되었을 때 서비스 컨테이너에 IHealthCheckPublisher 인스턴스를 추가하는 것을 허용합니다. ASP.NET Core 3.0에는 이 해결 방법이 필요하지 않습니다.

private const string HealthCheckServiceAssembly =
    "Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckPublisherHostedService";

services.TryAddEnumerable(
    ServiceDescriptor.Singleton(typeof(IHostedService),
        typeof(HealthCheckPublisherOptions).Assembly
            .GetType(HealthCheckServiceAssembly)));

참고

AspNetCore.Diagnostics.HealthChecksApplication Insights를 포함하여 몇몇 시스템에 대한 게시자를 포함합니다.

AspNetCore.Diagnostics.HealthChecks는 Microsoft에서 유지 관리하거나 지원하지 않습니다.

MapWhen으로 상태 검사 제한

MapWhen을 사용하여 상태 검사 엔드포인트에 대한 요청 파이프라인을 조건부로 분기합니다.

다음 예제에서 MapWhenapi/HealthCheck 엔드포인트에 대한 GET 요청을 받는 경우 상태 검사 미들웨어를 활성화하도록 요청 파이프라인을 분기합니다.

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

app.UseMvc();

자세한 내용은 ASP.NET Core 미들웨어 기본 사항를 참조하세요.