🇮🇳
🇮🇳
Limited-Time Offer!Get 20% OFF on all live courses
Enroll Now
PrakalpanaLive online tech training
DevOps⏱️ 9 min read📅 Oct 1

Dockerfile Best Practices 2026: Build Small, Fast and Secure Docker Images

SK
Sanjay Kulkarni•DevOps Engineer
📑 Contents (15 sections)

📌Why Image Quality Matters

A bloated image is slow to build, slow to pull, expensive to store and full of packages attackers can exploit. The same app can ship as a 1 GB image or a 90 MB one — the difference is entirely in the Dockerfile. These are the practices we teach in our Docker course.

📌1. Use Multi-Stage Builds

Build in one stage, run in another, and copy only the artifact.

# Build stage
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn -q dependency:go-offline
COPY src ./src
RUN mvn -q package -DskipTests
# Runtime stage
FROM gcr.io/distroless/java21-debian12
COPY --from=build /app/target/app.jar /app.jar
USER nonroot
ENTRYPOINT ["java", "-jar", "/app.jar"]

The Maven toolchain never reaches production, and the final image is a fraction of the size.

📌2. Order Instructions for Caching

Put what changes least at the top. Copy dependency manifests (pom.xml, package.json, requirements.txt) and install dependencies before copying source code, so a code change does not reinstall every dependency.

📌3. Choose a Minimal Base Image

Prefer -slim, Alpine or distroless images over full OS images. Fewer packages means fewer CVEs and faster pulls. Check that your runtime works with Alpine's musl libc before switching.

📌4. Pin Versions

Use a specific tag such as node:22.9-slim (or a digest) instead of latest, so builds are reproducible and upgrades are deliberate.

📌5. Add a .dockerignore

Exclude .git, node_modules, build output, logs and .env files. Builds get faster and you stop leaking secrets into the build context.

📌6. Combine and Clean Up in One Layer

RUN apt-get update && apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*

Cleaning up in a separate RUN does not shrink the image, because the earlier layer still contains the files.

📌7. Run as a Non-Root User

RUN addgroup --system app && adduser --system --ingroup app app
USER app

Many Kubernetes clusters enforce non-root pods through Pod Security Standards, so this also prevents deployment failures.

📌8. Never Bake In Secrets

Do not COPY credentials or set them with ENV or ARG — they stay in the image history. Use BuildKit secret mounts:

RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci

📌9. Use the Exec Form for ENTRYPOINT and CMD

ENTRYPOINT ["node", "server.js"] runs your app as PID 1 so it receives SIGTERM and shuts down gracefully. The shell form wraps it in /bin/sh, which swallows signals.

📌10. Add a Health Check

HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost:8080/health || exit 1

Compose uses it for depends_on conditions. On Kubernetes, use liveness and readiness probes instead.

📌11. Scan Images and Generate an SBOM

Run Trivy or Docker Scout in CI and fail the build on critical vulnerabilities. Generate an SBOM so you can answer "are we affected?" the day a new CVE lands.

📌12. Build in CI, Not on Laptops

Build, tag (with a version and the Git SHA), scan and push from a pipeline. See our GitHub Actions CI/CD tutorial.

📌Quick Checklist

  • Multi-stage build with a minimal runtime image
  • Dependencies copied and installed before source code
  • Pinned base image versions
  • .dockerignore in place
  • Non-root user
  • No secrets in layers
  • Exec-form entrypoint
  • Scanned in CI
  • 📌Go Further

    Ready for orchestration? Read Docker vs Kubernetes and prepare with Docker interview questions. Prakalpana's Docker & Containerization course covers all of this hands-on, live online or 1-on-1. WhatsApp or call +91 9243078181 for a free demo.

    SK

    Written by

    Sanjay Kulkarni

    DevOps Engineer

    🚀 Master DevOps

    Live online + 1-on-1 Docker & Containerization training · Join 5000+ developers