Dockerfile Guide
Complete guide to creating Dockerfiles for building optimized container images
A Dockerfile is a text document containing instructions to build a Docker image. Each instruction creates a layer in the image, making understanding and optimizing Dockerfiles crucial for efficient containerization.
Build Context
When you run docker build, Docker sends the entire directory (build context) to the daemon. Use .dockerignore to exclude unnecessary files.
Dockerfile Structure
Quick Navigation
Instructions Reference
Complete Dockerfile instruction guide
Multi-stage Builds
Optimize image size with stages
Best Practices
Security and optimization tips
Basic Dockerfile Example
# Use specific version for reproducibility
FROM node:20-alpine
# Set working directory
WORKDIR /app
# Copy package files first (leverage layer caching)
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy application code
COPY . .
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
# Switch to non-root user
USER nextjs
# Expose port
EXPOSE 3000
# Define startup command
CMD ["node", "server.js"]# Use slim base image
FROM python:3.12-slim
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# Set working directory
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Create non-root user
RUN useradd --create-home --shell /bin/bash app
USER app
# Expose port
EXPOSE 8000
# Run application
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0"]# Build stage
FROM golang:1.22-alpine AS builder
WORKDIR /app
# Copy go mod files
COPY go.mod go.sum ./
RUN go mod download
# Copy source and build
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
# Runtime stage
FROM alpine:3.19
WORKDIR /app
# Copy binary from builder
COPY --from=builder /app/main .
# Create non-root user
RUN adduser -D -g '' appuser
USER appuser
EXPOSE 8080
CMD ["./main"]# Build stage
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
# Copy maven files
COPY pom.xml .
COPY src ./src
# Build application
RUN ./mvnw package -DskipTests
# Runtime stage
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
# Copy JAR from builder
COPY --from=builder /app/target/*.jar app.jar
# Create non-root user
RUN addgroup -S spring && adduser -S spring -G spring
USER spring
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]Layer Caching
Docker caches layers to speed up builds. Understanding layer caching is essential for optimization.
Cache Invalidation
When a layer changes, all subsequent layers are rebuilt. Order instructions from least to most frequently changing.
Optimal Layer Order
# ✅ Good: Dependencies change less frequently
FROM node:20-alpine
WORKDIR /app
# 1. Copy dependency definitions first
COPY package*.json ./
# 2. Install dependencies (cached unless package.json changes)
RUN npm ci
# 3. Copy source code last (changes most frequently)
COPY . .
CMD ["npm", "start"]# ❌ Bad: Any file change invalidates npm install cache
FROM node:20-alpine
WORKDIR /app
# Source code changes invalidate everything below
COPY . .
RUN npm ci
CMD ["npm", "start"]Essential Instructions
| Instruction | Purpose | Example |
|---|---|---|
FROM | Set base image | FROM node:20-alpine |
WORKDIR | Set working directory | WORKDIR /app |
COPY | Copy files from context | COPY . . |
ADD | Copy with extraction/URLs | ADD archive.tar.gz /app/ |
RUN | Execute commands | RUN npm install |
ENV | Set environment variables | ENV NODE_ENV=production |
ARG | Build-time variables | ARG VERSION=1.0 |
EXPOSE | Document ports | EXPOSE 3000 |
VOLUME | Create mount point | VOLUME /data |
USER | Set user for commands | USER node |
CMD | Default command | CMD ["npm", "start"] |
ENTRYPOINT | Container executable | ENTRYPOINT ["node"] |
Building Images
Create a Dockerfile
FROM nginx:alpine
COPY ./html /usr/share/nginx/html
EXPOSE 80Build the Image
# Basic build
docker build -t my-app .
# Build with tag
docker build -t my-app:1.0.0 .
# Build with build args
docker build --build-arg VERSION=1.0.0 -t my-app .
# Build with no cache
docker build --no-cache -t my-app .Verify the Image
# List images
docker images | grep my-app
# Inspect image
docker inspect my-app
# View image history
docker history my-app.dockerignore
Exclude files from the build context to speed up builds and reduce image size.
# .dockerignore
node_modules
npm-debug.log
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
.env
*.md
.DS_Store
coverage
.nyc_output
distPerformance Impact
A large build context slows down builds. Always use .dockerignore to exclude unnecessary files.