Compare commits

...

4 Commits

Author SHA1 Message Date
Waloshi6
9e68016e8a aa 2026-02-08 14:52:14 +01:00
Waloshi6
908c25840e bb 2026-02-08 14:41:38 +01:00
Waloshi6
4723f4ebb9 Merge branch 'main' of https://git.bonisco.fr/OrgaDevops/Tuto-Devops-A---Z 2026-02-08 14:38:44 +01:00
Waloshi6
7377c00a47 aa 2026-02-08 14:34:23 +01:00
15 changed files with 266 additions and 198 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.log
manifest-*
*.bak

View File

@@ -16,4 +16,7 @@
- se connecter pour ouvrir l'accès ==> "url = https://git..." (url ==> C:\DevOpsProject\.git\config)
- "git push origin main"
# Puller une partie de projet modifié en preservant les modifs non pushé
-
-

View File

@@ -1 +1 @@
MANIFEST-000096
MANIFEST-000114

View File

@@ -1 +1 @@
MANIFEST-000094
MANIFEST-000112

View File

@@ -415,3 +415,96 @@
13:52:44.428084 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
13:52:44.486849 db@janitor F·3 G·0
13:52:44.487042 db@open done T·69.246442ms
=============== Feb 5, 2026 (UTC) ===============
15:51:14.399455 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
15:51:14.439535 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
15:51:14.440100 db@open opening
15:51:14.443037 journal@recovery F·1
15:51:14.444002 journal@recovery recovering @93
15:51:14.457130 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
15:51:14.511329 db@janitor F·3 G·0
15:51:14.511866 db@open done T·71.613432ms
=============== Feb 6, 2026 (UTC) ===============
10:49:29.095596 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
10:49:29.131170 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
10:49:29.131550 db@open opening
10:49:29.135461 journal@recovery F·1
10:49:29.135730 journal@recovery recovering @95
10:49:29.141437 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
10:49:29.199095 db@janitor F·3 G·0
10:49:29.199560 db@open done T·67.8483ms
=============== Feb 6, 2026 (UTC) ===============
10:53:40.580960 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
10:53:40.591365 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
10:53:40.591700 db@open opening
10:53:40.593746 journal@recovery F·1
10:53:40.594013 journal@recovery recovering @97
10:53:40.604447 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
10:53:40.712208 db@janitor F·3 G·0
10:53:40.712621 db@open done T·120.78394ms
=============== Feb 6, 2026 (UTC) ===============
10:57:24.598143 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
10:57:24.616721 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
10:57:24.617237 db@open opening
10:57:24.618928 journal@recovery F·1
10:57:24.619220 journal@recovery recovering @99
10:57:24.622811 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
10:57:24.658530 db@janitor F·3 G·0
10:57:24.658711 db@open done T·41.279095ms
=============== Feb 6, 2026 (UTC) ===============
11:00:06.298412 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
11:00:06.310703 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
11:00:06.311328 db@open opening
11:00:06.316598 journal@recovery F·1
11:00:06.317192 journal@recovery recovering @101
11:00:06.325703 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
11:00:06.374535 db@janitor F·3 G·0
11:00:06.374849 db@open done T·63.190584ms
=============== Feb 6, 2026 (UTC) ===============
11:50:03.854543 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
11:50:03.864227 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
11:50:03.865796 db@open opening
11:50:03.872207 journal@recovery F·1
11:50:03.872558 journal@recovery recovering @103
11:50:03.876753 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
11:50:03.949425 db@janitor F·3 G·0
11:50:03.950338 db@open done T·84.322748ms
=============== Feb 6, 2026 (UTC) ===============
12:45:29.925234 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
12:45:29.952459 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
12:45:29.953662 db@open opening
12:45:29.959031 journal@recovery F·1
12:45:29.959375 journal@recovery recovering @105
12:45:29.963600 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
12:45:30.026778 db@janitor F·3 G·0
12:45:30.027106 db@open done T·73.277756ms
=============== Feb 7, 2026 (UTC) ===============
15:37:46.707349 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
15:37:46.739671 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
15:37:46.740550 db@open opening
15:37:46.745371 journal@recovery F·1
15:37:46.745766 journal@recovery recovering @107
15:37:46.751116 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
15:37:46.811638 db@janitor F·3 G·0
15:37:46.811822 db@open done T·70.8136ms
=============== Feb 7, 2026 (UTC) ===============
15:41:07.560631 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
15:41:07.573670 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
15:41:07.574246 db@open opening
15:41:07.576253 journal@recovery F·1
15:41:07.576509 journal@recovery recovering @109
15:41:07.579359 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
15:41:07.617133 db@janitor F·3 G·0
15:41:07.617309 db@open done T·42.89556ms
<<<<<<< HEAD
=============== Feb 8, 2026 (UTC) ===============
13:10:57.397891 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed
13:10:57.432913 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
13:10:57.435331 db@open opening
13:10:57.437339 journal@recovery F·1
13:10:57.437654 journal@recovery recovering @111
13:10:57.440763 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
13:10:57.485091 db@janitor F·3 G·0
13:10:57.485346 db@open done T·49.7959ms
=======
>>>>>>> 7377c00 (aa)

112
readme.md
View File

@@ -47,8 +47,18 @@ Original pourrit: https://cloud.bonisco.fr/s/Cb2bFdLXeFEFcLm
Ouvrir PowerShell en tant qu'ADMINISTRATEUR (clic droit → Exécuter en tant qu'administrateur)
1. Activer les fonctionnalités Windows nécessaires
```
#🚀 TP DevOps Windows - Stack Complète Locale (Corrigé & Optimisé)
#📋 PRÉ-REQUIS WINDOWS - Installation Pas à Pas
Avant tout, bien penser à ACTIVER la fonction de VIRTUALISATION dans le BIOS du systeme de votre pc
#🔧 1. Préparation du système (PowerShell Administrateur)
# Ouvrir PowerShell en tant qu'ADMINISTRATEUR (clic droit → Exécuter en tant qu'administrateur)
# 1. Activer les fonctionnalités Windows nécessaires
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
```
@@ -63,8 +73,8 @@ wsl --set-default-version 2
4. Redémarrer l'ordinateur (OBLIGATOIRE)
```
Restart-Computer
```
### 📥 2. Installation des outils (après redémarrage)
#📥 2. Installation des outils (après redémarrage)
1. Installer Chocolatey (package manager Windows)
```
@@ -75,9 +85,9 @@ iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocola
2. Installer tous les outils
```
choco install -y git docker-desktop vscode kubernetes-cli minikube terraform helm postman
```
3. Configuration WSL2 et Ubuntu
```
#🐧 3. Configuration WSL2 et Ubuntu
# Vérifier l'installation WSL
wsl --list --verbose
# Doit afficher : Ubuntu-22.04 Running 2
@@ -98,10 +108,11 @@ Créer un alias pratique
echo "alias k=kubectl" >> ~/.bashrc
source ~/.bashrc
exit # Retour à PowerShell
```
## 🐋 ÉTAPE 1 : CONFIGURATION DOCKER DESKTOP
### ⚙️ Configuration manuelle obligatoire :
#🐋 ÉTAPE 1 : CONFIGURATION DOCKER DESKTOP
#⚙️ Configuration manuelle obligatoire :
Ouvrir Docker Desktop après installation
Settings → General :
@@ -131,10 +142,12 @@ docker run hello-world
Vérifier l'intégration WSL2
```
wsl -d Ubuntu-22.04 -e docker version
```
Doit fonctionner sans erreur
*📁 ÉTAPE 2 : STRUCTURE DU PROJET OPTIMISÉE
*🗂️ Création de la structure :
# Doit fonctionner sans erreur
#📁 ÉTAPE 2 : STRUCTURE DU PROJET OPTIMISÉE
#🗂️ Création de la structure :
Créer le dossier principal
```
@@ -173,11 +186,14 @@ C:\DevOpsProject\
├── .github\workflows\ # CI/CD
├── config\ # Fichiers de config
└── docs\ # Documentation
```
## 🐍 ÉTAPE 3 : APPLICATION PYTHON CORRIGÉE
### 3.1 Fichier : `src\app\requirements.txt`
```
#🐍 ÉTAPE 3 : APPLICATION PYTHON CORRIGÉE
#3.1 Fichier : src\app\requirements.txt
# commentaire de Oualim : Ce fichier installera les dépendances dans le conteneur, pas sur votre machine
fastapi==0.104.1
uvicorn[standard]==0.24.0
pydantic==2.5.0
@@ -185,9 +201,9 @@ prometheus-client==0.19.0
python-dotenv==1.0.0
pytest==7.4.3
httpx==0.25.1
```
#3.2 Fichier : `src\app\main.py `(CORRIGÉ)
```
#3.2 Fichier : src\app\main.py (CORRIGÉ)
from fastapi import FastAPI, Request, Response, HTTPException
from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
import time
@@ -403,7 +419,12 @@ USER devopsuser
# Commande de démarrage
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"]
```
#🐳 ÉTAPE 4 : DOCKER COMPOSE CORRIGÉ
#4.1 Fichier : docker\docker-compose.yml (RECOMMENCÉ)
## 🐳 ÉTAPE 4 : DOCKER COMPOSE CORRIGÉ
### 4.1 Fichier : `docker\docker-compose.yml` (RECOMMENCÉ)
@@ -527,6 +548,7 @@ volumes:
name: portainer-data
app-logs:
name: app-logs
#4.2 Fichier : docker\prometheus.yml (À CRÉER)
global:
@@ -570,7 +592,8 @@ scrape_configs:
# alertmanagers:
# - static_configs:
# - targets: []
```
#4.3 Exécution Docker Compose :
## 4.3 Exécution Docker Compose :
@@ -597,10 +620,11 @@ curl http://localhost:8000
ou dans PowerShell
```
Invoke-WebRequest -Uri "http://localhost:8000" -UseBasicParsing
```
##☸️ ÉTAPE 5 : KUBERNETES SIMPLIFIÉ POUR WINDOWS
### 5.1 Activer Kubernetes dans Docker Desktop :
#☸️ ÉTAPE 5 : KUBERNETES SIMPLIFIÉ POUR WINDOWS
#5.1 Activer Kubernetes dans Docker Desktop :
1. Docker Desktop → Settings (roue crantée)
2. Onglet Kubernetes
@@ -608,6 +632,8 @@ Invoke-WebRequest -Uri "http://localhost:8000" -UseBasicParsing
4. ✅ Show system containers (optional)
5. Apply & Restart (patienter 2-3 minutes)
#5.2 Vérification :
### 5.2 Vérification :
Vérifier que Kubernetes fonctionne
@@ -618,7 +644,8 @@ kubectl get nodes
# Doit afficher : docker-desktop Ready
kubectl get pods --all-namespaces
# Doit montrer les pods système
```
#5.3 Fichier : kubernetes\manifests\namespace.yaml
#### 5.3 Fichier : kubernetes\manifests\namespace.yaml
```
@@ -629,7 +656,8 @@ metadata:
labels:
name: devops-demo
environment: development
```
#5.4 Fichier : kubernetes\manifests\configmap.yaml (NOUVEAU)
### 5.4 Fichier : kubernetes\manifests\configmap.yaml (NOUVEAU)
```
@@ -643,7 +671,8 @@ data:
APP_NAME: "devops-windows-app"
LOG_LEVEL: "INFO"
PYTHONUNBUFFERED: "1"
```
#5.5 Fichier : kubernetes\manifests\deployment.yaml (SIMPLIFIÉ)
### 5.5 Fichier : kubernetes\manifests\deployment.yaml (SIMPLIFIÉ)
```
@@ -718,7 +747,6 @@ spec:
protocol: TCP
name: http
type: NodePort # CORRIGÉ : NodePort au lieu de LoadBalancer pour Windows
```
#5.6 Déploiement Kubernetes :
@@ -743,7 +771,10 @@ kubectl get svc -n devops-demo devops-app-service -o jsonpath='{.spec.ports[0].n
# 5. Accéder à l'application
# http://localhost:[PORT] (ex: http://localhost:30456)
#🏗️ ÉTAPE 6 : TERRAFORM SIMPLIFIÉ (OPTIONNEL)
#⚠️ IMPORTANT : Terraform + Docker sur Windows/WSL2 est complexe.
#Je recommande de SAUTER cette étape pour les débutants.
Si vous voulez quand même essayer :
@@ -863,6 +894,7 @@ output "application_url" {
output "namespace" {
value = kubernetes_namespace.devops.metadata[0].name
}
#6.2 Utilisation Terraform :
cd C:\DevOpsProject\terraform
@@ -878,7 +910,10 @@ terraform apply
# Pour détruire
terraform destroy
#📦 ÉTAPE 7 : HELM SIMPLE POUR WINDOWS
#7.1 Création d'un chart Helm simple :
cd C:\DevOpsProject\kubernetes\helm
@@ -935,6 +970,7 @@ app:
monitoring:
enabled: true
prometheusScrape: true
#7.4 Fichier : kubernetes\helm\devops-chart\templates\deployment.yaml
apiVersion: apps/v1
@@ -981,6 +1017,7 @@ spec:
port: {{ .Values.app.service.targetPort }}
initialDelaySeconds: 10
periodSeconds: 15
#7.5 Installation avec Helm :
cd C:\DevOpsProject\kubernetes\helm
@@ -996,7 +1033,10 @@ helm upgrade devops-release ./devops-chart -n devops-demo
# Désinstaller
helm uninstall devops-release -n devops-demo
#🔄 ÉTAPE 8 : GITHUB ACTIONS CORRIGÉ
#8.1 Fichier : .github\workflows\ci-cd.yml (PRATIQUE)
name: CI/CD DevOps Windows
@@ -1095,7 +1135,10 @@ jobs:
echo "kubectl apply -f kubernetes/manifests/"
echo "ou"
echo "helm upgrade --install ..."
#📊 ÉTAPE 9 : MONITORING FONCTIONNEL
#9.1 Dashboard Grafana prêt à l'emploi :
# Créer un dossier pour les dashboards Grafana
@@ -1127,6 +1170,7 @@ mkdir C:\DevOpsProject\docker\grafana-dashboards
}
}
'@ | Out-File -FilePath "C:\DevOpsProject\docker\grafana-dashboards\dashboard.json" -Encoding UTF8
#9.2 Accès aux interfaces :
✅ Après docker-compose up -d :
@@ -1142,7 +1186,10 @@ mkdir C:\DevOpsProject\docker\grafana-dashboards
1. Application K8s : http://localhost:[NODE_PORT]
(trouvez le port avec : kubectl get svc -n devops-demo)
#🛠️ ÉTAPE 10 : SCRIPTS PRATIQUES
#10.1 Script : scripts\setup.ps1 (AMÉLIORÉ)
# DevOps Windows Setup Script
@@ -1411,7 +1458,10 @@ Write-Host "✅ Toutes les ressources ont été nettoyées" -ForegroundColor Gre
Write-Host ""
Write-Host "Pour recommencer :" -ForegroundColor Cyan
Write-Host " .\setup.ps1" -ForegroundColor Gray
#🎯 VALIDATION FINALE
#Testez votre installation :
# 1. Lancer le setup
@@ -1469,7 +1519,7 @@ Votre stack DevOps Windows est maintenant fonctionnelle et prête à l'emploi !
# Commentaire de Oualim
# Avant d'aller plus loin, les partie 6,7 et 8 n'étant pas encore abordée à cette étape, en lançant uniquement les commandes de la partie 4.3 on se retrouvera avec des containeurs orphelins :
# Avant d'aller plus loin, les #6, #7 et #8 n'étant pas encore abordée à cette étape, en lançant uniquement les commandes de le #3 on se retrouvera avec des containeurs orphelins :
PS C:\DevOpsProject\docker> docker-compose ps
"....Found orphan containers ([gitea logstash kibana filebeat elasticsearch devops-db])...."

16
src/app/.dockerignore Normal file
View File

@@ -0,0 +1,16 @@
__pycache__
*.pyc
.pytest_cache
.coverage
.git
.gitignore
README.md
Dockerfile
.dockerignore
.env
*.log
node_modules
.vscode
.idea
tests/
docs/

View File

@@ -1,66 +1,32 @@
# ==========================
# STAGE 1 : Construction
# ==========================
FROM python:3.11-slim AS builder
# Phase de base
FROM python:3.11-slim AS base
WORKDIR /app
# Installer les dépendances système
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
gcc \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
build-essential libpq-dev gcc libpq5 && rm -rf /var/lib/apt/lists/*
# Créer un environnement virtuel
RUN pip install --upgrade pip
COPY src/app/requirements.txt .
RUN python -m venv /venv
ENV PATH="/venv/bin:$PATH"
RUN /venv/bin/pip install --no-cache-dir -r requirements.txt
# Installer les dépendances
COPY src/app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# ==========================
# STAGE 2 : Production
# ==========================
# Phase finale
FROM python:3.11-slim AS runtime
# Définir le répertoire de travail
WORKDIR /app
WORKDIR /app # 🔴 Ajouté : définit le répertoire de travail
# Installer les bibliothèques système
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
# 🔥 Installe curl ici
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# Créer un utilisateur non-root
RUN useradd -m -u 1000 devopsuser
# Copier l'environnement virtuel
COPY --from=builder /venv /venv
COPY --from=base /venv /venv
ENV PATH="/venv/bin:$PATH"
# Copier le code
COPY src/app /app
COPY readme.md /app/readme.md
# Changer les droits
RUN chown -R devopsuser:devopsuser /app
RUN useradd -m -u 1000 devopsuser && chown -R devopsuser:devopsuser /app
USER devopsuser
# Variables d'environnement
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV ENV=production
ENV HOSTNAME=devops-container
ENV PYTHONPATH="/app"
EXPOSE 8000
# Lancer l'application
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"]
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--app-dir", "/app"]

Binary file not shown.

View File

@@ -1,153 +1,79 @@
# ==========================
# IMPORTS DES DÉPENDANCES
# ==========================
import traceback
import os
from pathlib import Path
from fastapi import FastAPI, Request, HTTPException, Response
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
import time
import os
import logging
from typing import Dict
import markdown
# Import du routeur pour /users
from routes import router as routes_app
# ==========================
# CONFIGURATION DE L'APPLICATION
# ==========================
# Configuration du logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Création de l'application FastAPI
app = FastAPI(
title="DevOps Windows API",
description="Application de démonstration DevOps sous Windows",
version="1.0.0"
)
app = FastAPI(title="DevOps Windows API", description="Application de démonstration DevOps sous Windows", version="1.0.0")
# 🔹 Utilise un chemin absolu pour le dossier templates
BASE_DIR = Path(__file__).resolve().parent
templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
# Inclusion du routeur (doit être après la création de 'app')
app.include_router(routes_app, prefix="/users", tags=["users"])
# ==========================
# MÉTRIQUES PROMETHEUS
# ==========================
REQUEST_COUNT = Counter(
'http_requests_total',
'Total des requêtes HTTP',
['method', 'endpoint', 'status']
)
REQUEST_COUNT = Counter('http_requests_total', 'Total des requêtes HTTP', ['method', 'endpoint', 'status'])
REQUEST_LATENCY = Histogram('http_request_duration_seconds', 'Temps de réponse HTTP', ['method', 'endpoint'])
REQUEST_LATENCY = Histogram(
'http_request_duration_seconds',
'Temps de réponse HTTP',
['method', 'endpoint']
)
# ==========================
# MIDDLEWARE DE MONITORING
# ==========================
@app.middleware("http")
async def monitor_requests(request: Request, call_next):
"""Middleware pour suivre les requêtes et mesurer la latence."""
start_time = time.time()
try:
response = await call_next(request)
status_code = str(response.status_code)
except Exception as e:
status_code = "500"
response = Response(
content=f"Erreur serveur : {str(e)}",
status_code=500
)
response = Response(content=f"Erreur serveur : {str(e)}", status_code=500)
process_time = time.time() - start_time
# Enregistrement des métriques
REQUEST_COUNT.labels(
method=request.method,
endpoint=request.url.path,
status=status_code
).inc()
REQUEST_LATENCY.labels(
method=request.method,
endpoint=request.url.path
).observe(process_time)
# Ajout du temps de traitement dans les headers
REQUEST_COUNT.labels(method=request.method, endpoint=request.url.path, status=status_code).inc()
REQUEST_LATENCY.labels(method=request.method, endpoint=request.url.path).observe(process_time)
response.headers["X-Process-Time"] = f"{process_time:.3f}s"
return response
# ==========================
# ENDPOINTS PRINCIPAUX
# ==========================
@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
md_file_path = "/app/readme.md"
try:
with open(md_file_path, "r", encoding="utf-8") as f:
md_content = f.read()
html_content = markdown.markdown(md_content)
except Exception as e:
html_content = f"<h3>Erreur de lecture du fichier :</h3><pre>{traceback.format_exc()}</pre>"
@app.get("/")
async def home():
"""Endpoint racine - Statut de l'application."""
return {
"message": "🚀 DevOps Stack Windows - Fonctionnel !",
"environment": os.getenv("ENV", "development"),
"status": "running",
"hostname": os.getenv("HOSTNAME", "windows-devops"),
"version": "1.0.0"
}
header_banner = "🚀 <strong>$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ DevOps Stack Windows - Fonctionnel ! $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$</strong>"
try:
return templates.TemplateResponse("index.html", {
"request": request,
"header": header_banner,
"content": html_content
})
except Exception as e:
return HTMLResponse(f"<h3>Erreur de template :</h3><pre>{traceback.format_exc()}</pre>", status_code=500)
@app.get("/health")
async def health():
"""Health check pour Kubernetes."""
return {
"status": "healthy",
"timestamp": time.time(),
"service": "devops-app"
}
async def health(): return {"status": "healthy", "timestamp": time.time(), "service": "devops-app"}
@app.get("/metrics")
async def metrics():
"""Endpoint pour Prometheus."""
try:
data = generate_latest()
return Response(
content=data,
media_type=CONTENT_TYPE_LATEST,
headers={"Cache-Control": "no-cache"}
)
except Exception as e:
logger.error(f"Erreur lors de la génération des métriques : {e}")
raise HTTPException(status_code=500, detail="Échec de la génération des métriques")
try: return Response(content=generate_latest(), media_type=CONTENT_TYPE_LATEST)
except Exception as e: raise HTTPException(status_code=500, detail="Échec des métriques")
@app.get("/info")
async def info():
"""Informations système."""
return {
"python_version": "3.11",
"platform": "windows",
"service": "FastAPI DevOps",
async def info(): return {
"python_version": "3.11", "platform": "windows", "service": "FastAPI DevOps",
"features": ["docker", "kubernetes", "monitoring", "ci-cd"]
}
}
@app.get("/env")
async def show_env():
"""Affiche les variables d'environnement (sécurisées)."""
safe_env = {
"ENV": os.getenv("ENV", "not-set"),
"HOSTNAME": os.getenv("HOSTNAME", "not-set"),
"PYTHON_VERSION": os.getenv("PYTHON_VERSION", "not-set")
}
return safe_env
# ==========================
# LANCEMENT EN DÉVELOPPEMENT
# ==========================
if __name__ == "__main__":
import uvicorn
logger.info("Démarrage du serveur FastAPI...")
uvicorn.run(
app,
host="0.0.0.0",
port=8000,
log_level="info",
reload=True # Auto-reload en dev
)
async def show_env(): return {"ENV": os.getenv("ENV", "not-set"), "HOSTNAME": os.getenv("HOSTNAME", "not-set")}

View File

@@ -5,4 +5,6 @@ prometheus-client==0.19.0
python-dotenv==1.0.0
pytest==7.4.3
httpx==0.25.1
psycopg2==2.9.9
psycopg2-binary==2.9.9
markdown==3.6
jinja2

View File

@@ -0,0 +1,9 @@
<!-- templates/index.html -->
<!DOCTYPE html>
<html>
<head><title>DevOps App</title></head>
<body>
<h1>{{ header|safe }}</h1>
<div>{{ content|safe }}</div>
</body>
</html>