Lab 22 - Health checks
Lab 22 - Health checks
Goal: see what each probe does when it fails - and how readiness protects a rollout. Chapter: Startup, readiness and liveness probes
Readiness: no traffic, no restart
# 1 - three replicas behind a Service
cd ~
kubectl create deploy web --image nginx:1.27 --replicas 3
kubectl expose deploy web --port 80
kubectl rollout status deploy/web
# 2 - add a readiness probe on a file we control
kubectl patch deploy web -p '{"spec":{"template":{"spec":{"containers":[{"name":"nginx","readinessProbe":{"httpGet":{"path":"/ready.html","port":80},"periodSeconds":3}}]}}}}'
kubectl get pods -l app=web -w # Ctrl-C: new Pods Running but 0/1 READY
The rollout is stuck, safely: new Pods never become ready, so the old ones keep serving.
# 3 - make them ready by creating the file
for p in $(kubectl get pods -l app=web -o name); do
kubectl exec $p -- sh -c 'echo ok > /usr/share/nginx/html/ready.html' 2>/dev/null
done
kubectl rollout status deploy/web
kubectl get endpointslices -l kubernetes.io/service-name=web -o wide
# 4 - take one Pod out of the Service by hand
P=$(kubectl get pods -l app=web -o name | head -1)
kubectl exec $P -- rm /usr/share/nginx/html/ready.html
sleep 10
kubectl get pods -l app=web # one 0/1, RESTARTS still 0
kubectl get endpointslices -l kubernetes.io/service-name=web -o yaml | grep -B2 -A2 'ready: false'
Not ready = out of the load balancer. Nothing is restarted.
Liveness: restart
# 5 - a Pod whose health file disappears after 30 s
cat > live.yaml <<'YAML'
apiVersion: v1
kind: Pod
metadata:
name: live
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "touch /tmp/healthy; sleep 30; rm /tmp/healthy; sleep 600"]
livenessProbe:
exec:
command: ["cat", "/tmp/healthy"]
periodSeconds: 5
failureThreshold: 2
YAML
kubectl apply -f live.yaml
kubectl get pod live -w # RESTARTS 1 after ~40 s; Ctrl-C
kubectl events --for pod/live | tail -5
Liveness probe failed ... Container app failed liveness probe, will be restarted.
Startup: protect slow starters
# 6 - an app that needs 40 s to start, with a strict liveness probe
cat > slow.yaml <<'YAML'
apiVersion: v1
kind: Pod
metadata:
name: slow
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 40; touch /tmp/started; sleep 3600"]
livenessProbe:
exec: { command: ["cat", "/tmp/started"] }
periodSeconds: 5
failureThreshold: 2
YAML
kubectl apply -f slow.yaml
kubectl get pod slow -w # restarted every ~10 s - never starts
Liveness kills it before it ever finishes booting - a restart loop.
# 7 - the fix: a startup probe holds liveness back
kubectl delete pod slow
cat >> slow.yaml <<'YAML'
startupProbe:
exec: { command: ["cat", "/tmp/started"] }
periodSeconds: 5
failureThreshold: 12 # up to 60 s to start
YAML
kubectl apply -f slow.yaml
kubectl get pod slow -w # Running, 0 restarts after ~45 s
Discovery
InfodiscoverTask A. Give the web Deployment a liveness probe (tcpSocket port 80)
and a readiness probe (httpGet / port 80). Expected: rollout completes, all
Pods 1/1.
Task B. Why is it a bad idea for the liveness probe of web to check that
the database is reachable?
Clean up
kubectl delete deploy web; kubectl delete svc web
kubectl delete -f live.yaml -f slow.yaml