Implementing Docker Health Checks in .NET Core
Ensuring your containerized applications are healthy is crucial for reliable deployments. Docker provides a built-in health check mechanism that allows you to define how Docker determines if your container is running and functional. This guide explains how to implement health checks for your .NET Core applications.
What are Docker Health Checks?
A Docker health check is a command that Docker runs periodically inside your container. Based on the exit status of this command, Docker marks the container as:
starting: The health check is running for the first time.healthy: The command exited with status code 0.unhealthy: The command exited with a non-zero status code.none: No health check is configured.
Docker can then use this health status to perform actions like restarting unhealthy containers or preventing traffic from being sent to them.
Implementing Health Checks in .NET Core
The most common and recommended way to implement health checks in .NET Core applications is by using the Microsoft.Extensions.Diagnostics.HealthChecks NuGet package.
1. Install the NuGet Package
First, add the package to your .NET Core project:
dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks.AspNetCore
2. Configure Health Checks in Startup.cs (or `Program.cs` for .NET 6+)
You need to register the health check services and map an endpoint for Docker to query.
For .NET 5 and earlier (Startup.cs):
// In ConfigureServices method
services.AddHealthChecks();
// In Configure method
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/health"); // The endpoint Docker will poll
});
For .NET 6 and later (Program.cs):
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddHealthChecks(); // Register health check services
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.MapHealthChecks("/health"); // Map the health check endpoint
app.MapGet("/", () => "Hello World!"); // Example endpoint
app.Run();
3. Add Custom Health Checks (Optional but Recommended)
While the basic setup checks if your application is running, you often need to check the health of external dependencies like databases, caches, or external APIs.
Create a custom health check by implementing the IHealthCheck interface:
using Microsoft.Extensions.Diagnostics.HealthChecks;
using System.Threading;
using System.Threading.Tasks;
public class MyDatabaseHealthCheck : IHealthCheck
{
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
bool isHealthy = CheckDatabaseConnection(); // Implement your actual DB check
if (isHealthy)
{
return Task.FromResult(HealthCheckResult.Healthy("A healthy result."));
}
else
{
return Task.FromResult(HealthCheckResult.Unhealthy("An unhealthy result.", exception: new System.Exception("Could not connect to the database.")));
}
}
private bool CheckDatabaseConnection()
{
// Simulate a database connection check
// In a real application, you would try to establish a connection
// or execute a simple query.
return true; // Replace with actual logic
}
}
Register your custom health check:
// In ConfigureServices method (or Program.cs builder.Services)
services.AddHealthChecks()
.AddCheck<MyDatabaseHealthCheck>("Database"); // Name the check "Database"
You can also add checks for specific dependencies directly:
// Example for SQL Server
services.AddHealthChecks()
.AddSqlServer("YourConnectionString", name: "Database");
// Example for Redis
services.AddHealthChecks()
.AddRedis("YourRedisConnectionString", name: "Cache");
Advanced Configuration
The MapHealthChecks method accepts options to configure timeout, presence of status codes, and readiness checks. For readiness checks (used with Kubernetes), you'd typically map a different endpoint.
Configuring Dockerfile
To leverage the .NET Core health checks, you need to configure Docker's HEALTHCHECK instruction in your Dockerfile.
# Use an appropriate base image
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
# ... other build steps ...
# Copy your published application
COPY /publish .
# Expose the port your application runs on
EXPOSE 80
# Define the health check
# Make sure your application is running and accessible on port 80
# The CMD instruction might be different depending on your setup
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 CMD curl -f http://localhost:80/health || exit 1
--interval: How often to run the check.--timeout: How long to wait for the check to complete.--start-period: Grace period for the container to start. Health checks are suppressed during this time.--retries: Number of consecutive failures before marking the container as unhealthy.
Important Note on Health Check Endpoint
The CMD in the HEALTHCHECK instruction should execute a command that returns an exit code of 0 if healthy. Using curl against the /health endpoint is a common and effective pattern.
Testing Health Checks
After building your Docker image and running the container, you can inspect its health status using:
docker ps
Look for the STATUS column. It will show (healthy) or (unhealthy).
You can also view detailed health check logs using:
docker inspect --format='{{json .State.Health}}' <container_id>
Best Practices
- Keep health checks lightweight and fast.
- Check critical dependencies, not just application startup.
- Use appropriate
start-periodto allow your application time to initialize. - Configure
retriesto avoid false positives due to transient network issues. - Consider separate health and readiness checks if using orchestrators like Kubernetes.