skip to content

How can you add, change, or disable a container's health probe at `docker run` time without rebuilding the image, and when is that the right move?

level: middleimportance: nice to knowfreq 34%

answer

  1. `--health-cmd/-interval/-timeout/-retries/-start-period`
  2. `--no-healthcheck` disables; `HEALTHCHECK NONE` at image level
  3. Container-level definition overrides the image's
  4. `--health-cmd` is a string → needs a shell in the image
  5. Verify with `docker inspect .Config.Healthcheck`

basics

~20 s

docker run accepts --health-cmd, --health-interval, --health-timeout, --health-retries and --health-start-period to define or retune a probe, and --no-healthcheck to disable one entirely. Use them to tune against a real workload, or to override a base image's unsuitable check.

solid answer

~60 s

Every `HEALTHCHECK` option has a run-time counterpart: ``` docker run -d \ --health-cmd='wget -qO- http://localhost:8080/healthz || exit 1' \ --health-interval=10s --health-timeout=2s \ --health-retries=3 --health-start-period=30s \ myapi:1.0 ``` and `--no-healthcheck` turns off any probe the image inherited. Compose exposes the same via `healthcheck:` with `disable: true`. Three situations where this is right: 1. **The image isn't yours.** A third-party image ships a probe that doesn't fit your deployment, or ships none at all, and you don't want to maintain a derived image just for that. 2. **Tuning.** Interval/timeout/start-period should come from measured behaviour; iterating at run time is far faster than rebuild-and-push, and you bake the values into the Dockerfile afterwards. 3. **Debugging.** `--no-healthcheck` stops a flapping status while you investigate. The caveat: run-time flags live in deployment config, not in the image, so they are easy to lose or drift between environments. Once you know the right values, put them in the Dockerfile (or Compose file) so every consumer inherits them. `HEALTHCHECK NONE` is the image-level equivalent of `--no-healthcheck`.

code

bash · 9 lines
bash
docker run -d --name api \
  --health-cmd='wget -qO- http://localhost:8080/healthz >/dev/null || exit 1' \
  --health-interval=10s --health-timeout=2s \
  --health-retries=3 --health-start-period=30s \
  vendor/api:2.3

docker run -d --name batch --no-healthcheck vendor/api:2.3

docker inspect --format '{{json .Config.Healthcheck}}' api

go deeper

for a junior

Name the --health-* flags and --no-healthcheck, and say the container-level setting replaces whatever the image declared.

for a middle

Explain when overriding is right (third-party images, tuning, debugging) and that --health-cmd is shell-based so it needs a shell in the image.

for a senior

Draw the line clearly — command in the image, environment timings in committed deployment config, ad-hoc flags only for experiments — and verify with .Config.Healthcheck.

for a principal

Set the convention across the estate so every image ships a working default probe and environments tune only timings, keeping the meaning of healthy uniform for whatever consumes it.

## Two places a probe can be defined A health check can be declared in the **image** (`HEALTHCHECK` in the Dockerfile, stored in the image config) or supplied at **container creation** (`docker run --health-*`, or a Compose `healthcheck:` block). The container-level definition wins: it replaces whatever the image declared. That layering exists because the right probe is partly a property of the software (which endpoint means "ready") and partly of the deployment (how fast do you need detection, how slow is startup on this hardware, is this a dev laptop or a production host). ## The run-time flags | Flag | Overrides | |---|---| | `--health-cmd` | the probe command itself | | `--health-interval` | gap between probes | | `--health-timeout` | maximum duration of one probe | | `--health-retries` | consecutive failures needed to flip to unhealthy | | `--health-start-period` | startup grace window | | `--health-start-interval` | probe frequency during the start period (Docker 25.0+) | | `--no-healthcheck` | disables health checking entirely | A subtlety: `--health-cmd` takes a **string**, and Docker runs it through the container's shell — so it needs `/bin/sh` present. In a shell-less image you cannot express an arbitrary command this way, which is one of the few places where the Dockerfile's exec form (`HEALTHCHECK CMD ["/bin/healthcheck"]`) is strictly more capable. Another: overrides apply at container creation. Changing them later means recreating the container — you cannot retune a probe on a running container the way you can with some other settings. ## Disabling: two spellings - **`docker run --no-healthcheck`** — this container has no probe. - **`HEALTHCHECK NONE` in a Dockerfile** — images built from this one inherit no probe. - **Compose**: `healthcheck: { disable: true }`. Disabling is legitimate more often than people expect. A base image's check may test something your build removed or reconfigured; a batch job that runs for 40 seconds has nothing meaningful to probe; and during an incident, silencing a flapping probe keeps a consumer (an autoheal watcher, a Swarm scheduler) from acting while you look at the container. ## Compose as the usual home for these values In practice most teams put the *command* in the Dockerfile — it belongs to the software — and let the *timings* be overridable per environment in Compose or the deployment manifest. Compose's `healthcheck:` block accepts `test`, `interval`, `timeout`, `retries`, `start_period`, `start_interval`, and `disable`, mirroring the flags exactly, and the `test` list form (`["CMD", ...]` vs `["CMD-SHELL", "..."]`) lets you choose exec or shell semantics explicitly — which the `--health-cmd` flag does not. ## The tradeoff to state out loud Run-time overrides are configuration drift waiting to happen. If the probe only exists in one operator's `docker run` line, then anyone else who starts the image gets no check, or a stale one, and nothing in the image records what "healthy" is supposed to mean. Symptoms of having gone too far this way: the same `--health-cmd` copy-pasted across several scripts with slightly different intervals, or a production incident where the container had no probe because a flag was dropped from a deploy script. The healthy division: - **Image**: the probe command and sensible default timings — so every consumer gets a working check for free. - **Deployment config**: environment-specific timing overrides, checked into version control alongside the rest of the deployment. - **Ad-hoc `docker run` flags**: experiments and debugging, not the durable answer. ## Verifying an override took effect After starting the container, confirm what is actually configured rather than what you intended: ``` docker inspect --format '{{json .Config.Healthcheck}}' api ``` That prints the effective test, interval, timeout, retries, and start period for that container — including whether a `--no-healthcheck` left it empty. Pair it with `.State.Health` to see what the probe is currently reporting.

  • You override `--health-cmd` on an image with no shell. What happens?
    The flag takes a string that Docker runs through the container's shell, so with no `/bin/sh` present the probe fails immediately and the container trends unhealthy. For shell-less images you need an exec-form probe, which means either a `HEALTHCHECK CMD ["..."]` baked into the Dockerfile or Compose's `test: ["CMD", "binary", "arg"]` list form. The plain `--health-cmd` flag cannot express exec form.
  • Where should the probe definition ultimately live?
    The command belongs in the image, because knowing which endpoint means "working" is a property of the software and every consumer of the image should get it for free. Timings that depend on the environment — interval, timeout, start period — are reasonable to override in the deployment manifest, kept in version control. Ad-hoc `docker run` flags are fine for experimenting or debugging but are configuration drift if they become the durable definition.

saying these in an interview costs you the question

  • Assuming an image-level `HEALTHCHECK` cannot be changed without a rebuild
  • Believing `--no-healthcheck` also disables restart behaviour — the two are unrelated
  • Trying to retune a probe on an already-running container instead of recreating it
  • Leaving the only definition of the probe in an operator's shell history rather than the image or a committed manifest

context