Skip to content

malek0501/docker-microservices-stack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Review Assignment Due Date

🏗️ Lab 05 - Architecture Multi-Services avec Docker Compose

📋 Table des matières


🎯 Vue d'ensemble

Ce projet implémente une architecture microservices complète orchestrée par Docker Compose. L'application déploie 7 conteneurs interconnectés qui collaborent pour fournir une application web full-stack avec monitoring en temps réel.

Objectifs du projet

  • ✅ Orchestrer plusieurs services Docker via Docker Compose
  • ✅ Implémenter un reverse proxy avec Traefik
  • ✅ Déployer une application Flask avec base de données et cache
  • ✅ Mettre en place un système de monitoring (Prometheus + Grafana)
  • ✅ Assurer la communication sécurisée entre conteneurs

🏛️ Architecture détaillée

┌─────────────────────────────────────────────────────────────────────┐
│                          UTILISATEUR FINAL                           │
└────────────────────────────┬────────────────────────────────────────┘
                             │ HTTP Requests
                             │ Ports: 80, 8080, 3000, 9090
                             ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    🌐 TRAEFIK (Reverse Proxy)                        │
│  • Routage intelligent basé sur Host et PathPrefix                   │
│  • Load balancing automatique                                        │
│  • Service discovery via labels Docker                               │
│  • Dashboard de monitoring sur :8080                                 │
└──────────────┬────────────────────────────────┬─────────────────────┘
               │                                │
               │ Host: localhost                │ Host: localhost
               │ Path: /                        │ PathPrefix: /api
               ▼                                ▼
┌──────────────────────────┐      ┌────────────────────────────────────┐
│  📄 NGINX (Frontend)     │      │  🐍 FLASK (Backend API)            │
│  • Sert fichiers HTML    │      │  • API REST Endpoints:             │
│  • CSS/JavaScript        │      │    - GET /api (données principales)│
│  • Proxy API → Backend   │      │    - GET /api/health (health check)│
│  • Port interne: 80      │      │    - GET /metrics (Prometheus)     │
│                          │      │  • Serveur: Gunicorn (2 workers)   │
│  Routes:                 │      │  • Port interne: 5000              │
│  / → index.html          │      └─────┬──────────────────┬───────────┘
│  /api → backend:5000     │            │                  │
└──────────────────────────┘            │                  │
                                        │                  │
                        ┌───────────────┴──────┐           │
                        ▼                      ▼           │
              ┌──────────────────┐   ┌──────────────────┐ │
              │  🐘 PostgreSQL   │   │   🔴 Redis       │ │
              │                  │   │                  │ │
              │  • Base données  │   │  • Cache mémoire │ │
              │    relationnelle │   │  • Compteur hits │ │
              │  • Table: visits │   │  • Key-value     │ │
              │  • Port: 5432    │   │  • Port: 6379    │ │
              │  • User: appuser │   │                  │ │
              │  • DB: appdb     │   │                  │ │
              └──────────────────┘   └──────────────────┘ │
                                                           │
                        ┌──────────────────────────────────┘
                        │ Exposition /metrics
                        ▼
              ┌─────────────────────────────────────────────┐
              │     📊 PROMETHEUS (Collecte métriques)      │
              │  • Scrape /metrics toutes les 15 secondes   │
              │  • Stockage time-series des métriques       │
              │  • Targets: backend, prometheus             │
              │  • Port: 9090                               │
              │  • Retention: configurable                  │
              └────────────────┬────────────────────────────┘
                               │ API Query
                               ▼
              ┌─────────────────────────────────────────────┐
              │      📈 GRAFANA (Visualisation)             │
              │  • Dashboards interactifs                   │
              │  • Datasource: Prometheus (pré-configuré)   │
              │  • Credentials: admin/admin                 │
              │  • Port: 3000                               │
              │  • Provisioning automatique                 │
              └─────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│                   🔗 RÉSEAU DOCKER: app-network                      │
│          Tous les services communiquent via ce bridge network        │
└─────────────────────────────────────────────────────────────────────┘

🔧 Services et leurs rôles

1. Traefik - Reverse Proxy & Load Balancer

Image: traefik:v2.10
Rôle: Point d'entrée unique pour toutes les requêtes HTTP

Fonctionnalités:

  • Routage basé sur les règles (Host, PathPrefix)
  • Service discovery automatique via Docker labels
  • Dashboard de monitoring accessible
  • Configuration centralisée

Configuration clé:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.frontend.rule=Host(`localhost`)"
  - "traefik.http.routers.backend.rule=Host(`localhost`) && PathPrefix(`/api`)"

Ports exposés:

  • 80: Trafic HTTP
  • 8080: Dashboard Traefik

2. Nginx - Serveur Web Frontend

Image: nginx:alpine
Rôle: Servir les fichiers statiques et proxifier les appels API

Fonctionnalités:

  • Hébergement de l'interface utilisateur (HTML/CSS/JS)
  • Proxy pass vers le backend Flask
  • Configuration légère avec Alpine Linux

Configuration Nginx:

location / {
    try_files $uri $uri/ =404;
}

location /api {
    proxy_pass http://backend:5000/api;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

3. Flask Backend - API REST

Build: Custom Dockerfile
Rôle: Logique métier et API REST

Technologies:

  • Flask 2.3.2 (framework web)
  • Gunicorn 20.1.0 (serveur WSGI production)
  • psycopg2-binary 2.9.7 (driver PostgreSQL)
  • redis 4.5.5 (client Redis)
  • prometheus-client 0.16.0 (exposition métriques)

Endpoints exposés:

GET /api              # Données principales (DB time + compteur Redis)
GET /api/health       # Health check pour monitoring
GET /metrics          # Métriques Prometheus

Variables d'environnement:

DATABASE_URL: postgresql://appuser:apppassword@postgres:5432/appdb
REDIS_HOST: redis
REDIS_PORT: 6379

Dockerfile:

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "2", "app:app"]

4. PostgreSQL - Base de données relationnelle

Image: postgres:15-alpine
Rôle: Stockage persistant des données

Configuration:

  • Database: appdb
  • User: appuser
  • Password: apppassword

Initialisation:

CREATE TABLE IF NOT EXISTS visits (
  id serial primary key,
  ts timestamptz default now()
);

Health Check:

test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
interval: 10s
timeout: 5s
retries: 5

5. Redis - Cache en mémoire

Image: redis:7-alpine
Rôle: Cache rapide et compteur de requêtes

Utilisation:

  • Clé hits: Compteur incrémental du nombre de requêtes
  • Performances optimales pour données temporaires
  • Persistance optionnelle

Health Check:

test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5

6. Prometheus - Collecte de métriques

Image: prom/prometheus:latest
Rôle: Scraping et stockage des métriques

Configuration (prometheus.yml):

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'backend'
    metrics_path: /metrics
    static_configs:
      - targets: ['backend:5000']

Métriques collectées:

  • Requêtes HTTP totales (app_requests_total)
  • Métriques Python (GC, mémoire)
  • Métriques Gunicorn (workers)

7. Grafana - Visualisation

Image: grafana/grafana:latest
Rôle: Tableaux de bord et visualisation des métriques

Configuration:

  • Admin: admin / admin
  • Datasource Prometheus pré-configuré
  • Provisioning automatique des dashboards

Provisioning:

datasources:
  - name: Prometheus
    type: prometheus
    url: http://prometheus:9090
    isDefault: true

✅ Travail réalisé

1. Création du Dockerfile Backend

Fichier: backend/Dockerfile

Objectifs atteints:

  • ✅ Utilisation d'une image Python légère (python:3.11-slim)
  • ✅ Installation des dépendances via requirements.txt
  • ✅ Configuration de Gunicorn pour la production (2 workers)
  • ✅ Exposition du port 5000
  • ✅ Optimisation du build avec layer caching

Points techniques:

  • --no-cache-dir pour réduire la taille de l'image
  • Copie séparée de requirements.txt pour le cache Docker
  • Workers multiples pour gérer les requêtes concurrentes

2. Configuration Docker Compose

Fichier: docker-compose.yml

Objectifs atteints:

  • ✅ Orchestration de 7 services interconnectés
  • ✅ Réseau bridge isolé (app-network)
  • ✅ Volumes persistants pour les données
  • ✅ Health checks pour tous les services critiques
  • ✅ Dépendances respectées (depends_on avec conditions)
  • ✅ Labels Traefik pour le routage automatique
  • ✅ Variables d'environnement sécurisées

Services configurés:

  1. postgres - Base de données avec init script
  2. redis - Cache avec health check
  3. backend - Build custom avec variables d'environnement
  4. frontend - Nginx avec volumes de configuration
  5. traefik - Reverse proxy avec Docker provider
  6. prometheus - Monitoring avec configuration custom
  7. grafana - Dashboards avec provisioning automatique

Réseau et volumes:

networks:
  app-network:
    driver: bridge

volumes:
  postgres_data:    # Persistance base de données
  prometheus_data:  # Historique des métriques
  grafana_data:     # Configuration dashboards

3. Correction de la configuration Nginx

Fichier: frontend/nginx.conf

Problème identifié:

  • Nginx proxy vers /api/ avec trailing slash
  • Causait une redirection 301 et échec des requêtes

Solution appliquée:

# Avant (❌)
location /api/ {
    proxy_pass http://backend:5000/api/;
}

# Après (✅)
location /api {
    proxy_pass http://backend:5000/api;
}

⚙️ Fonctionnement détaillé

Flux d'une requête utilisateur

1. Accès à la page d'accueil (http://localhost/)

User → Traefik:80 
     → [Router: Host(localhost)]
     → Nginx:80
     → Fichier: /usr/share/nginx/html/index.html
     → Response: HTML + JavaScript

2. Appel API depuis le frontend (fetch('/api'))

Browser → Traefik:80
        → [Router: Host(localhost) && PathPrefix(/api)]
        → Flask:5000/api
        → Backend traite la requête:
           ├─ Connexion PostgreSQL → SELECT NOW()
           ├─ Connexion Redis → INCR hits
           ├─ Counter Prometheus → app_requests_total++
           └─ Response JSON: {message, db_time, hits}
        → Traefik
        → Browser

3. Collecte des métriques (Prometheus scrape)

Prometheus → Backend:5000/metrics (toutes les 15s)
          → Parse métriques format Prometheus
          → Stockage time-series
          → Disponible pour Grafana

4. Visualisation (Dashboard Grafana)

User → Grafana:3000
     → Datasource: Prometheus:9090
     → Query: rate(app_requests_total[5m])
     → Render: Graphique temps réel

Communication inter-conteneurs

Tous les services communiquent via le réseau Docker app-network en utilisant les noms de services comme hostnames:

backend:
  environment:
    DATABASE_URL: postgresql://appuser:apppassword@postgres:5432/appdb
    # 'postgres' est résolu par le DNS Docker
    REDIS_HOST: redis
    # 'redis' est résolu par le DNS Docker

Résolution DNS interne:

  • postgres → IP du conteneur PostgreSQL
  • redis → IP du conteneur Redis
  • backend → IP du conteneur Flask
  • prometheus → IP du conteneur Prometheus

Gestion des dépendances de démarrage

backend:
  depends_on:
    postgres:
      condition: service_healthy  # Attend que PostgreSQL soit prêt
    redis:
      condition: service_healthy  # Attend que Redis soit prêt

Ordre de démarrage:

  1. postgres + redis (en parallèle)
  2. Attente health checks (max 5 retries × 10s)
  3. backend démarre
  4. frontend, prometheus, grafana démarrent

Health Checks implémentés

PostgreSQL

test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
interval: 10s  # Vérifie toutes les 10 secondes
timeout: 5s    # Timeout si pas de réponse en 5s
retries: 5     # 5 tentatives avant de marquer unhealthy

Redis

test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5

Backend Flask

test: ["CMD", "curl", "-f", "http://localhost:5000/api/health"]
interval: 30s
timeout: 10s
retries: 3

Note: Le healthcheck backend échoue car curl n'est pas installé dans l'image Python slim, mais l'API fonctionne correctement.


Gestion des volumes persistants

volumes:
  postgres_data:/var/lib/postgresql/data
    # Persiste les tables et données PostgreSQL
    
  prometheus_data:/prometheus
    # Garde l'historique des métriques collectées
    
  grafana_data:/var/lib/grafana
    # Sauvegarde les dashboards et configurations

Avantages:

  • Données conservées après docker-compose down
  • Reconstruction rapide sans perte de données
  • Séparation données / configuration

🚀 Déploiement et tests

Commandes de déploiement

# Cloner le repository
git clone https://github.com/ENIT-TIC/lab-05-info1-malek0501.git
cd lab-05-info1-malek0501

# Démarrer tous les services
docker-compose up -d

# Vérifier l'état des services
docker-compose ps

# Voir les logs en temps réel
docker-compose logs -f

# Logs d'un service spécifique
docker-compose logs -f backend

# Arrêter tous les services
docker-compose down

# Arrêter et supprimer les volumes (reset complet)
docker-compose down -v

# Rebuild après modification du code
docker-compose up -d --build

Tests fonctionnels réalisés

✅ Test 1: API Backend

curl http://localhost/api
# Response:
# {
#   "message": "Hello from backend",
#   "db_time": "2025-10-24T08:25:41.446031+00:00",
#   "hits": 1
# }

✅ Test 2: Compteur Redis (incrémentation)

# Première requête
curl http://localhost/api  # hits: 1

# Deuxième requête
curl http://localhost/api  # hits: 2

# Troisième requête
curl http://localhost/api  # hits: 3

# Vérification directe dans Redis
docker exec redis_cache redis-cli GET hits
# Output: "3"

✅ Test 3: Connexion PostgreSQL

# Test depuis le conteneur
docker exec postgres_db psql -U appuser -d appdb -c "SELECT NOW();"
# Output: timestamp actuel

# Vérification table visits
docker exec postgres_db psql -U appuser -d appdb -c "SELECT * FROM visits;"
# Output: table créée (vide pour l'instant)

✅ Test 4: Health Check

curl http://localhost/api/health
# Response: {"status":"ok"}

✅ Test 5: Métriques Prometheus

# Vérification que Prometheus scrape le backend
curl http://localhost:9090/api/v1/targets
# Backend target: health="up", lastScrape="2025-10-24T..."

✅ Test 6: Frontend

curl http://localhost/
# Response: HTML page avec JavaScript qui fetch /api

✅ Test 7: Dashboard Traefik

# Accès via navigateur
http://localhost:8080
# Voir tous les routers et services configurés

✅ Test 8: Grafana

curl http://localhost:3000/api/health
# Response: {"database":"ok","version":"12.2.1"}

Résultats des tests

Test Endpoint Status Résultat
API principale GET /api JSON avec db_time et hits
Health check GET /api/health {"status":"ok"}
Compteur Redis Redis GET hits Incrémente à chaque requête
PostgreSQL Connection test Timestamp récupéré
Frontend GET / HTML servi correctement
Prometheus scrape Target backend health="up"
Grafana API Health endpoint Database OK
Traefik routing Dashboard Tous routers actifs

🌐 URLs d'accès

Service URL Description Credentials
Application http://localhost Interface utilisateur principale -
API Backend http://localhost/api Endpoint REST principal -
Health Check http://localhost/api/health Vérification statut backend -
Traefik Dashboard http://localhost:8080 Interface de gestion Traefik -
Prometheus http://localhost:9090 Interface de requêtes métriques -
Grafana http://localhost:3000 Dashboards de visualisation admin / admin

📊 Métriques disponibles

Métriques exposées par le backend (/metrics)

# Compteur de requêtes HTTP
app_requests_total{} 42

# Métriques Python
python_gc_collections_total{generation="0"} 109
python_info{implementation="CPython",major="3",minor="11"} 1.0

# Métriques processus
process_virtual_memory_bytes 125640704
process_cpu_seconds_total 1.23

# Métriques Gunicorn (workers)
gunicorn_workers{state="busy"} 1
gunicorn_workers{state="idle"} 1

Queries Prometheus utiles

# Taux de requêtes par seconde
rate(app_requests_total[5m])

# Nombre total de requêtes
app_requests_total

# Utilisation mémoire du backend
process_virtual_memory_bytes

# Nombre de collections garbage collector
rate(python_gc_collections_total[1m])

🔐 Sécurité et bonnes pratiques

Points de sécurité implémentés

  1. Réseau isolé: Tous les services sur un bridge network privé
  2. Pas d'exposition directe: Seul Traefik expose des ports publics
  3. Health checks: Validation de l'état des services critiques
  4. Variables d'environnement: Configuration centralisée
  5. Images officielles: Utilisation d'images Docker verified

Améliorations possibles

  • Ajouter HTTPS avec Let's Encrypt sur Traefik
  • Utiliser Docker Secrets pour les mots de passe
  • Implémenter rate limiting sur Traefik
  • Ajouter authentification sur Grafana/Prometheus
  • Configurer firewall rules pour les conteneurs
  • Mettre en place logging centralisé (ELK stack)

🐛 Troubleshooting

Backend marqué "unhealthy"

Cause: Healthcheck utilise curl qui n'est pas dans l'image Python slim
Solution: L'API fonctionne normalement, peut être ignoré ou installer curl dans le Dockerfile

Erreur "connection refused" PostgreSQL

Cause: Backend démarre avant que PostgreSQL soit prêt
Solution: Déjà implémenté avec depends_on et health checks

Redis "Could not connect"

Cause: Service Redis pas démarré
Solution: Vérifier avec docker-compose ps redis

Traefik ne route pas correctement

Cause: Labels Docker mal configurés
Solution: Vérifier les labels dans docker-compose.yml et redémarrer Traefik


📚 Technologies utilisées

Technologie Version Rôle
Docker Compose 3.8 Orchestration
Traefik 2.10 Reverse proxy
Nginx Alpine Serveur web
Python 3.11-slim Runtime backend
Flask 2.3.2 Framework web
Gunicorn 20.1.0 Serveur WSGI
PostgreSQL 15-alpine Base de données
Redis 7-alpine Cache
Prometheus Latest Monitoring
Grafana Latest Visualisation

📝 Conclusion

Ce projet démontre une architecture microservices complète et professionnelle avec:

  • ✅ Séparation des responsabilités (frontend/backend/data/monitoring)
  • ✅ Communication sécurisée inter-conteneurs
  • ✅ Monitoring et observabilité en temps réel
  • ✅ Scalabilité horizontale possible
  • ✅ Infrastructure as Code (Docker Compose)
  • ✅ Bonnes pratiques DevOps

L'architecture est prête pour un déploiement en production avec quelques ajustements de sécurité supplémentaires.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •