"Works on my laptop" and "survives production" are different things — but almost everything separating them is testable locally in k3d. Probe behavior, liveness restarts, rolling updates, SIGTERM shutdown: k3d reproduces all of it.
Takeaways
-
CPU throttles, memory kills. CPU is compressible — hit the limit and the container just slows down. Memory is not — exceed
limits.memoryand the kernel kills the process: OOMKilled, exit code 137. So a low CPU limit = slowness; a low memory limit = instant Pod death. Give memory headroom (request ~P99 + 20%); CPU can ride closer to P95. -
Three probes, three jobs:
-
liveness fails -> container is restarted. Keep it simple (
GET /healthz), never hit the DB — a dependency blip would restart a healthy container. - readiness fails -> Pod is pulled from the Service endpoints (no traffic), not restarted. This is the right place to check PostgreSQL.
-
startup gates the other two — until it passes, liveness/readiness are disabled. Use it for slow starters instead of a big
initialDelaySeconds.
-
liveness fails -> container is restarted. Keep it simple (
- QoS: Guaranteed (request=limit everywhere) evicted last; BestEffort (no requests/limits) evicted first. Always set at least requests.
-
Graceful shutdown: on delete, the Pod goes Terminating,
preStopruns, kubelet sends SIGTERM to PID 1, waitsterminationGracePeriodSeconds(default 30s), then SIGKILL. Your app must catch SIGTERM — and uvicorn must be PID 1 (exec-form CMD, no shell wrapper) or the signal never arrives. -
The endpoints race: removing the Pod from endpoints and sending SIGTERM happen in parallel, so traffic can still hit a shutting-down Pod (5xx during deploy). Fix: a
preStop: sleep 15so routing updates first. Keep preStop well under the grace period — it counts against the same budget. -
Zero-downtime rollout:
maxUnavailable: 0,maxSurge: 1, plusminReadySeconds. Without a readiness probe, zero-downtime is impossible — the rollout waits on readiness before retiring old Pods.
Verify locally: kubectl get endpointslices -n myapp -w while running a while true; do curl ... loop during a rollout.
Top comments (0)