Configure Liveness and Readiness Probes

KubernetesBeginner
Practice Now

Introduction

Logs, events, exec, and port-forwarding help you inspect an application. Probes let Kubernetes inspect the application continuously. A readiness probe answers, "Should this Pod receive traffic?" A liveness probe answers, "Should this container be restarted?"

In this lab, you will configure readiness and liveness separately. First, you will create an application that only becomes Ready after it creates a /ready endpoint. Then you will create another application with a liveness probe, remove its health file with kubectl exec, and observe Kubernetes restart the container.

Prepare a Probe Practice Namespace

In this step, you will prepare a clean namespace for probe practice.

Start in /home/labex/project. You will keep the probe manifests in this directory.

mkdir -p /home/labex/project
cd /home/labex/project

Check that the Kubernetes API server is reachable. If the VM has just started and the node is not ready yet, wait a few seconds and run the command again.

kubectl get nodes --request-timeout=5s

Expected output includes:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

Wait until the cluster networking Pod is Ready. Probes and Services depend on healthy Pod networking.

kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s

Expected output:

pod/calico-node-... condition met

Create a namespace named ckad-prep-probes and set it as the current namespace:

kubectl create namespace ckad-prep-probes
kubectl config set-context --current --namespace=ckad-prep-probes

Confirm the current namespace:

kubectl config view --minify --output 'jsonpath={..namespace}'; echo

Expected output:

ckad-prep-probes

Configure a Readiness Probe

In this step, you will configure a readiness probe and observe that the Service only uses ready Pods.

The container starts an HTTP server immediately, but it creates /www/ready a few seconds later. The readiness probe checks GET /ready on port 8080. Until that path exists, the Pod can be Running but not Ready, and the Service should not send traffic to it.

Create readiness-web.yaml:

cat > readiness-web.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: readiness-web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: readiness-web
  template:
    metadata:
      labels:
        app: readiness-web
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: web
        image: busybox:1.36
        command:
        - /bin/sh
        - -c
        - |
          mkdir -p /www
          echo readiness-ok > /www/index.html
          (sleep 12; echo ready > /www/ready) &
          httpd -f -p 8080 -h /www
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 1
          periodSeconds: 2
          failureThreshold: 1
---
apiVersion: v1
kind: Service
metadata:
  name: readiness-web
spec:
  selector:
    app: readiness-web
  ports:
  - port: 80
    targetPort: 8080
EOF

Apply the manifest and look at the Pods shortly after creation:

kubectl apply -f readiness-web.yaml
sleep 3
kubectl get pods -l app=readiness-web

Expected output may show Pods that are Running but not yet Ready:

NAME                             READY   STATUS    RESTARTS   AGE
readiness-web-...                0/1     Running   0          ...

Wait for the Deployment to become available:

kubectl rollout status deployment/readiness-web --timeout=120s

Expected output:

deployment "readiness-web" successfully rolled out

Inspect the Service endpoints through EndpointSlice. After the readiness probe passes, the Service should have two ready endpoints.

kubectl get endpointslice -l kubernetes.io/service-name=readiness-web

Expected output includes:

NAME                ADDRESSTYPE   PORTS   ENDPOINTS
readiness-web-...   IPv4          8080    ... + 1 more...

Create a client Pod and test the Service:

kubectl run probe-client --image=busybox:1.36 --restart=Never --command -- sleep 3600
kubectl wait --for=condition=Ready pod/probe-client --timeout=120s
kubectl exec probe-client -- wget -qO- http://readiness-web

Expected output:

readiness-ok

Configure a Liveness Probe

In this step, you will configure a liveness probe that checks a health file.

A liveness probe decides whether Kubernetes should restart a container. This example uses an exec probe that runs test -f /tmp/healthy inside the container. The container creates that file when it starts, so it begins healthy.

Create liveness-web.yaml:

cat > liveness-web.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: liveness-web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: liveness-web
  template:
    metadata:
      labels:
        app: liveness-web
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: web
        image: busybox:1.36
        command:
        - /bin/sh
        - -c
        - |
          touch /tmp/healthy
          mkdir -p /www
          echo liveness-ok > /www/index.html
          httpd -f -p 8080 -h /www
        ports:
        - containerPort: 8080
        livenessProbe:
          exec:
            command:
            - test
            - -f
            - /tmp/healthy
          initialDelaySeconds: 3
          periodSeconds: 3
          failureThreshold: 1
EOF

Apply the manifest and wait for the Deployment:

kubectl apply -f liveness-web.yaml
kubectl rollout status deployment/liveness-web --timeout=120s

Expected output includes:

deployment.apps/liveness-web created
deployment "liveness-web" successfully rolled out

Store the Pod name and confirm the health file exists:

LIVE_POD="$(kubectl get pods -l app=liveness-web -o jsonpath='{.items[0].metadata.name}')"
echo "$LIVE_POD"
kubectl exec "$LIVE_POD" -- test -f /tmp/healthy
echo "health file exists"

Expected output includes the Pod name and:

health file exists

Describe the Pod and look for the liveness probe configuration:

kubectl describe pod "$LIVE_POD" | grep -A3 'Liveness:'

Expected output includes:

Liveness:  exec [test -f /tmp/healthy] delay=3s timeout=1s period=3s

Trigger a Liveness Restart

In this step, you will remove the health file and watch the liveness probe restart the container.

The Pod object can stay the same while the container inside it restarts. That is why you will watch the container restart count instead of expecting a new Pod name.

Store the current Pod name:

LIVE_POD="$(kubectl get pods -l app=liveness-web -o jsonpath='{.items[0].metadata.name}')"
echo "$LIVE_POD"

Remove the health file from inside the container:

kubectl exec "$LIVE_POD" -- rm /tmp/healthy

Watch the restart count until it becomes greater than zero. The liveness probe runs every three seconds, so this may take a short moment.

for i in $(seq 1 20); do
  RESTARTS="$(kubectl get pod "$LIVE_POD" -o jsonpath='{.status.containerStatuses[0].restartCount}')"
  echo "restart-count=$RESTARTS"
  if [ "$RESTARTS" != "0" ]; then
    break
  fi
  sleep 3
done

Expected output eventually includes:

restart-count=1

After the container restarts, the startup command creates /tmp/healthy again. Confirm the file is back:

kubectl exec "$LIVE_POD" -- test -f /tmp/healthy
echo "health file recreated"

Expected output:

health file recreated

Read the Pod events and look for the liveness failure:

kubectl describe pod "$LIVE_POD" | sed -n '/Events:/,$p'

Expected output includes:

Warning  Unhealthy  ...  Liveness probe failed
Normal   Killing    ...  Container web failed liveness probe

Summary

You configured both major application probes. The readiness probe controlled when Pods joined Service endpoints, while the liveness probe restarted a container after its health file was removed. You also inspected EndpointSlices, Pod descriptions, restart counts, and events to connect probe configuration to visible Kubernetes behavior.