DevDocsDev Docs
Dockerfile

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

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

InstructionPurposeExample
FROMSet base imageFROM node:20-alpine
WORKDIRSet working directoryWORKDIR /app
COPYCopy files from contextCOPY . .
ADDCopy with extraction/URLsADD archive.tar.gz /app/
RUNExecute commandsRUN npm install
ENVSet environment variablesENV NODE_ENV=production
ARGBuild-time variablesARG VERSION=1.0
EXPOSEDocument portsEXPOSE 3000
VOLUMECreate mount pointVOLUME /data
USERSet user for commandsUSER node
CMDDefault commandCMD ["npm", "start"]
ENTRYPOINTContainer executableENTRYPOINT ["node"]

Building Images

Create a Dockerfile

FROM nginx:alpine
COPY ./html /usr/share/nginx/html
EXPOSE 80

Build 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
dist

Performance Impact

A large build context slows down builds. Always use .dockerignore to exclude unnecessary files.

Next Steps

On this page