On this page
Kubernetes can tell that your container process is running, but it cannot tell whether your application is actually working. A .NET API can be alive as a process and still be stuck in a deadlock, waiting for a database connection, or busy warming up its caches. Probes are how you teach Kubernetes to see the difference.
Think of a hospital ward. A nurse checks a patient's pulse regularly (is the patient alive?), a doctor decides when the patient is well enough to receive visitors (is the patient ready?), and during recovery from surgery nobody checks the usual vitals until the patient has woken up (is the patient still starting?). Kubernetes has one probe for each of these questions.
This lesson covers the three probe types, the four ways to run a probe, the timing parameters, and how to wire them to ASP.NET Core health checks so your Pods restart when they are broken and receive traffic only when they are ready.
What you will learn
- The difference between liveness, readiness and startup probes and what Kubernetes does when each one fails
- The four probe mechanisms:
httpGet,tcpSocket,execandgrpc - How to tune
initialDelaySeconds,periodSeconds,timeoutSeconds,successThresholdandfailureThreshold - How to expose separate liveness and readiness endpoints in ASP.NET Core
- The most common probe mistakes and how to avoid them
Why probes matter
Without probes, Kubernetes only knows whether the container's main process is running. That leads to two classic problems:
- A new Pod is added to the Service as soon as the container starts, so users hit an application that is still booting and get errors.
- A Pod whose application has hung keeps running forever, because the process has not exited, and keeps receiving traffic it cannot serve.
Probes solve both. The kubelet on each node runs them periodically and acts on the result.
The three probe types
| Probe | Question it answers | On failure |
|---|---|---|
livenessProbe | Is the container still healthy, or is it stuck? | The kubelet kills the container and restarts it according to restartPolicy. |
readinessProbe | Is the container ready to receive traffic right now? | The Pod is removed from the Service endpoints. The container is not restarted. |
startupProbe | Has the application finished starting? | Liveness and readiness probes are held back until it succeeds. If it never succeeds within its budget, the container is restarted. |
Probe mechanisms
Every probe uses exactly one of four mechanisms to check the container:
| Mechanism | How it works | Best for |
|---|---|---|
httpGet | Sends an HTTP GET. Any status from 200 to 399 is a success. | ASP.NET Core and other web apps |
tcpSocket | Tries to open a TCP connection to a port. Success if the connection opens. | Databases, brokers, non-HTTP servers |
exec | Runs a command inside the container. Exit code 0 is a success. | Workers and legacy apps without a port |
grpc | Calls the standard gRPC Health Checking Protocol. | gRPC services |
An HTTP probe looks like this:
A TCP probe and an exec probe:
A gRPC probe needs the service to implement grpc.health.v1.Health, which ASP.NET Core gRPC supports through the Grpc.AspNetCore.HealthChecks package:
Probe parameters
All three probe types share the same timing parameters:
| Field | Default | Meaning |
|---|---|---|
initialDelaySeconds | 0 | Seconds to wait after the container starts before the first probe |
periodSeconds | 10 | How often to run the probe |
timeoutSeconds | 1 | How long to wait for a response before counting a failure |
successThreshold | 1 | Consecutive successes needed to become healthy again (must be 1 for liveness and startup) |
failureThreshold | 3 | Consecutive failures before Kubernetes acts |
The time Kubernetes tolerates before acting is roughly failureThreshold × periodSeconds. With the defaults, a failing liveness probe restarts the container after about 30 seconds.
Startup probes for slow applications
Some .NET applications take a while to start: they run EF Core migrations, load large caches or warm up a JIT. If the liveness probe starts too early, it kills the container before it has finished booting, and the Pod ends up in CrashLoopBackOff.
You could raise initialDelaySeconds on the liveness probe, but then a genuinely broken container is detected late forever. The startup probe fixes this: it allows a long startup budget once, and then gets out of the way.
This gives the app up to 30 × 5 = 150 seconds to start. As soon as the startup probe succeeds once, the liveness and readiness probes take over with their own, tighter settings.
Health checks in ASP.NET Core
ASP.NET Core ships with a health check middleware. The key design decision is to expose two endpoints with different meanings:
/healthz/liveanswers "is the process able to respond at all?" and checks nothing external./healthz/readyanswers "can I serve requests right now?" and checks dependencies such as the database.
A complete example
This Deployment combines all three probes for a .NET Order API:
Here is what happens when the Pod starts. Only the startup probe runs for the first few seconds. When /healthz/live answers, the startup probe is done, and the liveness and readiness probes begin. The Pod joins the Service only after /healthz/ready succeeds, which means the database connection works.
Common mistakes
- Liveness probe that checks dependencies. As shown above, this can cause a cascading restart of every Pod.
- Identical liveness and readiness endpoints with no startup probe. A slow start then triggers restarts before the app is up.
- Timeouts that are too tight. The default
timeoutSecondsof 1 is often too short for a busy .NET app during a garbage collection or a CPU spike. Raise it to 2 or 3 seconds. - Expensive probe endpoints. The probe runs every few seconds on every replica. Keep it cheap and do not run heavy queries.
- Redirects to HTTPS. If
UseHttpsRedirectionanswers a plain HTTP probe with a 307, it is still a success for Kubernetes (200 to 399), but the probe is not testing what you think. Probe the HTTP port directly.
Hands-on: see probes in action
Step 1 — Deploy a Pod with a failing readiness probe
Save this as probe-demo.yaml. It uses nginx and probes a file that does not exist yet:
The Pod shows 0/1 in the READY column while its status is Running. The container is running, but it is not ready.
Step 2 — Inspect the probe failures
In the Events section you will see Readiness probe failed messages. Because it is only a readiness failure, the container is not restarted.
Step 3 — Make the Pod ready
Within five seconds the probe succeeds and the Pod switches to 1/1. It would now be included in a Service's endpoints.
Step 4 — Break liveness on purpose
The liveness probe now gets a 404, fails three times in a row, and the kubelet restarts the container. The RESTARTS column goes to 1 and kubectl describe pod probe-demo shows Liveness probe failed: HTTP probe failed with statuscode: 404. Clean up with kubectl delete pod probe-demo.
Summary
- Probes let the kubelet check the health of your application, not just whether its process is running.
- A failed liveness probe restarts the container. A failed readiness probe only removes the Pod from Service endpoints. A startup probe delays the other two while a slow app boots.
- Probes use one of four mechanisms:
httpGet,tcpSocket,execorgrpc. - Tune
periodSeconds,timeoutSecondsandfailureThreshold. Kubernetes acts after aboutfailureThreshold × periodSeconds. - In ASP.NET Core, expose a dependency-free
/healthz/liveendpoint and a/healthz/readyendpoint that checks dependencies, using tagged health checks. - Never put external dependency checks in the liveness probe, and keep probe endpoints cheap.
With probes in place, Kubernetes restarts broken Pods automatically and sends traffic only to Pods that are ready to handle it.