08 - Docker Production Best Practices
Docker Production Best Practices
In earlier tutorials, we covered Docker basics: concepts, commands, image building, data management, networking, and Docker Compose. These are enough for development, but production deployments require more: security, reliability, performance, and maintainability. This article shares Docker best practices for production.
Security best practices
1. Use minimal base images
Use minimal images like Alpine or Distroless to reduce the attack surface.
# Use Alpine as a base image
FROM alpine:3.14
# Or use an official lightweight image
FROM node:16-alpine
2. Do not run containers as root
Create a non-root user in the Dockerfile and run the app as that user.
# Create a non-root user
RUN addgroup -g 1000 appuser && \
adduser -u 1000 -G appuser -s /bin/sh -D appuser
# Switch to that user
USER appuser
# Run the app
CMD ["node", "app.js"]
3. Scan images for vulnerabilities
Use tools like Trivy, Clair, or Docker Scout to scan images.
# Scan an image with Trivy
trivy image myapp:1.0
4. Use content trust and image signing
Enable Docker Content Trust to ensure only signed images run.
# Enable Docker Content Trust
export DOCKER_CONTENT_TRUST=1
# Push a signed image
docker push myapp:1.0
5. Limit container resources
Restrict CPU, memory, and other resources to prevent DoS impact.
docker run -d \
--name myapp \
--memory="512m" \
--memory-swap="512m" \
--cpu-shares=512 \
myapp:1.0
6. Use read-only filesystems
Set the container filesystem to read-only and mount volumes only where writes are needed.
docker run -d \
--name myapp \
--read-only \
--tmpfs /tmp \
-v logs:/app/logs \
myapp:1.0
Monitoring and logging
1. Centralized log management
Use log drivers to send container logs to centralized systems like ELK, Graylog, or Fluentd.
# Use json-file with log rotation
docker run -d \
--name myapp \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
myapp:1.0
# Or use the syslog driver
docker run -d \
--name myapp \
--log-driver syslog \
--log-opt syslog-address=udp://logserver:514 \
myapp:1.0
2. Container health checks
Add HEALTHCHECK in the Dockerfile or configure at runtime.
# HEALTHCHECK in Dockerfile
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost/health || exit 1
# HEALTHCHECK at runtime
docker run -d \
--name myapp \
--health-cmd="curl -f http://localhost/health || exit 1" \
--health-interval=30s \
--health-retries=3 \
--health-timeout=3s \
myapp:1.0
3. Use monitoring tools
Use Prometheus, Grafana, cAdvisor, etc., to monitor resource usage and performance.
# docker-compose.yml example with Prometheus and Grafana
version: '3'
services:
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
depends_on:
- prometheus
Performance optimization
1. Optimize image size
- Use multi-stage builds
- Combine RUN instructions to reduce layers
- Clean unnecessary files and caches
# Multi-stage build example
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
2. Use volumes to improve I/O performance
For I/O-heavy apps, use volumes to boost performance.
docker run -d \
--name db \
-v db-data:/var/lib/postgresql/data \
postgres:13
3. Set resource limits appropriately
Set CPU and memory limits according to app needs to avoid contention.
docker run -d \
--name myapp \
--cpus=2 \
--memory=2g \
myapp:1.0
High availability and scalability
1. Use an orchestrator
In production, use Kubernetes, Docker Swarm, or Nomad to manage containers.
# Initialize Docker Swarm
docker swarm init
# Deploy a service
docker service create \
--name myapp \
--replicas 3 \
--publish 8080:80 \
myapp:1.0
2. Service discovery and load balancing
Leverage built-in discovery and load balancing from orchestrators, or tools like Traefik/Nginx.
# docker-compose.yml example using Traefik as reverse proxy
version: '3'
services:
traefik:
image: traefik:v2.5
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
webapp:
image: myapp:1.0
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(`example.com`)"
- "traefik.http.routers.webapp.entrypoints=web"
3. Auto scaling containers
Adjust replica counts based on load.
# Auto scaling in Docker Swarm
docker service update \
--replicas-max 10 \
--replicas-min 2 \
myapp
Backup and disaster recovery
1. Regularly back up data volumes
# Back up a data volume
docker run --rm \
-v db-data:/source \
-v $(pwd):/backup \
alpine \
tar -czf /backup/db-backup-$(date +%Y%m%d).tar.gz -C /source .
2. Auto-restart containers
docker run -d \
--name myapp \
--restart unless-stopped \
myapp:1.0
3. Multi-region deployments
Deploy across regions for high availability and disaster recovery.
CI/CD best practices
1. Automate build and test
Use CI/CD tools (Jenkins, GitHub Actions, GitLab CI) to build and test images automatically.
# GitHub Actions workflow example
name: Build and Test
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build the Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Test the Docker image
run: docker run --rm myapp:${{ github.sha }} npm test
2. Blue-green or canary releases
Use blue-green or canary strategies to reduce deployment risk.
# Blue-green deployment example (Docker Swarm)
# Deploy new version (green)
docker service create \
--name myapp-green \
--replicas 3 \
myapp:2.0
# After validation, update routing
docker service update \
--publish-add 8080:80 \
myapp-green
# Remove old version (blue)
docker service rm myapp-blue
Summary
We covered Docker production best practices spanning security, monitoring, performance, high availability, and CI/CD. By following these guidelines you can build a more stable, secure, and efficient Docker environment. Choose strategies and tools based on your scenario. In the next tutorial, we’ll look at common Docker issues and troubleshooting techniques.