dockerfile-best-practices

star 0

Apply modern Dockerfile best practices for secure, efficient, and production-ready container images. Use when writing, reviewing, or optimizing Dockerfiles, or when the user asks about Docker image size, security, build caching, multi-stage builds, .dockerignore, secrets handling, health checks, or container hardening.

nahom-d54 By nahom-d54 schedule Updated 2/20/2026

name: dockerfile-best-practices description: Apply modern Dockerfile best practices for secure, efficient, and production-ready container images. Use when writing, reviewing, or optimizing Dockerfiles, or when the user asks about Docker image size, security, build caching, multi-stage builds, .dockerignore, secrets handling, health checks, or container hardening.

Dockerfile Best Practices

Apply these 10 rules when writing or reviewing any Dockerfile.

1. Use a .dockerignore File

Exclude .git, node_modules, and local secrets to keep builds clean. This reduces build context size and prevents accidental leakage of sensitive files into the image.

.git
node_modules
.env
*.secret

2. Clean Up in the Same Layer

Never leave package cache in the final image. Run install and cleanup in the same RUN instruction:

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

3. Don't Use ENV for Secrets

ENV values are visible via docker inspect. Use ARG for build-time variables that don't persist. For runtime secrets, mount them securely using volumes or secret managers (e.g., Docker BuildKit secrets, Vault).

# Bad
ENV DB_PASSWORD=hunter2

# Good — build-time only
ARG DB_PASSWORD

# Good — runtime mount
# docker run -v /secrets/db_password:/run/secrets/db_password myapp

4. Run as a Non-Root User

Running as root is a major security risk. Create a dedicated user and switch immediately:

RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
USER appuser

5. Optimize Caching Order

Copy dependency files before source code so Docker caches dependency installation across code changes:

COPY package.json package-lock.json ./
RUN npm ci --production
COPY . .

6. Pin Your Versions

Avoid :latest or unversioned packages — they produce unpredictable builds:

# Bad
FROM node:latest

# Good
FROM node:20.11-alpine3.19
RUN apk add --no-cache curl=8.5.0-r0

7. Use Minimal Base Images

Prefer alpine, distroless, or -slim tags over full OS images. This reduces attack surface and image size dramatically.

Base Image Approx Size
ubuntu:24.04 ~78 MB
node:20 ~350 MB
node:20-alpine ~50 MB
gcr.io/distroless/static ~2 MB

8. Use Multi-Stage Builds

Separate build environment from runtime. Keep compilers and build tools out of production:

FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o /app/server .

FROM gcr.io/distroless/static
COPY --from=builder /app/server /server
ENTRYPOINT ["/server"]

9. Add a HEALTHCHECK

A running process doesn't mean a working application. Define a check so orchestrators can restart unhealthy containers:

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

10. Combine RUN Instructions

Every RUN line creates a new filesystem layer. Combine related commands to reduce layer count and image size:

# Bad — 3 layers
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*

# Good — 1 layer
RUN apt-get update && apt-get install -y --no-install-recommends curl \
    && rm -rf /var/lib/apt/lists/*
Install via CLI
npx skills add https://github.com/nahom-d54/MyAISkills --skill dockerfile-best-practices
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator