TL;DR
Docker containerizes applications, ensuring consistent environments from development to production. It facilitates deployment, scaling and infrastructure management. Here's how to use Docker in 2026.
Who is this for
- Developers wanting to standardize environments
- DevOps engineers managing infrastructure
- Companies planning to scale applications
Keywords (SEO)
docker, containerization, docker compose, kubernetes, container deployment
What is Docker?
Docker is a containerization platform:
- Isolated environments (containers)
- Consistency between environments
- Lightweight (vs virtual machines)
- Fast startup
Container vs VM:
- VM: full OS, slower, more resources
- Container: shared OS, faster, fewer resources
Benefits:
- "Works on my machine" → solved
- Faster deployments
- Easier scaling
- Better resource utilization
Docker Basics
Dockerfile
Basic example:
# Base image
FROM node:18-alpine
# Working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy application code
COPY . .
# Expose port
EXPOSE 3000
# Start application
CMD ["npm", "start"]
Build and Run
Build image:
docker build -t my-app:latest .
Run container:
docker run -p 3000:3000 my-app:latest
Run in background:
docker run -d -p 3000:3000 --name my-app my-app:latest
Dockerfile Best Practices
1. Multi-stage Builds
Reduce image size:
# Stage 1: Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Production
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]
2. Layer Caching
Optimal order:
# 1. Dependencies (rarely change)
COPY package*.json ./
RUN npm ci
# 2. Application code (often changes)
COPY . .
3. Use .dockerignore
.dockerignore:
node_modules
npm-debug.log
.git
.env
dist
*.md
4. Minimal Base Images
Alpine Linux:
FROM node:18-alpine # ~5MB vs ~150MB for node:18
Distroless (even smaller):
FROM gcr.io/distroless/nodejs18-debian11
5. Non-root User
Security:
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs
Docker Compose
Basic Configuration
docker-compose.yml:
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
depends_on:
- db
- redis
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=mydb
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
Running
Start all services:
docker-compose up -d
Logs:
docker-compose logs -f app
Stop:
docker-compose down
Kubernetes
Basic Concepts
Pod:
- Smallest unit
- One or more containers
- Shared resources (network, storage)
Deployment:
- Manages Pod replicas
- Rolling updates
- Rollback
Service:
- Expose Pods as network
- Load balancing
- Service discovery
Basic Deployment
deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-app:latest
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: "production"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
Service:
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: LoadBalancer
Apply:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
Scaling
Horizontal Pod Autoscaler (HPA)
Automatic scaling:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Manual Scaling
kubectl scale deployment my-app --replicas=5
Monitoring and Logging
Health Checks
In Dockerfile:
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
In Kubernetes:
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
Logging
Docker logs:
docker logs my-app
docker logs -f my-app # Follow
Kubernetes logs:
kubectl logs deployment/my-app
kubectl logs -f deployment/my-app
Security Best Practices
1. Scan Images
docker scan my-app:latest
2. Minimal Permissions
USER nonroot
3. Secrets Management
Not in Dockerfile:
# ❌ Bad
ENV API_KEY=secret123
Use secrets:
# Kubernetes
apiVersion: v1
kind: Secret
metadata:
name: api-secret
data:
api-key: <base64-encoded>
4. Regular Updates
Update base images:
FROM node:18-alpine # Use latest version
CI/CD with Docker
GitHub Actions example:
- name: Build Docker image
run: docker build -t my-app:${{ github.sha }} .
- name: Push to registry
run: |
docker tag my-app:${{ github.sha }} my-registry/my-app:latest
docker push my-registry/my-app:latest
- name: Deploy to Kubernetes
run: |
kubectl set image deployment/my-app app=my-registry/my-app:latest
FAQ
Is Docker Needed for Small Projects?
Not always, but worth it. Facilitates deployment, ensures environment consistency and prepares for scaling.
Docker vs Kubernetes?
Docker: containerization of applications. Kubernetes: container orchestration (for larger systems).
How Often to Update Base Images?
Regularly (monthly). Use tools like Dependabot for automatic updates.