Docker Full Tutorial — Part 12: Real-World Docker Project

By Suraj Ahir 2025-12-15 11 min read

← Part 11Docker Tutorial · Part 12 of 12
Docker Full Tutorial — Part 12: Real-World Docker Project

This is the part where everything comes together. Over eleven parts, you have learned containers, images, Dockerfiles, volumes, networking, Compose, registries, multi-stage builds, security, CI/CD, and Swarm. Now we build a real production project that uses all of it: a Node.js API with PostgreSQL, Redis caching, nginx reverse proxy, Docker Compose configuration, and a GitHub Actions pipeline.

This is the pattern I use in real projects. Not theoretical — practical. Copy what is useful, adapt what needs adapting.

Project Architecture

Our stack: nginx (reverse proxy + SSL termination), Node.js API (3 replicas), PostgreSQL (persistent storage), Redis (session and cache), and a CI/CD pipeline that builds and deploys on every push to main.

Production docker-compose.yml

Complete production compose file
version: '3.8'

services:
  nginx:
    image: nginx:1.25-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - ssl-certs:/etc/nginx/ssl:ro
    depends_on:
      - app
    restart: unless-stopped

  app:
    image: registry.example.com/myapp:${IMAGE_TAG:-latest}
    deploy:
      replicas: 3
    environment:
      NODE_ENV: production
      DB_HOST: postgres
      REDIS_HOST: redis
    env_file:
      - .env.production
    depends_on:
      postgres:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "wget", "-q", "-O-", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    restart: unless-stopped

  postgres:
    image: postgres:15-alpine
    volumes:
      - postgres-data:/var/lib/postgresql/data
    env_file:
      - .env.production
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis-data:/data
    restart: unless-stopped

volumes:
  postgres-data:
  redis-data:
  ssl-certs:

nginx Reverse Proxy Configuration

nginx/nginx.conf
upstream app {
    server app:3000;
}

server {
    listen 80;
    server_name api.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.yourdomain.com;

    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;

    location / {
        proxy_pass http://app;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }
}

Deployment Script

deploy.sh
#!/bin/bash
set -e

IMAGE_TAG=$1
if [ -z "$IMAGE_TAG" ]; then
    echo "Usage: ./deploy.sh IMAGE_TAG"
    exit 1
fi

echo "Deploying image tag: $IMAGE_TAG"

# Pull new image
IMAGE_TAG=$IMAGE_TAG docker compose pull app

# Deploy with zero downtime
IMAGE_TAG=$IMAGE_TAG docker compose up -d --no-deps --scale app=6 app
sleep 15
IMAGE_TAG=$IMAGE_TAG docker compose up -d --no-deps --scale app=3 app

echo "Deployment complete"
docker compose ps

You have now completed the full Docker series. You understand Docker from first principles through production deployment. The natural next step is the Kubernetes series — which takes everything you know about Docker containers and shows you how to orchestrate them at scale in production clusters. Every company running containers at scale uses Kubernetes, and Docker is the foundation everything builds on.

Frequently Asked Questions

What does a production Docker deployment look like?

A production Docker deployment typically includes: a multi-stage Dockerfile for each application service, a docker-compose.yml (or Kubernetes manifests) defining all services together, nginx as a reverse proxy handling SSL termination, named volumes for all persistent data, health checks on every service, a CI/CD pipeline that builds and scans images on every commit, and a registry to store versioned images.

Should I use Docker Compose in production?

For simple to medium deployments (one to a few servers), Docker Compose with docker compose up -d is perfectly valid in production. For large-scale deployments across many servers needing automatic failover, self-healing, and sophisticated scheduling, move to Kubernetes or Docker Swarm. Do not let perfect be the enemy of good — Docker Compose in production is far better than ad-hoc container management.

How do I handle database migrations in Docker?

The recommended pattern is an init container or entrypoint script that runs migrations before the application starts. In Docker Compose, use command to override the default CMD with a script that runs migrations then starts the app. In Kubernetes, use an initContainer. Always ensure migrations are idempotent — safe to run multiple times.

How do I set up nginx as a reverse proxy in Docker?

Run nginx as a container with a custom nginx.conf that proxy_passes to your application container by its service name (DNS resolution in Docker networks). Mount the config file as a bind mount or COPY it into a custom nginx image. For HTTPS, mount SSL certificates as volumes or use certbot in a companion container.

How do I monitor a Docker production deployment?

Use Portainer for a visual dashboard of all containers and their resource usage. Use docker stats for live resource monitoring from the CLI. Set up log forwarding to a centralized system (Loki, ELK Stack). Use health checks in your Compose file so Docker restarts unhealthy containers automatically. Set memory limits to prevent any container from consuming all host memory.

Key takeaways

Continue reading
Next series — Kubernetes Part 1
Now let's run containers at production scale.
Suraj Ahir — author of SRJahir Tech

Written by

Suraj Ahir

Cloud & DevOps engineer running four live production services on my own AWS infrastructure. I write everything on this site myself — no ghostwriters, no AI filler.

← Part 11Docker Tutorial · Part 12 of 12
← Back to Blog
Disclaimer: This content is for educational purposes only. SRJahir Tech does not guarantee any specific outcome, job placement, or exam result.