.NET Core

.NET Core 2.2 has been released. You can try it on Red Hat Enterprise Linux (RHEL) and OpenShift. One of the new features of ASP.NET Core is the Health Checks API.

In this article, which was written for C# Advent Calendar 2018, I show an example of how the API works with OpenShift by implementing two health checks for the Kubernetes liveness and readiness probes. Since OpenShift includes Kubernetes, this example also works well with Kubernetes.

Example code

This new Health Checks API quite works well with Kubernetes liveness and readiness probes. These probes are available in OpenShift, too.

Here is my example application to explain the Health Checks API.

And below is an example of configuring two health checks: one for the liveness probe and one for the readiness probe.

public void ConfigureServices(IServiceCollection services)
{
...

    services.AddHealthChecks()
            .AddCheck("Liveness", failureStatus: null)
            .AddCheck("Readiness", failureStatus: null);
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
    app.UseHealthChecks("/health/live", new HealthCheckOptions()
    {
        Predicate = check => check.Name == "Liveness"
    });

    app.UseHealthChecks("/health/ready", new HealthCheckOptions()
    {
        Predicate = check => check.Name == "Readiness",

    });
...
}

In the ConfigureServices method, you can enable health checks and add as many checks as you want. LivenessHealthCheck and ReadinessHealthCheck are the classes that define how to check the application's health in this project. I'll show you these classes later.

In the Configure method, you can define which health checks are responsible for the specified path. In my example, the health check whose name is Liveness is executed for /health/live and the health check whose name is Readiness is executed for /health/ready.

Below is an example implementation of the LivenessHealthCheck class. You can return the application's health status in the CheckHealthAsync method. My example returns Unhealth when the application status defined in HealthStatusData.IsLiveness is false. This status can be updated by the POST method.

Example implementation of the LivenessHealthCheck class

For more details, please refer to the code.

internal class LivenessHealthCheck : IHealthCheck
{
    private HealthStatusData data;

    public LivenessHealthCheck(HealthStatusData data)
    {
        this.data = data;
    }

    public Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken))
    {
        if (data.IsLiveness)
        {
            return Task.FromResult(HealthCheckResult.Healthy());
        }
        else
        {
            return Task.FromResult(HealthCheckResult.Unhealthy("Error"));
        }
    }
}

Working with OpenShift

My example code can be run on a local machine. However, you can try it with Kubernetes or OpenShift. If you want to try it with OpenShift, please import the ASP.NET Core 2.2 s2i image by following this document. After importing the .NET Core 2.2 s2i image, you can deploy my app to your cluster, as follows:

$ oc new-project aspnetcore22
$ oc new-app --name=healthcheckexample 'dotnet:2.2~https://github.com/tanaka-takayoshi/HealthCheckExample.git' --build-env DOTNET_STARTUP_PROJECT=HealthCheckExample
$ oc expose svc/healthcheckexample

After the deployment configuration is created, you can enable health checks in the OpenShift web console.

Enable health checks in the OpenShift web console

If you edit the deploymentconfig YAML file, the probes should be the following.

spec:
...
  template:
  ...
    spec:
      containers:
        - image: >-
            ...
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /health/live
              port: 8080
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 1
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /health/ready
              port: 8080
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 1
          ...

Now, here is the application status in the web console.

Application status in the web console

First, let's make the readiness probe unhealthy. Soon after that, you can see in the monitoring page of the web console that the readiness check has failed.

Web console showing that the Readiness check failed
Web console sowing that the Readiness check failed

You can see the same thing by using the oc get event -w command.

oc get event -w command showing that the Readiness check failed

When the readiness check fails, the pod is still running but it stops routing the traffic. Since this application has only one pod, you can't access the application.

Message showing the application is not available

You can easily scale up this application by clicking the upper arrow next to the number of the pods.

You can scale up the application

Now, since one of the two pods is healthy, you can access the application.

One of the pods is healthy, so you can access the application

Next, scale down the app to one pod and make the liveness probe unhealthy.

Scale down the app to one pod and make the Liveness probe unhealthy

When the liveness probe fails, the pod is killed and a new one is created. You can see the sequence of events.

Sequence of events after Liveness probe fails

Summary

In this article, I described how the Health Checks API in ASP.NET Core 2.2 works with OpenShift (Kubernetes) probes. You can define your appropriate logic in a class that implements the IHealthCheck interface. The readiness probe can be used when the pod is ready to serve the request. The liveness probe can be used when the pod is running.

Other resources

Last updated: January 12, 2024