Back

Mastering Docker : Real-World Patterns and Tips

Jul 7, 2025 (11mo ago)

Docker Mastery: Real-World Patterns, Gotchas, and Power Moves

Docker is everywhere, but most devs only scratch the surface. Here’s a practical, code-heavy guide to using Docker like a pro—beyond just docker run and docker-compose up.

Multi-Stage Builds: Smaller, Safer Images

# --- Build Stage ---
FROM node:20-alpine AS build
WORKDIR /app
COPY package.json .
RUN npm install --frozen-lockfile
COPY . .
RUN npm run build
 
# --- Production Stage ---
FROM node:20-alpine AS prod
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY package.json .
CMD ["node", "dist/server.js"]

Why?

Pattern Benefit
Multi-stage Smaller images, no dev deps
COPY --from Only what you need in prod
Alpine base Lower attack surface, smaller

Debugging Containers: Attach, Logs, and Shell

# See logs
docker logs <container>
 
# Attach a shell (if bash is installed)
docker exec -it <container> bash
 
# For Alpine/minimal images
docker exec -it <container> sh

Performance Tips

  • Use .dockerignore to avoid copying node_modules, build artifacts, etc.
  • Pin base image versions (avoid latest).
  • Layer order matters: put rarely-changed lines (like RUN npm install) first.
  • Use healthchecks for robust containers:
HEALTHCHECK CMD curl --fail http://localhost:3000/health || exit 1

Compose: Real-World Example

version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - db
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:

Common Gotchas

Problem Solution/Tip
"Works on my machine" Use Compose for parity, pin image versions
File permissions in container Set USER and chown as needed
Large images Multi-stage, .dockerignore, Alpine
Slow builds Order layers, cache dependencies