Build1 distinct publisher3 min readPublished
The word healthcheck names three different behaviours depending on which layer reads it, and the layer where it means nothing for routing is the one most production traffic goes through. Portability was the assumption.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
Start with what the daemon does when the HEALTHCHECK line fires. It runs your command inside the container and writes the result where `docker inspect` can read it [3]. That is the entire contract. In Compose, one thing consumes it: a dependency edge spelled `depends_on: condition: service_healthy` [3], which orders startup and then has no further opinion. Swarm consumes it as a routing signal, taking an unhealthy service out of rotation and replacing it per the restart policy [4]. The kubelet does not consume it [5].
Of the three layers the post walks through, exactly one gates traffic on that status [1]. The syntax is what does the damage. Interval, retries, and the healthy/unhealthy vocabulary all read like an availability feature, which is why the author calls it a log shaped like a feature [16], and why he thinks the shared name is what makes people trust it further than any one layer promises [10].
On the Kubernetes side the same idea arrives split into three. Liveness failure restarts the container. Readiness failure removes the pod from the Service's endpoints and restarts nothing. A startupProbe exists so a slow boot is not killed by liveness first [6]. Each carries its own period, timeout and failure threshold in the manifest [5]. A single Docker boolean cannot express that, which is a better explanation for the missing translation than an oversight in the kubelet.
The Compose experience transfers under two conditions only: your orchestrator is Swarm, or the sole thing you needed was startup ordering on one host. On a cluster the Service selects endpoints, and with no readinessProbe the pod joins that set as soon as the process is up, whether or not it has finished connecting to the database or warming its pool [7]. The author's account of teams walking into this is specific: a tidy `curl` HEALTHCHECK in the Compose file, `depends_on` honoured locally, and an assumption that the behaviour rides along into the cluster [12].
The part of that work which survives is the endpoint. A curl against the health endpoint proves the app can answer a question [12]. The probe block is what makes something ask. It is the same shape as the Actuator problem he flagged earlier: expose `/actuator/health`, get nothing, because nobody on the orchestration side is querying it with the right semantics [13]. Meanwhile `docker inspect` goes on reporting healthy, accurately, to no one [9].
On sourcing: this is one practitioner publishing the same argument twice, in Spanish and English [2]. The probe semantics are checkable against the Kubernetes documentation he cites, which is explicit that none of the three probes defer to the image's HEALTHCHECK [14]. The diagnosis of how teams get here, and the harder claim that the Dockerfile status is dead weight rather than merely inert, are his own [9][11]. In my context the call is cheap: keep HEALTHCHECK in the Compose file where a dependency edge actually reads it, and treat a pod spec with no readinessProbe as an unfinished deployment no matter how carefully the image reports on itself [1].
Ranked by verification strength, evidence, and original report placement.
The post reports that docker ps may show "Up 3 minutes (healthy)" while Kubernetes has zero idea the HEALTHCHECK exists; for the kubelet the pod is Running and ready to take traffic from the moment the process started, because Docker's internal state is not part of its equation.
The author's thesis is that Docker's HEALTHCHECK is an information layer living inside the Docker daemon, not a routing guarantee; the same argument was published in Spanish and in English on dev.to.
Docker Engine runs the HEALTHCHECK from the Dockerfile or docker-compose.yml, stores the result in docker inspect, and that is all; it does not restart anything on its own unless you use depends_on: condition: service_healthy in Compose.
Docker Swarm does read the HEALTHCHECK state: if a Swarm service goes unhealthy, Swarm pulls it out of rotation and can replace it according to the restart policy.
Kubernetes completely ignores Docker's HEALTHCHECK and uses its own probes, livenessProbe, readinessProbe and startupProbe, defined in the pod manifest, each with its own period, timeout and failure threshold.
If livenessProbe fails the kubelet restarts the container; if readinessProbe fails the pod is pulled from the Service's endpoints without a restart; startupProbe protects slow-starting apps from being killed by liveness before they are ready.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
2 articles · August 28, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
Probes cannot fix bad addressing: what a browser-run Kubernetes cluster actually shows1 distinct publisher
build
A dependency check in the liveness probe turns one outage into two1 distinct publisher
build
Spring Boot Actuator: the wildcard is the bug, not the endpoint that sounds scary1 distinct publisher
build
SSE in Go breaks twice before your handler runs: an illegal header, then a 30-second timeout1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Reproducible mechanics, one voice behind them
Everything structural here is something a reader can verify in an afternoon on their own cluster: where the health result is stored, which layer removes a container from rotation, where probes are declared. That is real strength. The weakness is sourcing depth — Kubernetes' probe documentation is invoked four times and never linked or quoted, no version is named, and the sharpest conclusion is explicitly the author's inference rather than doc wording. Two texts, one author, one platform.
No field data, and the author says so
How often teams actually ship this misconfiguration is exactly what nobody here measures. The closing paragraph is unusually candid about it: no production data on failure-detection latency between Docker and Kubernetes, no benchmark for how many requests the desync window loses, and the observation that measuring the operational cost is somebody else's experiment. We will not score a number that does not exist.
Rhetoric a step ahead of the measurement
The headline behaviour is real and narrowly stated, and the author repeatedly narrows it himself. What runs ahead of the evidence is the vocabulary: dead signal, decorative, a log shaped like a feature. Two paragraphs earlier the same text credits Swarm with acting on the instruction and Compose with honouring it for startup ordering — so what is really indicted is a portability assumption, not the instruction. Small gap, and mostly a matter of register.
Audience flywheel, no vendor stake
Nothing is being sold. What is visible is a writer's engine: the same argument shipped twice on the same day for two language audiences, with callbacks to an earlier Actuator post and to one on stateless JWTs versus stateful sessions. That shapes framing — a documented design boundary is presented as a discovery — but nobody gains from misdescribing which layer reads which signal, and no vendor, licence or price is in play.
Trust the mechanism, discount the stakes
We would stake a lot on the layer-by-layer description and very little on anything past it. One author, one publisher, two languages, no independent check, no linked documentation, and both texts stop mid-sentence with a promised comparison matrix that never arrives — a poor signal about how this was published, not about whether the argument is right.