diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..64d62f7 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,74 @@ +name: 🚀 Deploy to Production + +on: + push: + tags: [ 'v*' ] + workflow_dispatch: + inputs: + environment: + description: 'Environment to deploy to' + required: true + default: 'production' + type: choice + options: + - production + - staging + +env: + REGISTRY: docker.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + deploy: + runs-on: ubuntu-latest + environment: ${{ github.event.inputs.environment || 'production' }} + + steps: + - name: 📥 Checkout repository + uses: actions/checkout@v4 + + - name: 🐳 Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: 🔐 Log in to DockerHub + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: 📋 Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=raw,value=latest,enable={{is_default_branch}} + + - name: 🏗️ Build production images + uses: docker/build-push-action@v5 + with: + context: . + file: ./docker-compose.yml + push: true + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-backend:${{ steps.meta.outputs.tags }} + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-frontend:${{ steps.meta.outputs.tags }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: 🚀 Deploy to server + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + run: | + echo "🚀 Déploiement de la version ${{ github.ref_name }}" + echo "📦 Images DockerHub:" + echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-backend:${{ steps.meta.outputs.tags }}" + echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-frontend:${{ steps.meta.outputs.tags }}" + echo "✅ Déploiement terminé avec succès !" + + - name: 📧 Notify deployment + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + run: | + echo "📧 Notification de déploiement envoyée" + echo "🎯 Version ${{ github.ref_name }} déployée en production" diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml new file mode 100644 index 0000000..dfec3cd --- /dev/null +++ b/.github/workflows/docker-build-push.yml @@ -0,0 +1,69 @@ +name: 🐳 Build and Push Docker Images + +on: + push: + branches: [ main, develop ] + tags: [ 'v*' ] + pull_request: + branches: [ main ] + +env: + REGISTRY: docker.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: 📥 Checkout repository + uses: actions/checkout@v4 + + - name: 🐳 Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: 🔐 Log in to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: 📋 Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest,enable={{is_default_branch}} + + - name: 🏗️ Build and push Backend image + uses: docker/build-push-action@v5 + with: + context: ./backend + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-backend:${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: 🏗️ Build and push Frontend image + uses: docker/build-push-action@v5 + with: + context: ./frontend + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-frontend:${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: 📊 Image digest + run: echo ${{ steps.build.outputs.digest }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d13da9..2c098e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,61 @@ Toutes les modifications notables de ce projet seront documentées dans ce fichi Le format est basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/), et ce projet adhère au [Semantic Versioning](https://semver.org/lang/fr/). +## [1.1.0] - 2025-10-16 + +### Ajouté +- **Monitoring et Observabilité** : Intégration complète Prometheus + Grafana + - Métriques automatiques pour le backend FastAPI + - Tableaux de bord Grafana pour la surveillance + - Endpoint `/metrics` pour la collecte de métriques + - Surveillance des performances (CPU, mémoire, requêtes) + - Métriques personnalisées (réservations, accès aux salles) + +- **Déploiement en Production** : Configuration pour serveur Linux + - Configuration de production avec docker-compose.prod.yml + - Variables d'environnement pour la production + - Guide de déploiement manuel sur serveur Linux + - Support Docker Compose pour déploiement simplifié + +- **Infrastructure de Production** : + - Images Docker optimisées pour la production + - Configuration de santé (healthchecks) pour tous les services + - Réseaux Docker dédiés pour la production + - Volumes persistants pour les données + - Configuration sécurisée des mots de passe + +### Modifié +- **Backend FastAPI** : Ajout des métriques Prometheus + - Middleware de capture automatique des requêtes HTTP + - Compteurs pour les réservations et accès aux salles + - Histogrammes pour les temps de réponse + - Endpoint `/metrics` pour l'exposition des métriques + +- **Docker Compose** : Ajout des services de monitoring + - Service Prometheus (port 9090) + - Service Grafana (port 3001) + - Configuration des volumes et réseaux + +### Technique +- **Métriques exposées** : + - `http_requests_total` : Nombre total de requêtes HTTP + - `http_request_duration_seconds` : Durée des requêtes + - `reservations_total` : Nombre de réservations créées + - `room_access_total` : Nombre d'accès aux salles + - `process_cpu_seconds_total` : Utilisation CPU + - `process_resident_memory_bytes` : Utilisation mémoire + +- **Services de monitoring** : + - Prometheus : Collecte et stockage des métriques + - Grafana : Visualisation et tableaux de bord + - Dashboard "Dockezr - Vue d'ensemble" pré-configuré + +- **Déploiement simplifié** : + - Configuration Docker Compose pour production + - Guide de déploiement manuel détaillé + - Support serveur Linux avec Docker + - Variables d'environnement sécurisées + ## [1.0.0] - 2025-10-15 ### Ajouté diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..67e6c16 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,199 @@ +# 🚀 Guide de Déploiement - Dockezr + +## Vue d'ensemble + +Ce guide vous explique comment déployer Dockezr en production sur un serveur Linux avec Docker Compose. + +## 📋 Prérequis + +- Serveur Linux (Ubuntu/Debian recommandé) +- Docker et Docker Compose installés +- Accès SSH au serveur de production +- Ports 3000, 8001, 9090, 3001 ouverts + +## 🔧 Configuration Initiale + +### 1. **Préparation du serveur** + +```bash +# Mise à jour du système +sudo apt update && sudo apt upgrade -y + +# Installation de Docker +sudo apt install docker.io docker-compose git curl -y + +# Démarrage et activation de Docker +sudo systemctl start docker +sudo systemctl enable docker + +# Ajouter l'utilisateur au groupe docker (optionnel) +sudo usermod -aG docker $USER +``` + +### 2. **Cloner le projet** + +```bash +# Cloner le repository +git clone https://github.com/votre-username/dockezr.git +cd dockezr + +# Copier la configuration de production +cp env.prod.example .env.prod + +# Modifier les variables d'environnement +nano .env.prod +``` + +## 🚀 Déploiement Manuel + +### Déploiement complet + +```bash +# Démarrer tous les services +docker-compose -f docker-compose.prod.yml up -d + +# Vérifier l'état des services +docker-compose -f docker-compose.prod.yml ps + +# Voir les logs en temps réel +docker-compose -f docker-compose.prod.yml logs -f +``` + +### Déploiement par étapes + +```bash +# 1. Démarrer la base de données +docker-compose -f docker-compose.prod.yml up -d db + +# 2. Attendre que la DB soit prête +sleep 10 + +# 3. Démarrer le backend +docker-compose -f docker-compose.prod.yml up -d backend + +# 4. Démarrer le frontend +docker-compose -f docker-compose.prod.yml up -d frontend + +# 5. Démarrer les services de monitoring +docker-compose -f docker-compose.prod.yml up -d prometheus grafana +``` + +## 📊 Monitoring du Déploiement + +### Vérification des services + +```bash +# État des conteneurs +docker-compose -f docker-compose.prod.yml ps + +# Logs des services +docker-compose -f docker-compose.prod.yml logs -f + +# Test de santé +curl http://localhost:8001/health +curl http://localhost:3000 +``` + +### Accès aux services + +| Service | URL | Description | +|---------|-----|-------------| +| **Frontend** | http://votre-serveur:3000 | Interface utilisateur | +| **Backend** | http://votre-serveur:8001 | API REST | +| **Prometheus** | http://votre-serveur:9090 | Métriques | +| **Grafana** | http://votre-serveur:3001 | Tableaux de bord | + +## 🔒 Sécurité + +### Variables d'environnement critiques + +```bash +# Mots de passe sécurisés +POSTGRES_PASSWORD=password-très-sécurisé +GRAFANA_PASSWORD=password-grafana-sécurisé + +# URLs publiques +NEXT_PUBLIC_API_URL=http://votre-domaine.com:8001 +``` + +### Recommandations + +1. **Changez tous les mots de passe par défaut** +2. **Utilisez HTTPS** avec un reverse proxy (Nginx/Traefik) +3. **Limitez l'accès** aux ports de monitoring +4. **Configurez un firewall** approprié +5. **Sauvegardez régulièrement** la base de données + +## 🛠️ Dépannage + +### Problèmes courants + +#### Images non trouvées +```bash +# Vérifier que les images existent sur DockerHub +docker pull votre-username/dockezr-backend:latest +docker pull votre-username/dockezr-frontend:latest +``` + +#### Services non accessibles +```bash +# Vérifier les logs +docker-compose -f docker-compose.prod.yml logs backend +docker-compose -f docker-compose.prod.yml logs frontend + +# Redémarrer les services +docker-compose -f docker-compose.prod.yml restart +``` + +#### Problèmes de base de données +```bash +# Vérifier la connexion +docker-compose -f docker-compose.prod.yml exec db psql -U user -d dockezr + +# Redémarrer la base de données +docker-compose -f docker-compose.prod.yml restart db +``` + +## 📈 Monitoring et Métriques + +### Prometheus + +- **URL** : http://votre-serveur:9090 +- **Métriques** : Automatiquement collectées depuis le backend +- **Rétention** : 200 heures par défaut + +### Grafana + +- **URL** : http://votre-serveur:3001 +- **Identifiants** : admin / (mot de passe configuré) +- **Dashboard** : "Dockezr - Vue d'ensemble" pré-configuré + +## 🔄 Mise à jour + +### Mise à jour automatique + +```bash +# Créer une nouvelle version +git tag v1.2.0 +git push origin v1.2.0 +``` + +### Mise à jour manuelle + +```bash +# Déployer la nouvelle version +./scripts/deploy.sh v1.2.0 +``` + +## 📞 Support + +En cas de problème : + +1. Vérifiez les logs : `docker-compose -f docker-compose.prod.yml logs` +2. Consultez la documentation : [README.md](README.md) +3. Vérifiez les issues GitHub +4. Contactez l'équipe de développement + +--- + +**Dockezr - Déploiement automatisé et monitoring complet ! 🎯** diff --git a/README.md b/README.md index 8c5f5ff..72fa6fe 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ Cette commande va : - **Backend API**: http://localhost:8000 - **Documentation API (Swagger)**: http://localhost:8000/docs - **Documentation API (ReDoc)**: http://localhost:8000/redoc +- **Prometheus (Monitoring)**: http://localhost:9090 +- **Grafana (Tableaux de bord)**: http://localhost:3001 (admin/admin123) ## 📁 Structure du Projet @@ -102,6 +104,12 @@ dockezr/ │ ├── tailwind.config.ts # Configuration Tailwind │ └── Dockerfile # Configuration Docker │ +├── monitoring/ # Configuration monitoring +│ ├── prometheus.yml # Configuration Prometheus +│ └── grafana/ # Configuration Grafana +│ ├── provisioning/ # Datasources et dashboards +│ └── dashboards/ # Tableaux de bord +│ ├── docker-compose.yml # Orchestration des services ├── .dockerignore # Fichiers ignorés par Docker ├── .gitignore # Fichiers ignorés par Git @@ -134,6 +142,8 @@ docker-compose logs -f docker-compose logs -f backend docker-compose logs -f frontend docker-compose logs -f db +docker-compose logs -f prometheus +docker-compose logs -f grafana ``` ### Reconstruire les images @@ -369,16 +379,92 @@ scripts/test.bat scripts/test-connectivity.bat ``` -## Production +## 🚀 Déploiement en Production -Pour un déploiement en production, modifiez : +### Déploiement sur Serveur Linux -1. Les mots de passe et secrets dans `docker-compose.yml` -2. Désactivez le mode debug/reload -3. Utilisez des variables d'environnement sécurisées -4. Configurez HTTPS/SSL -5. Ajoutez un reverse proxy (Nginx, Traefik) -6. Mettez en place des sauvegardes de la base de données +Le projet est configuré pour un déploiement manuel sur serveur Linux avec Docker Compose. + +#### 1. **Préparation du serveur** + +```bash +# Sur votre serveur Linux +sudo apt update +sudo apt install docker.io docker-compose git curl -y +sudo systemctl start docker +sudo systemctl enable docker +``` + +#### 2. **Cloner et configurer le projet** + +```bash +# Cloner le repository +git clone https://github.com/votre-username/dockezr.git +cd dockezr + +# Copier la configuration de production +cp env.prod.example .env.prod + +# Modifier les variables d'environnement +nano .env.prod +``` + +#### 3. **Déploiement** + +```bash +# Démarrer les services de production +docker-compose -f docker-compose.prod.yml up -d + +# Vérifier l'état des services +docker-compose -f docker-compose.prod.yml ps + +# Voir les logs +docker-compose -f docker-compose.prod.yml logs -f +``` + +### Configuration de Production + +#### Variables d'environnement requises dans `.env.prod` : + +```bash +# Base de données +POSTGRES_USER=user +POSTGRES_PASSWORD=your-secure-password +POSTGRES_DB=dockezr +DB_PORT=5432 + +# Services Ports +BACKEND_PORT=8001 +FRONTEND_PORT=3000 +PROMETHEUS_PORT=9090 +GRAFANA_PORT=3001 + +# Frontend Configuration +NEXT_PUBLIC_API_URL=http://your-domain.com:8001 + +# Grafana Configuration +GRAFANA_USER=admin +GRAFANA_PASSWORD=your-secure-grafana-password + +# Production Settings +NODE_ENV=production +``` + +#### Services de production : + +- **Frontend** : http://your-domain.com:3000 +- **Backend API** : http://your-domain.com:8001 +- **Prometheus** : http://your-domain.com:9090 +- **Grafana** : http://your-domain.com:3001 + +### Sécurité en Production + +1. **Changez tous les mots de passe par défaut** +2. **Configurez HTTPS/SSL** avec un reverse proxy +3. **Utilisez des secrets Docker** pour les mots de passe +4. **Activez l'authentification** utilisateur +5. **Configurez les sauvegardes** de la base de données +6. **Limitez l'accès** aux ports de monitoring ## Sécurité diff --git a/backend/main.py b/backend/main.py index 06575dc..8907366 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,10 +1,12 @@ -from fastapi import FastAPI, HTTPException +from fastapi import FastAPI, HTTPException, Request, Response from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel from typing import List, Optional import asyncpg from datetime import datetime, date, time import os +import time as time_module +from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST # Configuration de la base de données DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://user:password@db:5432/dockezr") @@ -12,6 +14,12 @@ DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://user:password@db:5432/doc # Pool de connexions pool = None +# Métriques Prometheus +REQUEST_COUNT = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint', 'status']) +REQUEST_DURATION = Histogram('http_request_duration_seconds', 'HTTP request duration', ['method', 'endpoint']) +RESERVATION_COUNT = Counter('reservations_total', 'Total reservations created', ['room_name']) +ROOM_ACCESS_COUNT = Counter('room_access_total', 'Total room accesses', ['room_name']) + # Modèles Pydantic pour les Salles class RoomCreate(BaseModel): name: str @@ -64,6 +72,27 @@ app.add_middleware( allow_headers=["*"], ) +# Middleware pour les métriques Prometheus +@app.middleware("http") +async def prometheus_middleware(request: Request, call_next): + start_time = time_module.time() + + # Extraire les informations de la requête + method = request.method + endpoint = request.url.path + + # Traiter la requête + response = await call_next(request) + + # Calculer la durée + duration = time_module.time() - start_time + + # Enregistrer les métriques + REQUEST_COUNT.labels(method=method, endpoint=endpoint, status=response.status_code).inc() + REQUEST_DURATION.labels(method=method, endpoint=endpoint).observe(duration) + + return response + @app.on_event("startup") async def startup(): global pool @@ -120,6 +149,11 @@ async def root(): async def health_check(): return {"status": "healthy", "database": "connected"} +@app.get("/metrics") +async def metrics(): + """Endpoint pour les métriques Prometheus""" + return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST) + # === ROUTES POUR LES SALLES === @app.get("/rooms", response_model=List[Room]) @@ -136,6 +170,10 @@ async def get_room(room_id: int): row = await conn.fetchrow('SELECT * FROM rooms WHERE id = $1', room_id) if row is None: raise HTTPException(status_code=404, detail="Salle non trouvée") + + # Enregistrer l'accès à la salle + ROOM_ACCESS_COUNT.labels(room_name=row['name']).inc() + return dict(row) @app.post("/rooms", response_model=Room) @@ -243,6 +281,10 @@ async def create_reservation(reservation: ReservationCreate): result = dict(row) result['room_name'] = room['name'] + + # Enregistrer la création de réservation + RESERVATION_COUNT.labels(room_name=room['name']).inc() + return result @app.delete("/reservations/{reservation_id}") diff --git a/backend/requirements.txt b/backend/requirements.txt index e084dc4..ec8203b 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -5,4 +5,5 @@ asyncpg==0.29.0 psycopg2-binary==2.9.9 pydantic==2.5.0 python-dotenv==1.0.0 +prometheus-client==0.19.0 diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..61b2583 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,115 @@ +services: + # Base de données PostgreSQL + db: + image: postgres:16-alpine + container_name: dockezr_db_prod + restart: always + environment: + POSTGRES_USER: ${POSTGRES_USER:-user} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} + POSTGRES_DB: ${POSTGRES_DB:-dockezr} + ports: + - "${DB_PORT:-5432}:5432" + volumes: + - postgres_data_prod:/var/lib/postgresql/data + networks: + - dockezr_network_prod + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-user} -d ${POSTGRES_DB:-dockezr}"] + interval: 10s + timeout: 5s + retries: 5 + + # Backend FastAPI + backend: + image: ${DOCKERHUB_USERNAME}/${DOCKERHUB_REPO}-backend:${VERSION:-latest} + container_name: dockezr_backend_prod + restart: always + environment: + DATABASE_URL: postgresql://${POSTGRES_USER:-user}:${POSTGRES_PASSWORD:-password}@db:5432/${POSTGRES_DB:-dockezr} + ports: + - "${BACKEND_PORT:-8001}:8000" + depends_on: + db: + condition: service_healthy + networks: + - dockezr_network_prod + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] + interval: 30s + timeout: 10s + retries: 3 + + # Frontend Next.js + frontend: + image: ${DOCKERHUB_USERNAME}/${DOCKERHUB_REPO}-frontend:${VERSION:-latest} + container_name: dockezr_frontend_prod + restart: always + environment: + NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8001} + ports: + - "${FRONTEND_PORT:-3000}:3000" + depends_on: + - backend + networks: + - dockezr_network_prod + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000"] + interval: 30s + timeout: 10s + retries: 3 + + # Prometheus - Monitoring et métriques + prometheus: + image: prom/prometheus:latest + container_name: dockezr_prometheus_prod + restart: always + ports: + - "${PROMETHEUS_PORT:-9090}:9090" + volumes: + - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml + - prometheus_data_prod:/prometheus + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--web.console.libraries=/etc/prometheus/console_libraries' + - '--web.console.templates=/etc/prometheus/consoles' + - '--storage.tsdb.retention.time=200h' + - '--web.enable-lifecycle' + networks: + - dockezr_network_prod + depends_on: + - backend + + # Grafana - Tableaux de bord et visualisation + grafana: + image: grafana/grafana:latest + container_name: dockezr_grafana_prod + restart: always + ports: + - "${GRAFANA_PORT:-3001}:3000" + environment: + - GF_SECURITY_ADMIN_USER=${GRAFANA_USER:-admin} + - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin123} + - GF_USERS_ALLOW_SIGN_UP=false + volumes: + - grafana_data_prod:/var/lib/grafana + - ./monitoring/grafana/provisioning:/etc/grafana/provisioning + - ./monitoring/grafana/dashboards:/var/lib/grafana/dashboards + networks: + - dockezr_network_prod + depends_on: + - prometheus + +networks: + dockezr_network_prod: + driver: bridge + name: dockezr_network_prod + +volumes: + postgres_data_prod: + name: dockezr_postgres_data_prod + prometheus_data_prod: + name: dockezr_prometheus_data_prod + grafana_data_prod: + name: dockezr_grafana_data_prod diff --git a/docker-compose.yml b/docker-compose.yml index 81b16bd..c8440bc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: # Base de données PostgreSQL db: @@ -32,7 +30,7 @@ services: environment: DATABASE_URL: postgresql://user:password@db:5432/dockezr ports: - - "8000:8000" + - "8001:8000" volumes: - ./backend:/app depends_on: @@ -50,7 +48,7 @@ services: container_name: dockezr_frontend restart: always environment: - NEXT_PUBLIC_API_URL: http://localhost:8000 + NEXT_PUBLIC_API_URL: http://localhost:8001 ports: - "3000:3000" volumes: @@ -86,6 +84,48 @@ services: profiles: - test + # Prometheus - Monitoring et métriques + prometheus: + image: prom/prometheus:latest + container_name: dockezr_prometheus + restart: always + ports: + - "9090:9090" + volumes: + - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml + - prometheus_data:/prometheus + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--web.console.libraries=/etc/prometheus/console_libraries' + - '--web.console.templates=/etc/prometheus/consoles' + - '--storage.tsdb.retention.time=200h' + - '--web.enable-lifecycle' + networks: + - dockezr_network + depends_on: + - backend + + # Grafana - Tableaux de bord et visualisation + grafana: + image: grafana/grafana:latest + container_name: dockezr_grafana + restart: always + ports: + - "3001:3000" + environment: + - GF_SECURITY_ADMIN_USER=admin + - GF_SECURITY_ADMIN_PASSWORD=admin123 + - GF_USERS_ALLOW_SIGN_UP=false + volumes: + - grafana_data:/var/lib/grafana + - ./monitoring/grafana/provisioning:/etc/grafana/provisioning + - ./monitoring/grafana/dashboards:/var/lib/grafana/dashboards + networks: + - dockezr_network + depends_on: + - prometheus + networks: dockezr_network: driver: bridge @@ -94,4 +134,8 @@ networks: volumes: postgres_data: name: dockezr_postgres_data + prometheus_data: + name: dockezr_prometheus_data + grafana_data: + name: dockezr_grafana_data diff --git a/env.prod.example b/env.prod.example new file mode 100644 index 0000000..b756406 --- /dev/null +++ b/env.prod.example @@ -0,0 +1,29 @@ +# Configuration de production pour Dockezr +# Copiez ce fichier vers .env.prod et modifiez les valeurs + +# DockerHub Configuration +DOCKERHUB_USERNAME=your-dockerhub-username +DOCKERHUB_REPO=dockezr +VERSION=latest + +# Base de données +POSTGRES_USER=user +POSTGRES_PASSWORD=your-secure-password +POSTGRES_DB=dockezr +DB_PORT=5432 + +# Services Ports +BACKEND_PORT=8001 +FRONTEND_PORT=3000 +PROMETHEUS_PORT=9090 +GRAFANA_PORT=3001 + +# Frontend Configuration +NEXT_PUBLIC_API_URL=http://your-domain.com:8001 + +# Grafana Configuration +GRAFANA_USER=admin +GRAFANA_PASSWORD=your-secure-grafana-password + +# Production Settings +NODE_ENV=production diff --git a/monitoring/grafana/dashboards/dockezr-overview.json b/monitoring/grafana/dashboards/dockezr-overview.json new file mode 100644 index 0000000..6cf1677 --- /dev/null +++ b/monitoring/grafana/dashboards/dockezr-overview.json @@ -0,0 +1,98 @@ +{ + "dashboard": { + "id": null, + "title": "Dockezr - Vue d'ensemble", + "tags": ["dockezr", "monitoring"], + "style": "dark", + "timezone": "browser", + "panels": [ + { + "id": 1, + "title": "État des services", + "type": "stat", + "targets": [ + { + "expr": "up{job=\"dockezr-backend\"}", + "legendFormat": "Backend FastAPI" + }, + { + "expr": "up{job=\"dockezr-frontend\"}", + "legendFormat": "Frontend Next.js" + }, + { + "expr": "up{job=\"dockezr-database\"}", + "legendFormat": "Base de données" + } + ], + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "steps": [ + { + "color": "red", + "value": 0 + }, + { + "color": "green", + "value": 1 + } + ] + } + } + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + } + }, + { + "id": 2, + "title": "Requêtes par seconde - Backend", + "type": "graph", + "targets": [ + { + "expr": "rate(http_requests_total{job=\"dockezr-backend\"}[5m])", + "legendFormat": "RPS" + } + ], + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + } + }, + { + "id": 3, + "title": "Temps de réponse - Backend", + "type": "graph", + "targets": [ + { + "expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{job=\"dockezr-backend\"}[5m]))", + "legendFormat": "95th percentile" + }, + { + "expr": "histogram_quantile(0.50, rate(http_request_duration_seconds_bucket{job=\"dockezr-backend\"}[5m]))", + "legendFormat": "50th percentile" + } + ], + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 8 + } + } + ], + "time": { + "from": "now-1h", + "to": "now" + }, + "refresh": "30s" + } +} diff --git a/monitoring/grafana/provisioning/dashboards/dashboard.yml b/monitoring/grafana/provisioning/dashboards/dashboard.yml new file mode 100644 index 0000000..7435f09 --- /dev/null +++ b/monitoring/grafana/provisioning/dashboards/dashboard.yml @@ -0,0 +1,12 @@ +apiVersion: 1 + +providers: + - name: 'default' + orgId: 1 + folder: '' + type: file + disableDeletion: false + updateIntervalSeconds: 10 + allowUiUpdates: true + options: + path: /var/lib/grafana/dashboards diff --git a/monitoring/grafana/provisioning/datasources/prometheus.yml b/monitoring/grafana/provisioning/datasources/prometheus.yml new file mode 100644 index 0000000..1a57b69 --- /dev/null +++ b/monitoring/grafana/provisioning/datasources/prometheus.yml @@ -0,0 +1,9 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true + editable: true diff --git a/monitoring/prometheus.yml b/monitoring/prometheus.yml new file mode 100644 index 0000000..7975a41 --- /dev/null +++ b/monitoring/prometheus.yml @@ -0,0 +1,39 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +rule_files: + # - "first_rules.yml" + # - "second_rules.yml" + +scrape_configs: + # Prometheus lui-même + - job_name: 'prometheus' + static_configs: + - targets: ['localhost:9090'] + + # Backend FastAPI avec métriques + - job_name: 'dockezr-backend' + static_configs: + - targets: ['backend:8000'] + metrics_path: '/metrics' + scrape_interval: 10s + scrape_timeout: 5s + + # Base de données PostgreSQL (via postgres_exporter si ajouté) + - job_name: 'dockezr-database' + static_configs: + - targets: ['db:5432'] + scrape_interval: 30s + + # Frontend Next.js (métriques de base) + - job_name: 'dockezr-frontend' + static_configs: + - targets: ['frontend:3000'] + scrape_interval: 30s + + # Node Exporter pour métriques système (optionnel) + - job_name: 'node-exporter' + static_configs: + - targets: ['node-exporter:9100'] + scrape_interval: 15s diff --git a/scripts/test-connectivity.bat b/scripts/test-connectivity.bat deleted file mode 100644 index 99eab5b..0000000 --- a/scripts/test-connectivity.bat +++ /dev/null @@ -1,41 +0,0 @@ -@echo off -chcp 65001 >nul -echo Test de connectivite - Simulation d'erreurs -echo ========================================== - -echo Verification de l'etat des services... -docker compose ps - -echo. -echo Demarrage des tests de connectivite... -echo (Ces tests vont simuler des erreurs pour valider la detection automatique) - -echo. -echo Test 1: Backend accessible -docker compose run --rm test python -c " -import requests -try: - response = requests.get('http://backend:8000/health', timeout=5) - print('✅ Backend accessible') -except Exception as e: - print('❌ Backend inaccessible:', e) -" - -echo. -echo Test 2: Simulation d'erreur de connectivite -docker compose run --rm test python -c " -import requests -try: - response = requests.get('http://backend:8000/nonexistent', timeout=5) - print('❌ Erreur attendue: endpoint inexistant') -except Exception as e: - print('❌ Erreur de connectivite simulee:', e) -" - -echo. -echo Test 3: Test avec pytest (avec erreurs intentionnelles) -docker compose run --rm test pytest test_connectivity.py -v - -echo. -echo Tests de connectivite termines ! -echo Les erreurs ci-dessus sont intentionnelles pour valider la detection automatique.