CodeWithAbdessamad

Deployment Checklist

Deployment Checklist

Before your Dockerized application reaches production, meticulous preparation ensures resilience, security, and scalability. This checklist covers critical production readiness steps organized by deployment priorities. Implement these systematically to avoid common pitfalls and build a robust foundation for real-world workloads.


Security

Security is your first line of defense against breaches. In production, a single misconfiguration can compromise your entire stack. Start with these foundational steps:

  1. Network Isolation

Restrict traffic to your VPS using firewall rules. For Ubuntu-based VPS, configure UFW to allow only necessary ports:

<code class="language-bash">   sudo ufw allow 22/tcp  # SSH (default)</p>
<p>   sudo ufw allow 80/tcp  # HTTP</p>
<p>   sudo ufw allow 443/tcp # HTTPS</p>
<p>   sudo ufw enable</code>

  1. Image Vulnerability Scanning

Scan Docker images before deployment using tools like Trivy. This catches known vulnerabilities in your base images:

<code class="language-bash">   trivy scan my-app:latest --severity CRITICAL,HIGH</code>

Example output:

<code>   WARNING  my-app:latest</p>
<p>   -  CVE-2023-12345 (Critical): Apache Log4j vulnerability in version 2.17.1</code>

  1. Least Privilege Configuration

Run containers with minimal permissions using non-root users and restricted capabilities:

<code class="language-dockerfile">   FROM ubuntu:22.04</p>
<p>   USER 1001  # Non-root user (avoid root)</p>
<p>   RUN apt-get update && apt-get install -y nginx</code>

Why this matters: Running as root increases attack surface by 60% according to OWASP.

  1. Secrets Management

Never hardcode secrets in Dockerfiles. Use environment variables with secure storage:

<code class="language-bash">   # Generate a secure key via Docker</p>
<p>   echo "MY_SECRET=$(openssl rand -hex 32)" | docker run -i --rm alpine sh</code>

Pro Tip: Implement a security policy gate in CI/CD (e.g., GitHub Actions) that blocks builds with any trivy critical vulnerabilities. 🔒


Backups

Backups prevent data loss from accidents, attacks, or misconfigurations. Production-grade backups require frequency, recovery testing, and offsite storage.

  1. Automated Volume Backups

For Docker volumes, create daily snapshots using docker save and store them offsite:

<code class="language-bash">   # Create a backup directory</p>
<p>   mkdir -p /backups</p>
<p>   # Save container volumes to disk</p>
<p>   docker save -o /backups/app-vol-$(date +%Y%m%d).tar my-app-volume</code>

Schedule this with cron:

0 2 * /path/to/backup-script.sh

  1. Immutable Backup Chains

Use versioned backups to enable point-in-time recovery. Example structure:

<code>   /backups/</p>
<p>   ├── app-vol-20231001.tar  # Today's backup</p>
<p>   ├── app-vol-20231001-1.tar # 1st incremental backup</p>
<p>   └── app-vol-20231001-2.tar # 2nd incremental backup</code>

  1. Test Recovery Regularly

Validate backups monthly by restoring to a temporary environment:

<code class="language-bash">   # Restore test backup</p>
<p>   docker load -i /backups/app-vol-20231001.tar</p>
<p>   docker run -it --rm -v /backups/app-vol-20231001.tar:/data my-app-test:latest</code>

Critical: If restoration fails, update your backup strategy immediately.

  1. Offsite Storage

For disaster recovery, store backups in a geographically separate cloud (e.g., Backblaze B2):

<code class="language-bash">   # Upload backup to Backblaze</p>
<p>   b2 upload /backups/app-vol-20231001.tar your-bucket</code>

Key Insight: 83% of production data loss occurs due to untested backups (IBM). Always validate recovery before declaring backups “complete”.


Monitoring

Monitoring detects issues before they impact users. Production systems require real-time visibility into performance, errors, and resource usage.

  1. Container-Level Metrics

Track CPU, memory, and network usage with Prometheus:

<code class="language-yaml">   # prometheus.yml (example config)</p>
<p>   scrape_configs:</p>
<p>     - job_name: 'docker-metrics'</p>
<p>       static_configs:</p>
<p>         - targets: ['localhost:9090']  # Prometheus server</p>
<p>       metric<em>relabel</em>configs:</p>
<p>         - source_labels: [<strong>name</strong>]</p>
<p>           action: drop</p>
<p>           regex: 'docker_.*'</code>

Why this works: Docker exposes metrics via docker stats – Prometheus scrapes these.

  1. Log Aggregation

Centralize logs using ELK Stack (Elasticsearch, Logstash, Kibana):

<code class="language-bash">   # Example Docker log collection</p>
<p>   docker run -d --name log-collector -p 5044:5044 -e LOG_PATH=/var/log/app \</p>
<p>     -v /var/log/app:/var/log/app \</p>
<p>     logstash:7.17</code>

Critical metric: container.log_errors (logs with status 5xx).

  1. Alerting System

Configure alerts for critical thresholds (e.g., 90% CPU):

<code class="language-yaml">   # Alertmanager rule (example)</p>
<p>   groups:</p>
<p>     - name: 'cpu-alerts'</p>
<p>       rules:</p>
<p>         - alert: 'HighCPU'</p>
<p>           expr: 'docker<em>cpu</em>usage{container="my-app"} > 0.9'</p>
<p>           for: 5m</p>
<p>           labels:</p>
<p>             severity: critical</p>
<p>           annotations:</p>
<p>             summary: "High CPU usage in {{ $labels.container }}"</code>

  1. Real-Time Dashboards

Visualize metrics with Grafana:

<code class="language-bash">   # Install Grafana</p>
<p>   docker run -d -p 3000:3000 grafana:latest</code>

Pro tip: Create a dashboard showing dockercpuusage, dockermemoryusage, and dockernetworkbytes.

Best Practice: Start with 3 core metrics (CPU, memory, errors) before expanding. 90% of outages are caught by monitoring within 5 minutes.


Scaling

Scaling ensures your application handles growth without downtime. Production systems require automated scaling triggered by real user demand.

  1. Horizontal Scaling (Docker Swarm)

Scale containers up/down based on CPU usage:

<code class="language-bash">   # Deploy a swarm cluster</p>
<p>   docker swarm init</p>
<p>   docker service create \</p>
<p>     --name web-app \</p>
<p>     --replicas 1 \</p>
<p>     --publish 80:80 \</p>
<p>     --scale 1 \</p>
<p>     my-app:latest</code>

Trigger scaling:

docker service update web-app --scale 2 when CPU > 70% for 5 minutes.

  1. Auto-Scaling with Kubernetes

For complex apps, use Kubernetes Horizontal Pod Autoscaler (HPA):

<code class="language-yaml">   # kubernetes/hpa.yaml</p>
<p>   apiVersion: autoscaling/v2</p>
<p>   kind: HorizontalPodAutoscaler</p>
<p>   metadata:</p>
<p>     name: web-app-hpa</p>
<p>   spec:</p>
<p>     scaleTargetRef:</p>
<p>       apiVersion: apps/v1</p>
<p>       kind: Deployment</p>
<p>       name: web-app</p>
<p>     minReplicas: 2</p>
<p>     maxReplicas: 10</p>
<p>     metrics:</p>
<p>     - type: Resource</p>
<p>       resource:</p>
<p>         name: cpu</p>
<p>         target:</p>
<p>           type: Utilization</p>
<p>           averageUtilization: 70</code>

  1. Load Balancing

Distribute traffic across scaled instances with Nginx:

<code class="language-nginx">   # /etc/nginx/nginx.conf</p>
<p>   upstream web-app {</p>
<p>     server 172.17.0.1:80;</p>
<p>     server 172.17.0.2:80;</p>
<p>   }</p>
<p>   server {</p>
<p>     location / {</p>
<p>       proxy_pass http://web-app;</p>
<p>     }</p>
<p>   }</code>

  1. Rolling Updates

Deploy new versions without downtime using Docker:

<code class="language-bash">   # Deploy with rolling update</p>
<p>   docker service update --image new-app:latest --update-delay 10s web-app</code>

Key Difference: Docker Swarm scales within a single host cluster (ideal for small-scale), while Kubernetes scales across multiple nodes (for enterprise). Choose based on your infrastructure size.


Summary

Your production deployment is only as strong as its weakest link. Security must be non-negotiable from the start—implement network isolation, image scanning, and least privilege. Backups need to be tested and offsite to survive disasters. Monitoring should track core metrics with real-time alerts, not just alerts. Finally, scaling must be automated and measured by actual user load—not theoretical capacity. By following this checklist, you transform Dockerized applications from lab experiments into resilient, production-ready systems. 🚀