☸️ Docker & Kubernetes
Docker Container vs VM Model
How Docker containers differ from VMs and why they're the foundation of modern deployment
Docker containers share the host kernel — there's no guest OS to boot. This makes them start in milliseconds and use a fraction of VM memory. The real value isn't speed though; it's reproducibility: the same image runs identically on a developer's laptop, CI, staging, and production.
Key Concepts
Images are Immutable
A Docker image is a layered, read-only snapshot. Container = image + writable layer. You can't accidentally change an image in production — you must rebuild it. This is Immutable Infrastructure.
Eliminates 'Works on My Machine'
Image packages the app binary, runtime, libraries, configs, and OS user-space together. Dev, CI, and prod run byte-for-byte identical environments.
Layer Caching Speeds Builds
Each Dockerfile instruction creates a cache layer. Put frequently changing layers (COPY source code) last, rarely changing layers (npm install) first. A 10-minute build becomes 30 seconds.
Multi-stage Builds
Build in a full compiler image, copy only the binary to a minimal runtime image (alpine). Reduces production image from 1.2GB to 50MB, eliminating attack surface.
VM vs Container Architecture
| Aspect | Virtual Machine | Docker Container |
|---|---|---|
| Isolation | Full hardware virtualization (Hypervisor) | OS-level namespaces (cgroups, namespaces) |
| Startup time | 30-120 seconds (boots full OS) | < 1 second (process starts) |
| Memory overhead | 500MB–2GB per VM (guest OS) | < 10MB per container |
| Image size | GB+ (full OS image) | MB (layered, shared base layers) |
| Security isolation | Strong (hardware boundary) | Process-level (shared kernel — weaker) |
Optimized Dockerfile — NestJS Multi-Stage Build
Dockerfiledockerfile
1# ── Stage 1: Build ──────────────────────────────────
2FROM node:20-alpine AS builder
3WORKDIR /app
4
5# Copy package files first — cached until package.json changes
6COPY package*.json ./
7RUN npm ci --only=production # Deterministic install
8
9COPY . .
10RUN npm run build # Compile TypeScript
11
12# ── Stage 2: Runtime ─────────────────────────────────
13FROM node:20-alpine AS runtime
14WORKDIR /app
15
16# Non-root user for security (လုံခြုံရေးအတွက် Root မဟုတ်သော User ဖန်တီးခြင်း)
17RUN addgroup -g 1001 appgroup && adduser -u 1001 -G appgroup -s /bin/sh -D appuser
18
19# Copy only what's needed — no src/, no dev deps
20COPY /app/dist ./dist
21COPY /app/node_modules ./node_modules
22
23USER appuser
24EXPOSE 3000
25HEALTHCHECK CMD wget -qO- http://localhost:3000/health || exit 1
26CMD ["node", "dist/main.js"]
27# Final image size: ~95MB vs 1.2GB without multi-stage💡
Senior Architect Insight: The most impactful Docker optimization is .dockerignore — exclude node_modules, .git, dist/, logs/. Without it, COPY . . sends gigabytes of data to the Docker daemon on every build, making builds 10x slower even with layer caching.