hadolint/DL3057¶
HEALTHCHECK instruction missing.
| Property | Value |
|---|---|
| Severity | Ignore (off by default) |
| Category | Best Practice |
| Default | Off |
Description¶
This is an optional rule. When it is required to define a health check (e.g. by company policy), it must not be omitted.
This rule is disabled by default because a HEALTHCHECK is not desirable in all circumstances. Images used with Kubernetes do not benefit from a
HEALTHCHECK instruction, as Kubernetes brings its own mechanisms.
Examples¶
Problematic code¶
Correct code¶
or:
tally enhancements¶
Smart suppression¶
tally automatically suppresses this rule when the Dockerfile shows strong signals that a HEALTHCHECK would not be beneficial:
Serverless / FaaS base images¶
Containers built for serverless platforms have their lifecycle managed externally — the platform decides when to start, stop, and replace
function instances. A container-level HEALTHCHECK is ignored in these environments.
| Platform | Suppressed image patterns |
|---|---|
| AWS Lambda | public.ecr.aws/lambda/*, gallery.ecr.aws/lambda/*, amazon/aws-lambda-* |
| Azure Functions | mcr.microsoft.com/azure-functions/* |
| OpenFaaS | openfaas/of-watchdog, openfaas/classic-watchdog (including ghcr.io variants) |
If any stage in the Dockerfile uses a recognized serverless base image, the violation is suppressed for the entire file. Multi-stage builds that pull from a Lambda image in one stage and copy artifacts into another are still covered because the presence of the serverless image signals the target runtime.
Serverless framework entrypoints¶
When the final stage's CMD or ENTRYPOINT invokes a known serverless function framework, the container is a short-lived function handler
managed by the platform — not a service that benefits from HEALTHCHECK.
| Framework | Example |
|---|---|
Google Cloud Functions (functions-framework) |
CMD ["functions-framework", "--target=hello"] |
The exec prefix commonly used in shell form is handled:
Interactive / shell-only containers¶
When the final stage's CMD or ENTRYPOINT resolves to a bare interactive shell (sh, bash, zsh, ash, dash, fish, csh, tcsh,
ksh), the container is clearly not a long-running service — there is no endpoint to health-check.
Recognized patterns:
CMD ["bash"] # exec form
CMD bash # shell form
CMD ["bash", "-l"] # shell with flags (still interactive)
ENTRYPOINT ["/bin/sh"] # entrypoint shell
Not suppressed when the shell is used to execute a command:
If an ENTRYPOINT is present, it takes precedence over CMD (matching Docker runtime semantics).
No explicit CMD/ENTRYPOINT (external parent delegation)¶
When the final stage has no CMD or ENTRYPOINT instruction and its base is an external image (not another build stage), the image
delegates run orchestration to its parent. In these cases the parent likely also defines a HEALTHCHECK, so flagging the child produces false
positives. The violation is suppressed.
FROM nginx:latest
RUN echo "custom config" > /etc/nginx/conf.d/default.conf
EXPOSE 80
# No CMD — nginx base image provides CMD and likely HEALTHCHECK
This does not apply when the final stage inherits from a prior build stage (FROM <stage-name>), because CMD/ENTRYPOINT are inherited from
the prior stage and the image is not opaque:
FROM alpine AS base
CMD ["my-app"]
FROM base
RUN echo "setup"
# DL3057 still fires — CMD inherited from "base", image is not opaque
Explicit opt-out with HEALTHCHECK NONE¶
HEALTHCHECK NONE is treated as a deliberate opt-out. When present in any stage, DL3057 is fully suppressed — no fast-path violation is
emitted and no async registry checks are planned. This matches Docker's semantics where HEALTHCHECK NONE explicitly disables health checking.
Async registry resolution¶
tally extends this rule with async registry resolution (enabled with --slow-checks):
- Base image inspection: For each external base image, tally checks if it already defines a
HEALTHCHECKin its image metadata. If so, the violation is suppressed since the health check is inherited. This check is skipped when any explicitHEALTHCHECKinstruction (CMD or NONE) is already present. - Cross-rule awareness:
buildkit/MultipleInstructionsDisallowedmay still flag duplicateHEALTHCHECKinstructions even when DL3057 is suppressed.