A Kubernetes application can be running without being ready to handle requests. It can also appear healthy for a while before becoming stuck and unable to make progress.
These situations are common in web APIs, background workers, and distributed applications. A container may start successfully while the application is still loading configuration, establishing connections, or warming up caches. Another container may remain running even though its main processing loop has stopped responding.
Kubernetes uses health probes to detect these conditions and decide what action to take. Readiness probes determine whether a container should receive traffic. Liveness probes help Kubernetes decide whether a container needs to be restarted. Startup probes give slow-starting applications time to initialize before the other probes take effect.
Using the wrong probe can make an application less reliable. An overly aggressive liveness probe may repeatedly restart a healthy application during a temporary dependency outage. A readiness probe that checks only whether a process is running may allow traffic to reach an application that cannot handle requests.
This article explains how readiness, liveness, and startup probes work, how to configure them, and how to avoid common mistakes in production clusters.
What Is a Kubernetes Readiness Probe?
A readiness probe tells Kubernetes whether a container is ready to receive traffic.
When a readiness probe fails, Kubernetes marks the container as not ready. For workloads managed by a Deployment or another controller, the Pod can remain running while Kubernetes stops routing ordinary Service traffic to that Pod through its endpoints.
This distinction matters during application startup and temporary periods when a service cannot accept new requests.
For example, a web API may need to load its configuration, initialize required components, and prepare its request handlers before it can serve traffic. The container can be running throughout this process, but the application should not receive requests until initialization is complete.
A readiness probe can use an HTTP endpoint:
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-api
spec:
replicas: 2
selector:
matchLabels:
app: orders-api
template:
metadata:
labels:
app: orders-api
spec:
containers:
- name: orders-api
image: example/orders-api:1.0.0
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /health/ready
port: http
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
In this example, Kubernetes checks /health/ready every 10 seconds. Each probe has a two-second timeout, and three consecutive failures cause the container to be marked not ready.
The values are examples, not universal defaults for every application. Choose timings based on the application's startup behavior, request characteristics, and recovery requirements.
A readiness failure does not automatically restart the container. It changes whether the container is considered ready for traffic.
What Is a Kubernetes Liveness Probe?
A liveness probe helps Kubernetes determine whether a container should be restarted because the application is no longer functioning correctly.
For example, an application might enter a deadlocked state, stop processing its event loop, or become permanently stuck due to an internal failure. The process may still exist, but it cannot make progress.
A liveness probe can detect this condition through a dedicated endpoint:
livenessProbe:
httpGet:
path: /health/live
port: http
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
With this configuration, Kubernetes checks the liveness endpoint periodically. After three consecutive failures, it treats the container as unhealthy and restarts it according to the Pod's restart policy.
The initialDelaySeconds value delays the first probe relative to the container start. For applications with variable startup times, a startup probe is generally a more flexible way to protect initialization from premature liveness failures.
A liveness probe should answer a narrow question: can the application continue operating, or is it stuck in a state that requires a restart?
It should not fail merely because a downstream service is temporarily unavailable. If a database is down but the application can still respond, handle requests appropriately, and recover when the database returns, restarting every application instance may make the outage worse.
Readiness vs. Liveness vs. Startup
Kubernetes provides three main probe types for different stages of the container lifecycle.
Probe | Main question | Failure behavior |
|---|
Readiness | Can this container receive traffic now? | Marks the container not ready |
Liveness | Is the application stuck and in need of a restart? | Triggers a container restart after the configured failures |
Startup | Has the application completed startup? | Prevents readiness and liveness checks from taking effect until startup succeeds |
A startup probe is particularly useful for applications that need a long or unpredictable initialization period.
For example, a Java service may take several minutes to initialize, while a .NET API might start quickly in one environment and more slowly in another because of configuration loading or cache initialization.
Without a startup probe, an aggressive liveness check could restart the container before it finishes starting. A startup probe gives the application a defined startup window.
Use a Startup Probe for Slow-Starting Applications
Consider an application that can take up to two minutes to initialize. A startup probe can allow that period before readiness and liveness checks begin.
startupProbe:
httpGet:
path: /health/startup
port: http
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 30
livenessProbe:
httpGet:
path: /health/live
port: http
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: http
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
The startup probe allows up to approximately 150 seconds of failed checks before Kubernetes considers startup unsuccessful, based on the configured period and failure threshold. Actual timing can vary with probe execution and scheduling.
While the startup probe has not succeeded, Kubernetes does not run the configured liveness and readiness probes for that container. Once startup succeeds, the other probes take over.
The startup endpoint should indicate whether initialization has completed. It should not simply return success because the process exists.
For applications that start quickly, a separate startup probe may not be necessary. Use one when it meaningfully protects a slow or variable initialization process.
Implement Health Endpoints in ASP.NET Core
ASP.NET Core provides health-check support through Microsoft.Extensions.Diagnostics.HealthChecks. It can expose endpoints that Kubernetes probes call to determine whether an application is ready or alive.
Start by registering health checks and mapping separate endpoints:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks();
var app = builder.Build();
app.MapHealthChecks("/health/live");
app.MapHealthChecks("/health/ready");
app.Run();
This example demonstrates the endpoint structure, but both endpoints currently perform the same default health-check evaluation. For production use, configure checks and tags so that readiness and liveness represent different conditions.
A liveness endpoint should normally be lightweight and should not depend on every external service. A readiness endpoint can include checks for dependencies that are essential for serving requests.
For example, you can register tagged checks and filter which ones each endpoint executes:
using Microsoft.Extensions.Diagnostics.HealthChecks;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks()
.AddCheck(
"application",
() => HealthCheckResult.Healthy(),
tags: new[] { "live" })
.AddCheck(
"database",
() => HealthCheckResult.Healthy(),
tags: new[] { "ready" });
var app = builder.Build();
app.MapHealthChecks("/health/live", new()
{
Predicate = check => check.Tags.Contains("live")
});
app.MapHealthChecks("/health/ready", new()
{
Predicate = check => check.Tags.Contains("ready")
});
app.Run();
The database check in this example is a placeholder that always reports healthy. Replace it with a real database health check if database availability is required for the application to serve requests.
The example separates the endpoint responsibilities:
A production liveness check may also need an application-specific signal indicating that the service is making progress. Avoid expensive work in the liveness path because Kubernetes calls it repeatedly.
Should Liveness Check the Database?
This is one of the most important health-check design decisions.
Suppose an API depends on SQL Server. If the database becomes temporarily unavailable, a liveness probe that queries SQL Server may fail for every API instance. Kubernetes may then restart all those instances even though the application processes themselves are functioning correctly.
The restarts do not repair the database. They can also increase connection attempts and delay recovery.
A better approach is often to keep database availability in the readiness check while keeping liveness focused on whether the application itself can continue operating.
With this design, the application can stop receiving ordinary traffic while the database is unavailable. When the dependency recovers and readiness checks succeed, Kubernetes can route traffic to the application again.
There are exceptions. If the application cannot make any useful progress without a dependency and has no meaningful recovery path, a different policy may be justified. However, restart behavior should be based on a clear recovery strategy rather than assuming that every dependency failure requires a process restart.
Choose HTTP, TCP, or Exec Probes
Kubernetes supports different mechanisms for checking health.
HTTP probes
An HTTP probe sends a request to a configured endpoint and evaluates the response. This is a common choice for web APIs.
Use separate endpoints when readiness and liveness have different meanings. Keep them lightweight and avoid exposing sensitive diagnostic details through public health responses.
TCP probes
A TCP probe attempts to establish a connection to a specified port.
livenessProbe:
tcpSocket:
port: 8080
periodSeconds: 10
failureThreshold: 3
A TCP probe is useful when an application does not expose an HTTP health endpoint. However, an open port does not prove that the application can process requests correctly. It may detect a process that has stopped listening, but it cannot verify higher-level behavior.
Exec probes
An exec probe runs a command inside the container and evaluates its exit code.
livenessProbe:
exec:
command:
- /bin/sh
- -c
- test -f /tmp/app-healthy
periodSeconds: 10
failureThreshold: 3
This example checks whether a file exists. In a real application, the file would need to represent a reliable health signal, and the application would need to maintain it correctly.
Exec probes can be useful for applications without an HTTP interface, but they introduce command execution overhead and depend on the tools available in the container image. A file-existence check can also produce false confidence if the application stops working but leaves the file behind.
Choose the probe mechanism based on what it actually proves about the application.
Understand Probe Timing Settings
Several settings control how quickly Kubernetes reacts to probe failures.
Setting | Meaning |
|---|
initialDelaySeconds | Delay before the first probe starts |
periodSeconds | Interval between probes |
timeoutSeconds | Time allowed for a probe to complete |
failureThreshold | Consecutive failures required before the probe is considered failed |
successThreshold | Consecutive successes required to recover; for startup and liveness probes, it must be 1 |
terminationGracePeriodSeconds | Grace period used for termination when a liveness or startup probe triggers a restart, where configured |
For example:
readinessProbe:
httpGet:
path: /health/ready
port: 8080
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
successThreshold: 2
This readiness probe requires two consecutive successful checks to mark the container ready again after a failure. Three consecutive failures mark it not ready.
The successThreshold setting is useful for readiness probes when brief recovery does not necessarily mean the application is stable enough to receive traffic.
Do not set every timeout to the lowest possible value. A probe that times out during ordinary CPU contention or a short scheduling delay can trigger unnecessary state changes. On the other hand, very long probe intervals can delay detection of a genuine failure.
Tune these settings using measured startup times, normal response times, and the application's recovery requirements.
Common Probe Mistakes
Several configuration errors can make Kubernetes health checks less useful:
Using the same endpoint for readiness and liveness without considering their different responsibilities.
Restarting containers whenever a database or external API becomes unavailable.
Returning a successful health response before initialization has completed.
Using an overly short timeout that fails during normal resource contention.
Allowing a startup probe too little time for legitimate initialization.
Checking only whether a TCP port is open when the application needs deeper health validation.
Exposing internal dependency details through unauthenticated health endpoints.
Making health checks expensive enough to create additional load during an outage.
Assuming a readiness failure restarts the container.
Treating a successful probe as proof that every application feature is working correctly.
Health probes should provide a useful signal for a specific operational decision. A check that cannot distinguish between a recoverable dependency outage and an unrecoverable application failure may cause more harm than it prevents.
Test Probe Behavior Before Deployment
Probe configuration should be tested under realistic failure conditions, not just during normal startup.
For example, verify what happens when the database becomes unavailable, the application takes longer than expected to initialize, a request handler becomes stuck, or the container receives heavy CPU load.
Check that:
A container is not marked ready before it can handle requests.
A temporary dependency outage does not cause unnecessary restarts.
A genuinely unhealthy application can be restarted.
A slow startup is protected by the startup probe.
Readiness recovers when the application becomes healthy again.
Probe endpoints return the expected status codes.
Probe settings do not cause repeated restarts under ordinary production load.
Useful diagnostic commands include:
kubectl get pods
kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl get events --sort-by=.metadata.creationTimestamp
Replace <pod-name> with the actual Pod name. The describe output and cluster events can reveal repeated probe failures, restart counts, and other lifecycle problems.
If a container repeatedly restarts, inspect its logs and termination details before simply increasing the failure threshold. The probe may be detecting a real application defect.
Conclusion
Kubernetes readiness, liveness, and startup probes solve different problems. Readiness controls whether a container should receive traffic, liveness helps recover from an application that is no longer functioning correctly, and startup probes protect applications that need additional initialization time.
For ASP.NET Core APIs, separate lightweight health endpoints make these responsibilities easier to implement and maintain. Keep dependency checks in readiness when a dependency outage should stop traffic, and avoid making liveness depend on services whose temporary failure does not require restarting the application.
Finally, tune probe timing to the application's actual behavior and test how the system responds to failure. Well-designed probes improve traffic routing and recovery without creating unnecessary restarts during ordinary operational problems.
Join the conversation! Your thoughts help the community grow.