HxHippy

Dockerfile Best Practices

Optimize Dockerfiles for smaller, faster, and more secure images.

Last updated: 2025-01-15

Dockerfile Optimization

Write efficient Dockerfiles for smaller images, faster builds, and better security.

Layer Optimization

Minimize Layers

# Bad: Multiple RUN commands
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y wget
RUN rm -rf /var/lib/apt/lists/*

# Good: Combined RUN command
RUN apt-get update && \
    apt-get install -y \
      curl \
      wget && \
    rm -rf /var/lib/apt/lists/*

Order for Cache Efficiency

# Bad: Busting cache early
COPY . /app
RUN npm install

# Good: Dependencies first
COPY package*.json /app/
RUN npm ci
COPY . /app

Image Size Reduction

Use Minimal Base Images

# Size comparison:
# ubuntu:22.04     ~77MB
# debian:slim      ~80MB
# alpine:3.19      ~7MB
# distroless       ~2MB

FROM node:20-alpine         # Not node:20 (~1GB)
FROM python:3.12-slim       # Not python:3.12 (~1GB)
FROM golang:1.22-alpine     # For build stage

Clean Up in Same Layer

# Bad: Files persist in earlier layer
RUN apt-get update
RUN apt-get install -y build-essential
RUN make
RUN rm -rf /var/lib/apt/lists/*

# Good: Clean up in same layer
RUN apt-get update && \
    apt-get install -y build-essential && \
    make && \
    apt-get purge -y build-essential && \
    apt-get autoremove -y && \
    rm -rf /var/lib/apt/lists/*

Use .dockerignore

# .dockerignore
.git
.gitignore
node_modules
npm-debug.log
Dockerfile*
docker-compose*
.env
*.md
.vscode
.idea
__pycache__
*.pyc
.pytest_cache
coverage
.coverage

Security Best Practices

Run as Non-Root

# Create and use non-root user
RUN addgroup --gid 1001 --system appgroup && \
    adduser --uid 1001 --system --ingroup appgroup appuser

USER appuser

# Or use existing user
USER nobody

Don't Store Secrets

# Bad: Secrets in image
ENV API_KEY=secret123
COPY credentials.json /app/

# Good: Use build secrets or runtime injection
RUN --mount=type=secret,id=api_key cat /run/secrets/api_key

# Or inject at runtime
# docker run -e API_KEY=$API_KEY myapp

Use Specific Versions

# Bad: Unpredictable
FROM node:latest
RUN npm install express

# Good: Pinned versions
FROM node:20.10.0-alpine3.19
RUN npm install [email protected]

Build Performance

Use BuildKit

# Enable BuildKit
export DOCKER_BUILDKIT=1

# Or per-build
DOCKER_BUILDKIT=1 docker build -t myapp .

Parallel Operations

# syntax=docker/dockerfile:1.4
FROM node:20-alpine

# Parallel downloads
RUN --mount=type=cache,target=/root/.npm \
    npm ci --prefer-offline

Cache Mounts

# Cache package manager data
RUN --mount=type=cache,target=/var/cache/apt \
    apt-get update && apt-get install -y curl

# Cache npm
RUN --mount=type=cache,target=/root/.npm \
    npm ci

# Cache pip
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

Optimization Checklist

Category Practice
Base Image Use minimal (alpine, slim, distroless)
Layers Combine RUN commands
Caching Order from least to most changing
Size Clean up in same layer
Security Run as non-root user
Secrets Never embed in image
Versions Pin base image and dependencies
Context Use .dockerignore
intermediate Dockerfile Updated 2025-01-15
  • dockerfile
  • optimization
  • layers
  • caching
  • security