Skip to content
Muhammet Şafak
tr
Asked by: Elif Answered:

Should I define the healthcheck in the Dockerfile or leave it to Kubernetes probes?


Question

My image defines a `HEALTHCHECK`, but Kubernetes seems to ignore it. Meanwhile the Deployment spec has readiness/liveness probes. I can't figure out which layer owns the "am I ready" decision. Should I write the healthcheck in the Dockerfile, leave it to Kubernetes probes, or have both? What exactly is the relationship between them?

Answer

Short answer: in Kubernetes, probes own readiness/liveness; the kubelet never reads the image’s HEALTHCHECK status, by design. But it’s worth keeping the HEALTHCHECK for Compose/plain Docker — it’s not junk, it just serves a different runtime.

The confusion is understandable: two layers both look like they own health, but only one of them is actually consulted in a given runtime. Pin down which runtime the image is really going to run in first, and the answer falls out of that.

  1. Kubernetes ignores the Dockerfile HEALTHCHECK by design. The kubelet runs its own liveness/readiness/startup probes and never reads the image’s HEALTHCHECK result. So in k8s that line is dead weight — harmless, but not what gates traffic.
  2. Which layer owns what. Readiness (traffic gating), liveness (restart), and startup (slow boot) are all Kubernetes probe concepts. That’s the layer that owns “can this pod serve”; define them in the Deployment/Pod spec.
  3. Docker/Compose do honor HEALTHCHECK. In local dev, Compose’s depends_on: condition: service_healthy and plain Docker/Swarm use HEALTHCHECK to mark a container “healthy.” So it isn’t useless; it just serves a different consumer.
  4. Don’t duplicate the logic, share the endpoint. Expose the same /healthz (liveness) and /readyz (readiness) HTTP endpoints; point both the Dockerfile HEALTHCHECK and the k8s probes at them. One implementation, two consumers.
  5. HEALTHCHECK has a cost. CMD curl needs curl in the image (distroless won’t have it); prefer exec-ing your binary’s own healthcheck subcommand, or just drop HEALTHCHECK entirely if the image only ever runs in k8s. A shell-form HEALTHCHECK also spawns a process on every interval, which is wasted work on a container whose orchestrator never reads the result.
  6. Keep probes cheap and correct. Same golden rule: keep liveness dependency-free, and have readiness check dependencies but cache the result for a few seconds. Otherwise the probes DDoS your database.
# Only meaningful if the image also runs under Compose/plain Docker:
HEALTHCHECK --interval=10s --timeout=2s --retries=3 \
  CMD ["/app/server", "healthcheck"]
# In Kubernetes, this is the layer that actually gates traffic and restarts:
readinessProbe:
  httpGet: { path: /readyz, port: 8080 }
  periodSeconds: 5
livenessProbe:
  httpGet: { path: /healthz, port: 8080 }
  periodSeconds: 10

Bottom line: personally I’d define readiness/liveness/startup as Kubernetes probes — because that’s the layer that decides traffic and restarts. I’d keep a HEALTHCHECK in the Dockerfile only if the same image also runs under Compose/plain Docker, wiring both at the same /healthz + /readyz endpoints. If the image is k8s-only, I’d drop the HEALTHCHECK to avoid the illusion that it does anything.

Tags: #docker#kubernetes#healthcheck
Share:

Comments

Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.

More Questions

All questions

Search the site

Start typing to search posts, projects and pages.

Esc to close Powered by Pagefind