<p>Our aim is to horizontally scale a .NET Core 2.0 Web API using Kubernetes. The Web API application will be served by Kestrel.</p>

<p>It looks like we can gracefully handle the termination of pods by configuring Kestrel's shutdown timeout so now we are looking into how to probe the application to determine readiness and liveness.</p>

<p>Would it be enough to simply probe the Web API with a HTTP request? If so, would it be a good idea to create a new healthcheck controller to handle these probing requests or would it make more sense to probe an actual endpoint that would be consumed in normal use?</p>

<p>What should we consider when differentiating between the liveness and readiness probes?</p>

<p>I would recommend to perform health checks through separate endpoints.
In general, there are a number of good reasons for doing so, like:</p>

<ol>
<li>Checking that the application is live/ready or, more in general, in a healthy status is not necessarily the same as sending a user request to your web service. When performing health checks you should define what makes your web service healthy: this could be e.g. checking access to external resources, like database.</li>
<li>It is easier to control who can actually perform health checks through your endpoints.</li>
<li>More in general, you do not want to mess up with the actual service functionalities: you would otherwise need to re-think the way you do health checks when maintaining your service's functionalities. E.g. if your service interacts with a database, in a health checks context you want to verify the connection to the database is fine, but you do not actually care much about the data being manipulated internally by your service.</li>
<li>Things get even more complicated if your web service is not stateless: in such case, you will need to make sure data remain consistent independently from your health checks.</li>
</ol>

<p>As you pointed out, a good way to avoid any of the above could be setting up a separate Controller to handle health checks.</p>

<p>As an alternative option, there is a standard library available in ASP.NET Core for enabling <a href="https://learn.microsoft.com/en-us/dotnet/standard/microservices-architecture/implement-resilient-applications/monitor-app-health" rel="noreferrer">Health Checks</a> on your web service: at the time of writing this answer, it is not officially part of ASP.NET Core and no NuGet packages are available yet, but there is a plan for this to happen on future releases. For now, you can easily pull the code from the <a href="https://github.com/dotnet-architecture/HealthChecks" rel="noreferrer">Official Repository</a> and include it in your solution as explained in the <a href="https://learn.microsoft.com/en-us/dotnet/standard/microservices-architecture/implement-resilient-applications/monitor-app-health" rel="noreferrer">Microsoft documentation</a>.
This is currently planned to be included in ASP.NET Core 2.2 as described in the <a href="https://github.com/aspnet/Announcements/issues/307" rel="noreferrer">ASP.NET Core 2.2 Roadmap</a>.</p>

<p>I personally find it very elegant, as you will configure everything through the <code>Startup.cs</code> and <code>Program.cs</code> and won't need to explicitly create a new endpoint as the library already handles that for you.</p>

<p>I have been using it in a few projects and I would definitely recommend it.
The repository includes an <a href="https://github.com/dotnet-architecture/HealthChecks/tree/dev/samples/SampleHealthChecker.AspNetCore" rel="noreferrer">example</a> specific for ASP.NET Core projects you can use to get quickly up to speed.</p>

<h1>Liveness vs Readiness</h1>

<p>In Kubernetes, you may then setup liveness and readiness probes through HTTP: as explained in the <a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/" rel="noreferrer">Kubernetes documentation</a>, while the setup for both is almost identical, Kubernetes takes different actions depending on the probe:</p>

<p><strong>Liveness probe</strong> from <a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/" rel="noreferrer">Kubernetes documentation</a>:</p>

<blockquote>
  <p>Many applications running for long periods of time eventually transition to broken states, and cannot recover except by being restarted. Kubernetes provides liveness probes to detect and remedy such situations.</p>
</blockquote>

<p><strong>Readiness probe</strong> from <a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/" rel="noreferrer">Kubernetes documentation</a>:</p>

<blockquote>
  <p>Sometimes, applications are temporarily unable to serve traffic. For example, an application might need to load large data or configuration files during startup. In such cases, you don’t want to kill the application, but you don’t want to send it requests either. Kubernetes provides readiness probes to detect and mitigate these situations. A pod with containers reporting that they are not ready does not receive traffic through Kubernetes Services.</p>
</blockquote>

<p>So, while an unhealthy response to a liveness probe will cause the Pod (and so, the application) to be killed, an unhealthy response to a readiness probe will simply cause the Pod to receive no traffic until it gets back to a healthy status.</p>

<p><strong>What to consider when differentiating liveness and readiness probes?</strong></p>

<p>For liveness probe:
I would recommend to define what makes your application healthy, i.e. minimum requirements for user consumption, and implement health checks based on that.
This typically involves external resources or applications running as separate processes, e.g. databases, web services, etc.
You may define health checks by using ASP.NET Core Health Checks library or manually with a separate Controller.</p>

<p>For readiness probe:
You simply want to load your service to verify it actually responds in time and so allows Kubernetes to balance traffic accordingly. Trivially (and in most cases as suggested by Lukas in another answer), you may use the same exact endpoint you would use for liveness but setting up different timeouts, but this then really depends on your needs and requirements.</p>
