1. Why lint a Dockerfile? #
Find problems before building.
The principle #
A linter reads the Dockerfile without building it and flags errors and bad practices: untagged image, ADD instead of COPY, apt cache kept, shell-form CMD. Hadolint is the reference; it also analyzes RUN commands with ShellCheck.
2. Hadolint in practice #
A real result, and how to read it.
The Dockerfile to fix #
FROM node
RUN apt-get update && apt-get install -y curl
ADD . /app
WORKDIR /app
RUN npm install
EXPOSE 3000
CMD npm starthadolint Dockerfile
# ou sans installation
docker run --rm -i hadolint/hadolint:v2.15.1 < DockerfileDockerfile:1 DL3006 warning: Always tag the version of an image explicitly
Dockerfile:2 DL3008 warning: Pin versions in apt get install. Instead of `apt-get install <package>` use `apt-get install <package>=<version>`
Dockerfile:2 DL3015 info: Avoid additional packages by specifying `--no-install-recommends`
Dockerfile:2 DL3009 info: Delete the apt lists (/var/lib/apt/lists) after installing something
Dockerfile:3 DL3020 error: Use COPY instead of ADD for files and folders
Dockerfile:7 DL3025 warning: Use arguments JSON notation for CMD and ENTRYPOINT arguments| Rule | Problem | Fix |
|---|---|---|
| DL3006 | Untagged image | node:22.11-bookworm-slim |
| DL3020 | ADD for local files | COPY |
| DL3015 / DL3009 | Recommended packages, apt cache kept | --no-install-recommends, rm -rf /var/lib/apt/lists/* |
| DL3025 | Shell-form CMD: signals poorly forwarded | CMD ["npm", "start"] |
The result after fixing #
On the previous lesson's hardened Dockerfile, Hadolint still flagged DL3066 for USER nonroot: a user name may not be resolvable by the host. With USER 65532:65532, it reports nothing and returns code 0.
Thresholds and exceptions #
By default, Hadolint fails on the first finding, even at info level. In CI, set a threshold, and justify each exception in .hadolint.yaml:
hadolint --failure-threshold warning Dockerfile
hadolint -f json Dockerfile # pour un outil de CI# .hadolint.yaml
ignored:
- DL3008 # apt versions managed by RenovateOccasionally, a # hadolint ignore=DL3008 comment right above the line.
3. Built-in checks #
docker build --check.
docker build --check #
BuildKit embeds its own rules (keyword casing, inconsistent FROM … AS, undefined variables, shell-form CMD…). The command evaluates them without building the image:
docker build --check .They complement Hadolint without replacing it: Hadolint goes further on shell commands and packages. This command was not run for this article, as our test environment had no Docker daemon.
Sources #
Real output from Hadolint 2.15.1.
