Kubernetes is a powerful container orchestration platform that automates application deployment, scaling, and management. One of the key tasks in container management is ensuring that containers are healthy and ready to handle requests.
In Kubernetes, there are mechanisms known as probes: Liveness, Readiness, and Startup. With their help, Kubernetes monitors container states and makes decisions about restarting them, routing traffic, or waiting for initialization to complete.
In this article, we’ll take a detailed look at each probe, how to configure them, common mistakes when using them, and best practices. Each probe will be accompanied by a practical example.
We’ll be working through practical examples, which requires a Kubernetes cluster. You can rent a ready-made cluster using a cloud Kubernetes service. For basic service operation, one master node and one worker node with minimal configuration is enough.
Probes in Kubernetes are diagnostic checks performed by the kubelet
(an agent running on each Kubernetes node) to assess the state of containers. They help determine whether a container is functioning correctly, whether it is ready to accept network traffic, or whether it has finished initialization.
Without such checks, Kubernetes cannot know for sure whether an application is in a healthy state, which can lead to service disruptions or incorrect request routing.
There are three main types of probes in Kubernetes, each solving its own task:
These checks are necessary to ensure fault tolerance and application stability. In particular, they allow Kubernetes to:
Probes support three execution mechanisms:
Now, let’s look at each type of probe in more detail.
The Liveness Probe determines whether a running container is functioning correctly. If the check fails, Kubernetes considers the container unhealthy and automatically restarts it. This is useful in situations where the application hangs, consumes too many resources, or encounters an internal error, but the container process itself continues running.
The kubelet periodically performs the check defined in the Liveness Probe configuration. If the check fails (for example, an HTTP request returns a 500 code or a command returns a non-zero exit code), Kubernetes increases the counter of failed attempts. After reaching the threshold (set by the failureThreshold parameter), the container will be restarted automatically.
Below are the parameters used when configuring a Liveness Probe:
initialDelaySeconds
: Delay before the first check after the container starts (in seconds).periodSeconds
: Interval between checks (in seconds).timeoutSeconds
: Timeout for waiting for a response (in seconds).successThreshold
: Minimum number of successful checks for the container to be considered “healthy” (usually set to 1).failureThreshold
: Number of failed checks after which the container is considered “unhealthy.”Let’s see how to use a Liveness Probe in practice. Below is the manifest:
---
apiVersion: v1
kind: Namespace
metadata:
name: test-liveness-probe
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-liveness-probe-http
namespace: test-liveness-probe
spec:
replicas: 1
selector:
matchLabels:
app: nginx-liveness
template:
metadata:
labels:
app: nginx-liveness
spec:
containers:
- name: nginx--test-container
image: nginx:1.26.0
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
In this configuration, an Nginx web server image is used, and a Liveness Probe is set up to periodically perform an HTTP request to the root / endpoint on port 80 to monitor application health.
The first check starts 15 seconds after the container launches (initialDelaySeconds
) and is performed every 10 seconds (periodSeconds
). If the HTTP request to /healthz
returns a response code in the range 200–399, the check is considered successful. However, if three consecutive checks fail (failureThreshold
), the container will be restarted automatically.
Save the configuration above to a file named test-liveness-probe.yaml
and apply it:
kubectl apply -f test-liveness-probe.yaml
Check that the pod has started successfully:
kubectl get pods -n test-liveness-probe
As you can see in the screenshot above, the pod started successfully and is in Running
status.
Now, let’s verify that the probe works. Check the pod logs with:
kubectl logs test-liveness-probe-http-6bf85d548b-xc9lf -n test-liveness-probe
(Remember to replace the pod name test-liveness-probe-http-6bf85d548b-xc9lf
with the one displayed by the command above.)
In the output, we will see that the probe sends a request every 10 seconds and successfully receives a response.
Next, let’s test how the pod behaves if we change the probe to use a non-existent endpoint. Update the configuration like this:
livenessProbe:
httpGet:
path: /nonexistent
port: 80
Save the changes and apply them:
kubectl apply -f test-liveness-probe.yaml
Check the pod status:
kubectl get pods -n test-liveness-probe
The pod is running, but note the RESTARTS
column, which shows the number of pod restarts. In this case, the pod has restarted twice and will continue restarting. This is because of the Liveness Probe settings: if three consecutive checks fail, the container is restarted automatically.
The Liveness Probe is useful in the following cases:
The Readiness Probe determines whether a container is ready to accept incoming network traffic. If the check fails, Kubernetes removes the container from routing (for example, from a Service or Ingress object), but does not restart the container. This allows temporary isolation of a container that is not ready to handle requests, for example, during a database update or cache loading.
The kubelet performs the check similarly to the Liveness Probe. If the check succeeds, the container is considered ready, and Kubernetes includes it in traffic routing. If the check fails, the container is excluded from routing but continues running.
The Readiness Probe uses the same parameters as the Liveness Probe, but their values may differ.
Let’s look at a practical example of using a Readiness Probe. Below is a manifest that configures a readiness check using HTTP:
apiVersion: v1
kind: Namespace
metadata:
name: test-readiness-probe
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-test-deployment
namespace: test-readiness-probe
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-web-server
image: nginx:1.14.2
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 3
In this configuration, we use an Nginx web server image. The check is performed every 10 seconds on port 80 (the default port for Nginx). If the probe fails three consecutive times on port 80, the container is removed from routing. The first check begins 5 seconds after the container starts.
Save the configuration above into a file named test-readiness-probe.yaml
and apply it:
kubectl apply -f test-readiness-probe.yaml
Verify that the pod has started successfully:
kubectl get pods -n test-readiness-probe
As shown in the screenshot above, the pod started successfully and is in Running
status.
Now let’s check probe behavior in case of a failure. To “break” the container, connect to the pod and remove the index file index.html:
kubectl exec -it nginx-deployment-5c8b8b9669-q8vrh -n test-readiness-probe -- rm /usr/share/nginx/html/index.html
Next, check the pod status:
kubectl get pods -n test-readiness-probe
As seen in the screenshot above, the pod will be marked as not ready (0/1
in the READY
column).
Check the pod events with:
kubectl describe pod nginx-deployment-5c8b8b9669-q8vrh -n test-readiness-probe
In the Events
section, a message appears indicating that the Readiness Probe failed and returned a 403 error.
To make the pod accept incoming traffic again, simply delete it:
kubectl delete pod nginx-deployment-5c8b8b9669-q8vrh -n test-readiness-probe
Check pod status again:
kubectl get pods -n test-readiness-probe
The pod is now ready to work and can accept incoming network traffic.
The Readiness Probe is useful in the following cases:
The Startup Probe is intended for applications that require more time to start. It allows Kubernetes to wait for container initialization to complete before starting Liveness or Readiness checks.
Without the Startup Probe, a slow application may be restarted due to failed Liveness checks, even though it simply hasn’t finished starting yet.
The Startup Probe runs until it either succeeds or exceeds the failure threshold. Once it succeeds, Kubernetes begins running the Liveness and Readiness Probes (if configured). If the check fails, the container is restarted.
The Startup Probe uses parameters similar to other probes but typically with higher values for initialDelaySeconds and failureThreshold to account for the application’s long startup time.
Let’s see how to use a Startup Probe in practice. Here’s a configuration for an application with a long initialization time:
apiVersion: v1
kind: Namespace
metadata:
name: test-startup-probe
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: startup-demo
namespace: test-startup-probe
spec:
replicas: 1
selector:
matchLabels:
app: startup-demo
template:
metadata:
labels:
app: startup-demo
spec:
containers:
- name: demo-container
image: nginx:alpine
ports:
- containerPort: 80
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "sleep 30 && touch /usr/share/nginx/html/ready"]
startupProbe:
exec:
command: ["cat", "/usr/share/nginx/html/ready"]
failureThreshold: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
In this configuration, a container based on an Nginx image is launched, simulating a slow startup. Kubernetes uses three probes to manage container state:
Startup Probe: Checks if the container has finished starting by running cat /usr/share/nginx/html/ready
every 5 seconds (periodSeconds: 5
). If the ready file exists and is accessible (command succeeds), the container is considered started. The probe is retried up to 10 times (failureThreshold: 10
), giving a maximum of 50 seconds for a successful startup. If all attempts fail, the container restarts.
Liveness Probe: Checks whether the container continues running correctly by sending an HTTP GET request to / on port 80 every 5 seconds (periodSeconds: 5
) after an initial delay of 5 seconds (initialDelaySeconds: 5
). If the server responds with a code in the 200–399 range, the check is successful. Otherwise, the container is considered unhealthy and restarted.
Readiness Probe: Determines whether the container is ready to accept traffic by also sending an HTTP GET request to / on port 80 every 5 seconds (periodSeconds: 5
) after a 5-second delay. If successful (response code 200–399), the container is included in load balancing. If it fails, the container is excluded from routing but not restarted.
Save the configuration to a file named test-startup-probe.yaml
and apply it:
kubectl apply -f test-startup-probe.yaml
Check pod status:
kubectl get pods -n test-startup-probe
As shown in the screenshot above, the pod starts but is not ready (0/1
in the READY
column). During the first 30 seconds (because of sleep 30
in postStart
), the pod remains in Running
status but not Ready
, since the Startup Probe is waiting for the /usr/share/nginx/html/ready
file to appear.
After 30 seconds, the pod becomes ready for work.
The Startup Probe is useful for:
Applications with long initialization (e.g., loading large machine learning models).
Containers that connect to external services during startup.
Using incorrect values. Small values for periodSeconds or timeoutSeconds can lead to false positives due to temporary delays. You should set reasonable values (for example, periodSeconds: 10, timeoutSeconds: 3).
Missing endpoints for checks. If the application does not define endpoints (e.g., /healthz
or /ready
), HTTP checks will fail. Implement the necessary endpoints in the application during development.
Overloading the container. Frequent checks can overload the application, especially if they perform complex operations. Use lightweight checks, such as TCP instead of HTTP, if that is sufficient.
Ignoring the Startup Probe. Without a Startup Probe, slow applications may be restarted because of failed Liveness checks. You need to use and properly configure a Startup Probe for applications with long startup times.
Separate Liveness and Readiness probes. The Liveness Probe should check whether the application is running, while the Readiness Probe should check whether it is ready to accept network traffic. For example, Liveness can check for process existence, while Readiness can check the availability of external dependencies.
Use a Startup Probe for slow applications. If an application takes more than 10–15 seconds to start, configure a Startup Probe to avoid premature restarts.
Implement lightweight checks. HTTP checks should return minimal data to reduce application load. TCP checks are preferable if checking port availability is sufficient.
Take dependencies into account. If the application depends on a database or another service, configure the Readiness Probe to check the availability of those dependencies.
Liveness, Readiness, and Startup Probes in Kubernetes are critical tools that allow you to:
Proper probe configuration requires understanding how the application works and carefully tuning the parameters.
Using probes in Kubernetes not only increases application stability but also simplifies infrastructure management by automating responses to failures and state changes.