name: docker-basics description: Apply when containerizing applications: writing Dockerfiles, docker-compose configurations, and multi-stage builds. version: 1.1.0 tokens: ~650 confidence: high sources:
- https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
- https://docs.docker.com/compose/ last_validated: 2025-12-10 next_review: 2025-12-24 tags: [docker, containers, devops, deployment]
When to Use
Apply when containerizing applications: writing Dockerfiles, docker-compose configurations, and multi-stage builds.
Patterns
Pattern 1: Node.js Dockerfile (Multi-stage)
# Source: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
# Build stage
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Create non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
USER nextjs
EXPOSE 3000
CMD ["node", "dist/index.js"]
Pattern 2: .dockerignore
# Source: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
node_modules
npm-debug.log
.git
.gitignore
.env
.env.*
Dockerfile*
docker-compose*
.dockerignore
README.md
.next
coverage
.nyc_output
Pattern 3: Docker Compose for Development
# Source: https://docs.docker.com/compose/
# docker-compose.yml
# Note: version field is deprecated in Compose Specification
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules # Preserve container's node_modules
environment:
- DATABASE_URL=postgres://postgres:postgres@db:5432/myapp
depends_on:
- db
- redis
db:
image: postgres:16-alpine
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: myapp
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
Pattern 4: Health Checks
# Source: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
# In docker-compose
services:
app:
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
interval: 30s
timeout: 3s
retries: 3
Pattern 5: Common Commands
# Build image
docker build -t myapp:latest .
# Run container
docker run -d -p 3000:3000 --name myapp myapp:latest
# View logs
docker logs -f myapp
# Execute command in container
docker exec -it myapp sh
# Docker Compose
docker compose up -d # Start in background
docker compose down # Stop and remove
docker compose logs -f app # Follow logs
docker compose exec app sh # Shell into service
Pattern 6: Environment Variables
# docker-compose.yml
services:
app:
env_file:
- .env # Load from file
environment:
- NODE_ENV=production
- API_KEY=${API_KEY} # From host environment
Anti-Patterns
- Running as root - Always create non-root user
- No .dockerignore - Bloats image with unnecessary files
- Single stage for production - Use multi-stage builds
- Hardcoded secrets - Use env vars or secrets
Verification Checklist
- Multi-stage build (separate build/runtime)
- Non-root user for runtime
- .dockerignore excludes dev files
- Health check configured
- Environment variables externalized