How to Add a Kubernetes startupProbe for a Slow-Starting Container
A liveness probe tuned for steady-state health will kill a JVM app, a migration-heavy service, or any slow starter mid-boot - before it ever becomes healthy. A startupProbe gives the container a generous one-time boot budget, then hands off to liveness. Here's how to add one.
Why slow starters crash-loop
Kubernetes runs livenessProbe checks continuously. If you set
failureThreshold: 3 and periodSeconds: 5, the container has 15 seconds
to pass a liveness check - or Kubernetes kills it and restarts it.
A JVM service, a container that runs database migrations on boot, or anything
that does heavy warm-up often takes 30-120 seconds before it can answer HTTP.
The liveness probe declares it dead and kills it first. The pod enters a
CrashLoopBackOff even though the app itself is perfectly healthy.
The fix: a startupProbe
startupProbe runs instead of livenessProbe until the probe succeeds
once. After that first success, Kubernetes stops running the startup probe
and switches to the liveness probe for ongoing health checks. This gives you:
- A long boot budget for slow starters (without loosening the liveness probe for the steady-state lifetime of the container)
- Clean separation of "did it finish starting?" from "is it still healthy?"
Add it to your Deployment manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: my-app:latest
ports:
- containerPort: 80
startupProbe:
httpGet:
path: /health
port: 80
failureThreshold: 30
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 80
periodSeconds: 10
failureThreshold: 3
Apply and verify:
kubectl apply -f deployment.yaml
kubectl rollout status deployment/web
kubectl get deploy web -o yaml | grep -A6 startupProbe
Calculating the boot budget
The startup probe runs for up to failureThreshold x periodSeconds before
giving up. With failureThreshold: 30 and periodSeconds: 5 that's 150
seconds of startup budget. Tune both numbers to match your app's worst-case
boot time plus a comfortable margin.
Once the startup probe passes once, it is gone. The liveness probe takes over
with its own (tighter) thresholds. This is the right pattern - you don't need
to set a permissive initialDelaySeconds on the liveness probe or inflate
its failureThreshold for the ongoing lifetime of the container.
Probe types
All three probe types (startupProbe, livenessProbe, readinessProbe)
support the same check mechanisms - httpGet, tcpSocket, or exec. Use
whatever your app already has a health endpoint for. A minimal /healthz
that returns 200 as soon as the app is ready to serve traffic is the
standard pattern.
When you need all three
startupProbe- passes once the app has finished bootinglivenessProbe- restarts the container if it gets stuck (deadlock, OOM)readinessProbe- removes the pod from Service endpoints if it is temporarily overloaded or not ready for new traffic (does NOT restart it)
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Adding a startupProbe to a Deployment manifest alongside a livenessProbe
- Calculating the right failureThreshold x periodSeconds boot budget for a slow-starting app
- Applying the manifest with kubectl and verifying the probe config with kubectl get deploy -o yaml
FAQ
What is a Kubernetes startupProbe?
A startupProbe runs in place of the livenessProbe until it succeeds once. It gives slow-starting containers a long boot budget without loosening the liveness probe for the container's steady-state lifetime. After the startup probe passes, Kubernetes switches to the liveness probe.
Why is my Kubernetes pod in CrashLoopBackOff even though the app works?
If the liveness probe fails during startup before the app finishes booting, Kubernetes kills and restarts the container - creating a crash loop even though the app itself is healthy. Adding a startupProbe with a generous failureThreshold x periodSeconds budget stops this.
What is the difference between startupProbe and livenessProbe?
startupProbe runs once at startup and gives the container time to boot. livenessProbe runs continuously afterward to restart the container if it gets stuck. Both use the same check format (httpGet, tcpSocket, exec), but serve different purposes in the container lifecycle.
What is the difference between a startup probe and a liveness probe?
A startupProbe runs only during boot and gives a slow-starting container a one-time window; once it passes, the livenessProbe takes over and restarts the container if it later hangs. The startup probe stops liveness from killing a slow boot.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →