Skip to content

🐳 Docker & Containers ​

Containerizing applications for consistent environments and deployment.

Dockerfile best practices ​

dockerfile
# Use specific version, not :latest
FROM node:20-alpine

WORKDIR /app

# Copy dependency files first (cache layer)
COPY package.json package-lock.json ./
RUN npm ci --production

# Copy source code
COPY . .

# Non-root user
RUN addgroup -S app && adduser -S app -G app
USER app

EXPOSE 3000
CMD ["node", "server.js"]

Key principles ​

  • One process per container β€” Don't run multiple services in one container
  • Minimize image size β€” Use Alpine, multi-stage builds
  • Layer caching β€” Put rarely-changing layers first
  • No secrets in images β€” Use env vars or mounted secrets
  • Immutable images β€” Same image across all environments

Multi-stage build ​

dockerfile
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build

# Production stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]

Docker Compose (local dev) ​

yaml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=pass

volumes:
  pgdata:

Common commands ​

CommandPurpose
docker build -t app .Build image
docker run -p 3000:3000 appRun container
docker compose up -dStart all services
docker compose logs -fFollow logs
docker exec -it <id> shShell into container
docker system pruneClean unused resources

Pergame Knowledge Base