Fix a Broken Readiness Probe and Add Liveness and Startup Probes
Deployment `web` in `health-check` should run two nginx replicas. Its readiness probe uses a nonexistent path, leaving the new pods unready. The application listens on port 80, named `http`, and serves a successful response at `/`. Liveness and startup probes are missing.
Live lab access
This scenario is included in Free Practice. Choose from 6 fixed labs with 5 shared sessions per week, automatic grading, hints, solutions, AI Lab Coach and saved progress.
Create an account for this free lab →
Explore the six free labs with AI Lab Coach →
Read the brief on any device. Use a desktop or laptop for the terminal lab. Nothing starts until you choose Start.
The task
Deployment web in health-check should run two nginx replicas. Its readiness probe uses a nonexistent path, leaving the new pods unready. The application listens on port 80, named http, and serves a successful response at /. Liveness and startup probes are missing.
Requirements
1. Correct readiness to HTTP GET / on the application port, checked every 5 seconds.
2. Add liveness using HTTP GET / on the application port, checked every 10 seconds.
3. Add a startup probe using HTTP GET /, checked every 2 seconds with failureThreshold 30.
4. Ensure both replicas become available. Keep image nginx:1.27.5, two replicas, and the existing application configuration.
Both the named port http and numeric port 80 are accepted. Probe the container itself; do not override the HTTP host.
Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster.
Startup, readiness and liveness: one gate, one traffic switch, one restart trigger
The three probes answer different questions, and the kubelet reacts to each one differently. A failed startup or liveness probe gets the container killed and restarted under the Pod's restart policy. A failed readiness probe kills nothing; it only takes the Pod out of its Services' endpoints. Picking the wrong probe type turns a brief hiccup into a restart loop, which is why the exam expects you to know which is which.
container starts ──→ startupProbe (others paused until it passes, budget = failureThreshold × periodSeconds)
├─→ readinessProbe fail → removed from EndpointSlice, no restart
└─→ livenessProbe fail → kubelet kills and restarts the container
1. Deploy a Pod whose readiness you control by hand
The example uses an unprivileged nginx build that listens on 8080, names that port web, and uses all three handler types: httpGet for startup, exec for readiness and tcpSocket for liveness. Readiness passes only while the file /tmp/ready exists. Save this as cka-probes-gate.yaml.
apiVersion: apps/v1
kind: Deployment
metadata:
name: gatekeeper
namespace: prepium-tutorial
spec:
replicas: 1
selector:
matchLabels:
app: gatekeeper
template:
metadata:
labels:
app: gatekeeper
spec:
containers:
- name: site
image: nginxinc/nginx-unprivileged:1.27-alpine
ports:
- name: web
containerPort: 8080
startupProbe: # gate: nothing else runs until this passes
httpGet:
path: /
port: web
periodSeconds: 3
failureThreshold: 20 # 20 x 3s = up to 60s to start
readinessProbe: # traffic switch, never restarts anything
exec:
command: ["cat", "/tmp/ready"]
periodSeconds: 4
livenessProbe: # restart trigger
tcpSocket:
port: web
periodSeconds: 15
---
apiVersion: v1
kind: Service
metadata:
name: gatekeeper
namespace: prepium-tutorial
spec:
selector:
app: gatekeeper
ports:
- port: 9000
targetPort: web
kubectl create namespace prepium-tutorial
kubectl apply -f cka-probes-gate.yaml
kubectl -n prepium-tutorial get pods -l app=gatekeeper
kubectl -n prepium-tutorial get endpointslices -l kubernetes.io/service-name=gatekeeper -o yaml | grep -A3 conditions
The Pod reaches Running but READY stays 0/1, and its endpoint shows ready: false. Nothing is broken: the startup gate passed, so readiness is now running and failing as designed. The named port works for the HTTP and TCP probes and for the Service's targetPort, so changing the number later means editing one line.
2. Flip the traffic switch
kubectl -n prepium-tutorial exec deploy/gatekeeper -- touch /tmp/ready
kubectl -n prepium-tutorial get pods -l app=gatekeeper -w # Ctrl+C once READY is 1/1
kubectl -n prepium-tutorial exec deploy/gatekeeper -- rm /tmp/ready
kubectl -n prepium-tutorial get pods -l app=gatekeeper
kubectl -n prepium-tutorial exec deploy/gatekeeper -- touch /tmp/ready
Within one readiness period the Pod becomes ready and the endpoint turns ready: true; remove the file and it drops out again; the last command restores it. Watch the RESTARTS column: it stays at 0 throughout. That is readiness doing its job, pausing traffic without touching the process.
3. Break liveness and compare
kubectl -n prepium-tutorial patch deployment gatekeeper --type=json \
-p='[{"op":"replace","path":"/spec/template/spec/containers/0/livenessProbe/tcpSocket/port","value":8081}]'
kubectl -n prepium-tutorial get pods -l app=gatekeeper -w
The new Pod starts, passes its startup probe, then fails three TCP checks 15 seconds apart (the default failureThreshold is 3) and is restarted; the RESTARTS count keeps rising and kubectl describe pod lists failed liveness probe events. Meanwhile the old Pod keeps serving: with one replica the default rolling update rounds maxUnavailable down to 0, and the new Pod (with no /tmp/ready) never becomes ready to replace it. Undo it with kubectl -n prepium-tutorial rollout undo deployment/gatekeeper.
4. Size the startup budget deliberately
The startup probe's worst-case allowance is failureThreshold × periodSeconds: here 20 × 3 seconds, so the app has up to a minute to answer before the kubelet kills it. A short period with a high threshold notices a fast start quickly while still tolerating a slow one. Liveness and readiness are held back until startup succeeds, so you do not need a long initialDelaySeconds on them.
Common mistakes
- Using liveness to check a dependency such as a database. When the dependency blips, every replica restarts at once; readiness would only pause traffic.
- A startup budget shorter than the real start time. The container is killed before it ever finishes booting and the Pod cycles through restarts.
- Setting
successThresholdabove 1 on a liveness or startup probe. The documentation requires 1 for both. - Reading the phase instead of readiness.
Runningwith READY0/1means no Service traffic reaches the Pod.
| Example check | Evidence |
|---|---|
| Probe handler and target are right | kubectl get deploy -o yaml shows the path or command, the port (name or number) and periodSeconds per probe |
| Startup budget matches the app | failureThreshold × periodSeconds exceeds the real start time |
| Pods are serving | READY 1/1, EndpointSlice endpoints ready: true |
| No hidden restart loop | RESTARTS stable over a few minutes |
Cleanup: kubectl delete namespace prepium-tutorial. References: Configure liveness, readiness and startup probes, Pod lifecycle: container probes. Next, try a readiness probe on the wrong path or rollout recovery.
Practice scope
This additional curriculum lab is available in single-task practice with the existing 12-minute limit. Its alternate scenario also appears in one of the two mixed curriculum mocks. The first three 17-task mocks keep their original task sets. Hints, an explained solution and requirement-by-requirement feedback are available in the lab.
Browse CKA practice tasks →