Containers package your application with all its dependencies into a portable, reproducible unit. This solves "works on my machine" permanently.
# Multi-stage build — keeps final image small
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# Stage 2: Production image
FROM node:20-alpine
WORKDIR /app
# Don't run as root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Copy only what's needed
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]
# docker-compose.yml — typical web app stack
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/myapp
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
restart: unless-stopped
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 5s
timeout: 3s
retries: 5
cache:
image: redis:7-alpine
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- app
volumes:
pgdata:
# Commands
docker compose up -d # Start all services
docker compose logs -f app # Follow app logs
docker compose ps # Status of all services
docker compose down # Stop and remove
docker compose up -d --build # Rebuild and restart
| Registry | Free Tier | Best For |
|---|---|---|
| Docker Hub | 1 private repo | Public images, open source |
| GitHub Container Registry (ghcr.io) | Generous free | GitHub-based projects |
| AWS ECR | 500MB free | AWS deployments |
| Google Artifact Registry | 500MB free | GCP deployments |
Kubernetes (K8s) manages containers at scale: scheduling, scaling, self-healing, service discovery, rolling updates.
# Pod — smallest deployable unit (one or more containers)
# Deployment — manages replica sets, rolling updates
# Service — stable network endpoint for pods
# Ingress — HTTP routing from outside the cluster
# Example: Deployment + Service + Ingress
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: ghcr.io/you/myapp:v1.2.3
ports:
- containerPort: 3000
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-svc
port:
number: 80
| Service | Provider | Starting Cost | Notes |
|---|---|---|---|
| EKS | AWS | $0.10/hr control plane + nodes | Most popular, complex |
| GKE | 1 free zonal cluster + nodes | Best K8s experience (Google made K8s) | |
| AKS | Azure | Free control plane + nodes | Good for Microsoft shops |
| DOKS | DigitalOcean | Free control plane + $12/node | Simplest managed K8s |