Hadolint 12,433 (https://github.com/hadolint/hadolint 12,433 ) (GPL-3.0, written in Haskell) parses a Dockerfile, checks it against some 70 DLxxxx rules, and runs ShellCheck 151,887 (https://github.com/koalaman/shellcheck 40,089 ) on the shell code in every RUN. Install the single binary from its releases page, or run docker run --rm -i hadolint/hadolint < Dockerfile; version 2.15.1 is installed here. Point it at a Dockerfile full of classic mistakes, then at BookNest's:
printf 'FROM node:latest\nRUN apt-get update\nRUN apt-get install -y curl\n' > ../bad.Dockerfile
printf 'ADD . /app\nRUN cd /app && npm install\nCMD node server.js\n' >> ../bad.Dockerfile
hadolint --no-color ../bad.Dockerfile | cut -c 1-95
hadolint Dockerfile && echo "Dockerfile: no findings"../bad.Dockerfile:1 DL3007 warning: Using latest is prone to errors if the image will ever upda ../bad.Dockerfile:2 DL3009 info: Delete the apt lists (/var/lib/apt/lists) after installing som ../bad.Dockerfile:3 DL3008 warning: Pin versions in apt get install. Instead of `apt-get instal ... ../bad.Dockerfile:4 DL3020 error: Use COPY instead of ADD for files and folders ../bad.Dockerfile:5 DL3003 warning: Use WORKDIR to switch to a directory ../bad.Dockerfile:6 DL3025 warning: Use arguments JSON notation for CMD and ENTRYPOINT argument Dockerfile: no findings
Each finding maps to a subsection of this chapter: the latest trap (Tagging Conventions), ADD for local files (COPY vs ADD), cd instead of WORKDIR (FROM and WORKDIR), split RUNs and apt lists left behind (RUN and Caching), and a shell-form CMD (Exec vs Shell Form). Silence an accepted finding with # hadolint ignore=DL3008 above the line, or project-wide in .hadolint.yaml. Hadolint exits non-zero on any finding, even info; --failure-threshold warning relaxes that for CI (Jenkins).
Commit both files, so that Jenkins and Kubernetes build exactly these:
git add Dockerfile .dockerignore
git commit -q -m "Add Dockerfile and .dockerignore for the BookNest API" \
-m "node:24-slim base, production dependencies via npm ci, non-root UID 1000, /health check."
git log --oneline -28336b06 Add Dockerfile and .dockerignore for the BookNest API 7e7c388 BookNest baseline: Express + PostgreSQL REST API with health/readiness endpoints ...