Use when creating Dockerfiles, building container images, optimizing image size, configuring multi-stage builds, or troubleshooting Docker build failures - focuses on containerization and Docker best practices
☐ Use official images from Docker Hub
☐ Choose minimal base images (alpine, slim variants)
☐ Match language/runtime version to production
☐ Consider security updates (avoid latest tag)
Base image examples:
node:20-alpine (smaller) or node:20-slimpython:3.11-slim or python:3.11-alpinegolang:1.21-alpine or scratch for productiondebian:bookworm-slim, ubuntu:22.04☐ Start with FROM base image
☐ Install system dependencies first (change infrequently)
☐ Copy dependency files (package.json, requirements.txt)
☐ Install dependencies (leverage layer caching)
☐ Copy application code (changes frequently)
☐ Define CMD or ENTRYPOINT
Layer ordering for caching:
FROM node:20-alpine
# 1. Install system dependencies (rarely changes)
RUN apk add --no-cache python3 make g++
# 2. Set working directory
WORKDIR /app
# 3. Copy dependency files only (leverage cache)
COPY package*.json ./
# 4. Install dependencies (cached unless package.json changes)
RUN npm ci --only=production
# 5. Copy application code (changes frequently)
COPY . .
# 6. Build application (if needed)
RUN npm run build
# 7. Set runtime command
EXPOSE 8080
CMD ["node", "dist/server.js"]
☐ Create builder stage for compilation ☐ Create production stage with minimal runtime ☐ Copy only necessary artifacts from builder ☐ Reduce final image size significantly
Multi-stage build example (Node.js):
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Production
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 8080
CMD ["node", "dist/server.js"]
Multi-stage build example (Go):
# Stage 1: Build
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server
# Stage 2: Production (minimal)
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/server .
EXPOSE 8080
CMD ["./server"]
☐ Use .dockerignore to exclude unnecessary files ☐ Combine RUN commands to reduce layers ☐ Remove build dependencies after use ☐ Use --no-cache for package managers ☐ Clean up temporary files in same layer
Create .dockerignore:
node_modules
npm-debug.log
.git
.env
.env.local
dist
build
*.md
.vscode
.idea
coverage
.DS_Store
Combine RUN commands:
# ❌ Bad - creates multiple layers
RUN apk add curl
RUN apk add git
RUN curl -o file.tar.gz https://example.com/file.tar.gz
RUN tar -xzf file.tar.gz
RUN rm file.tar.gz
# ✅ Good - single layer
RUN apk add --no-cache curl git \
&& curl -o file.tar.gz https://example.com/file.tar.gz \
&& tar -xzf file.tar.gz \
&& rm file.tar.gz
☐ Use ENV for environment variables ☐ Use ARG for build-time variables ☐ Expose necessary ports ☐ Avoid hardcoding secrets (use runtime env vars)
Environment configuration:
# Build-time variables
ARG NODE_ENV=production
# Runtime environment variables
ENV NODE_ENV=$NODE_ENV \
PORT=8080 \
LOG_LEVEL=info
# Expose port
EXPOSE 8080
# Run as non-root user (security)
RUN addgroup -g 1001 -S nodejs \
&& adduser -S nodejs -u 1001
USER nodejs
CMD ["node", "server.js"]
☐ Build with descriptive tag
☐ Use version tags, not just latest
☐ Tag for multiple registries if needed
☐ Check image size after build
Build commands:
# Build with tag
docker build -t myapp:1.0.0 .
# Build with multiple tags
docker build -t myapp:1.0.0 -t myapp:latest .
# Build for specific platform
docker buildx build --platform linux/amd64 -t myapp:1.0.0 .
# Build with build args
docker build --build-arg NODE_ENV=production -t myapp:1.0.0 .
☐ Run container: docker run -p 8080:8080 myapp:1.0.0
☐ Test application responds correctly
☐ Check logs: docker logs <container-id>
☐ Verify environment variables
☐ Test with volume mounts (if needed)
Testing commands:
# Run with environment variables
docker run -p 8080:8080 -e DATABASE_URL=postgres://... myapp:1.0.0
# Run with volume mount
docker run -v $(pwd)/data:/app/data myapp:1.0.0
# Run interactively for debugging
docker run -it myapp:1.0.0 sh
# Check image layers
docker history myapp:1.0.0
☐ Tag image for registry ☐ Authenticate with registry ☐ Push image ☐ Verify image pushed successfully
Push to Docker Hub:
docker tag myapp:1.0.0 username/myapp:1.0.0
docker push username/myapp:1.0.0
Push to Google Container Registry:
docker tag myapp:1.0.0 gcr.io/project-id/myapp:1.0.0
docker push gcr.io/project-id/myapp:1.0.0
Push to GitHub Container Registry:
docker tag myapp:1.0.0 ghcr.io/username/myapp:1.0.0
docker push ghcr.io/username/myapp:1.0.0
docker-compose.yml example: