aa
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
*.log
|
||||||
|
manifest-*
|
||||||
|
*.bak
|
||||||
@@ -54,7 +54,12 @@ Versionning spécifique des images Docker
|
|||||||
|
|
||||||
|
|
||||||
#🚀 TP DevOps Windows - Stack Complète Locale (Corrigé & Optimisé)
|
#🚀 TP DevOps Windows - Stack Complète Locale (Corrigé & Optimisé)
|
||||||
|
|
||||||
|
|
||||||
#📋 PRÉ-REQUIS WINDOWS - Installation Pas à Pas
|
#📋 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)
|
#🔧 1. Préparation du système (PowerShell Administrateur)
|
||||||
|
|
||||||
# Ouvrir PowerShell en tant qu'ADMINISTRATEUR (clic droit → Exécuter en tant qu'administrateur)
|
# Ouvrir PowerShell en tant qu'ADMINISTRATEUR (clic droit → Exécuter en tant qu'administrateur)
|
||||||
@@ -71,6 +76,7 @@ wsl --set-default-version 2
|
|||||||
|
|
||||||
# 4. Redémarrer l'ordinateur (OBLIGATOIRE)
|
# 4. Redémarrer l'ordinateur (OBLIGATOIRE)
|
||||||
Restart-Computer
|
Restart-Computer
|
||||||
|
|
||||||
#📥 2. Installation des outils (après redémarrage)
|
#📥 2. Installation des outils (après redémarrage)
|
||||||
|
|
||||||
# 1. Installer Chocolatey (package manager Windows)
|
# 1. Installer Chocolatey (package manager Windows)
|
||||||
@@ -80,6 +86,7 @@ iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocola
|
|||||||
|
|
||||||
# 2. Installer tous les outils
|
# 2. Installer tous les outils
|
||||||
choco install -y git docker-desktop vscode kubernetes-cli minikube terraform helm postman
|
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
|
# Vérifier l'installation WSL
|
||||||
@@ -98,7 +105,10 @@ sudo apt install -y python3 python3-pip python3-venv nodejs npm curl wget
|
|||||||
echo "alias k=kubectl" >> ~/.bashrc
|
echo "alias k=kubectl" >> ~/.bashrc
|
||||||
source ~/.bashrc
|
source ~/.bashrc
|
||||||
exit # Retour à PowerShell
|
exit # Retour à PowerShell
|
||||||
|
|
||||||
|
|
||||||
#🐋 ÉTAPE 1 : CONFIGURATION DOCKER DESKTOP
|
#🐋 ÉTAPE 1 : CONFIGURATION DOCKER DESKTOP
|
||||||
|
|
||||||
#⚙️ Configuration manuelle obligatoire :
|
#⚙️ Configuration manuelle obligatoire :
|
||||||
Ouvrir Docker Desktop après installation
|
Ouvrir Docker Desktop après installation
|
||||||
|
|
||||||
@@ -142,7 +152,10 @@ docker run hello-world
|
|||||||
# Vérifier l'intégration WSL2
|
# Vérifier l'intégration WSL2
|
||||||
wsl -d Ubuntu-22.04 -e docker version
|
wsl -d Ubuntu-22.04 -e docker version
|
||||||
# Doit fonctionner sans erreur
|
# Doit fonctionner sans erreur
|
||||||
|
|
||||||
|
|
||||||
#📁 ÉTAPE 2 : STRUCTURE DU PROJET OPTIMISÉE
|
#📁 ÉTAPE 2 : STRUCTURE DU PROJET OPTIMISÉE
|
||||||
|
|
||||||
#🗂️ Création de la structure :
|
#🗂️ Création de la structure :
|
||||||
|
|
||||||
# Créer le dossier principal
|
# Créer le dossier principal
|
||||||
@@ -177,9 +190,14 @@ C:\DevOpsProject\
|
|||||||
├── .github\workflows\ # CI/CD
|
├── .github\workflows\ # CI/CD
|
||||||
├── config\ # Fichiers de config
|
├── config\ # Fichiers de config
|
||||||
└── docs\ # Documentation
|
└── docs\ # Documentation
|
||||||
|
|
||||||
|
|
||||||
#🐍 ÉTAPE 3 : APPLICATION PYTHON CORRIGÉE
|
#🐍 ÉTAPE 3 : APPLICATION PYTHON CORRIGÉE
|
||||||
|
|
||||||
#3.1 Fichier : src\app\requirements.txt
|
#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
|
fastapi==0.104.1
|
||||||
uvicorn[standard]==0.24.0
|
uvicorn[standard]==0.24.0
|
||||||
pydantic==2.5.0
|
pydantic==2.5.0
|
||||||
@@ -187,6 +205,7 @@ prometheus-client==0.19.0
|
|||||||
python-dotenv==1.0.0
|
python-dotenv==1.0.0
|
||||||
pytest==7.4.3
|
pytest==7.4.3
|
||||||
httpx==0.25.1
|
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 fastapi import FastAPI, Request, Response, HTTPException
|
||||||
@@ -399,7 +418,11 @@ USER devopsuser
|
|||||||
|
|
||||||
# Commande de démarrage
|
# Commande de démarrage
|
||||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"]
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#🐳 ÉTAPE 4 : DOCKER COMPOSE CORRIGÉ
|
#🐳 ÉTAPE 4 : DOCKER COMPOSE CORRIGÉ
|
||||||
|
|
||||||
#4.1 Fichier : docker\docker-compose.yml (RECOMMENCÉ)
|
#4.1 Fichier : docker\docker-compose.yml (RECOMMENCÉ)
|
||||||
|
|
||||||
version: '3.8'
|
version: '3.8'
|
||||||
@@ -521,6 +544,7 @@ volumes:
|
|||||||
name: portainer-data
|
name: portainer-data
|
||||||
app-logs:
|
app-logs:
|
||||||
name: app-logs
|
name: app-logs
|
||||||
|
|
||||||
#4.2 Fichier : docker\prometheus.yml (À CRÉER)
|
#4.2 Fichier : docker\prometheus.yml (À CRÉER)
|
||||||
|
|
||||||
global:
|
global:
|
||||||
@@ -564,6 +588,7 @@ scrape_configs:
|
|||||||
# alertmanagers:
|
# alertmanagers:
|
||||||
# - static_configs:
|
# - static_configs:
|
||||||
# - targets: []
|
# - targets: []
|
||||||
|
|
||||||
#4.3 Exécution Docker Compose :
|
#4.3 Exécution Docker Compose :
|
||||||
|
|
||||||
# Se placer dans le dossier docker
|
# Se placer dans le dossier docker
|
||||||
@@ -582,7 +607,10 @@ docker-compose logs app
|
|||||||
curl http://localhost:8000
|
curl http://localhost:8000
|
||||||
# ou dans PowerShell
|
# ou dans PowerShell
|
||||||
Invoke-WebRequest -Uri "http://localhost:8000" -UseBasicParsing
|
Invoke-WebRequest -Uri "http://localhost:8000" -UseBasicParsing
|
||||||
|
|
||||||
|
|
||||||
#☸️ ÉTAPE 5 : KUBERNETES SIMPLIFIÉ POUR WINDOWS
|
#☸️ ÉTAPE 5 : KUBERNETES SIMPLIFIÉ POUR WINDOWS
|
||||||
|
|
||||||
#5.1 Activer Kubernetes dans Docker Desktop :
|
#5.1 Activer Kubernetes dans Docker Desktop :
|
||||||
|
|
||||||
1. Docker Desktop → Settings (roue crantée)
|
1. Docker Desktop → Settings (roue crantée)
|
||||||
@@ -590,6 +618,7 @@ Invoke-WebRequest -Uri "http://localhost:8000" -UseBasicParsing
|
|||||||
3. ✅ Enable Kubernetes
|
3. ✅ Enable Kubernetes
|
||||||
4. ✅ Show system containers (optional)
|
4. ✅ Show system containers (optional)
|
||||||
5. Apply & Restart (patienter 2-3 minutes)
|
5. Apply & Restart (patienter 2-3 minutes)
|
||||||
|
|
||||||
#5.2 Vérification :
|
#5.2 Vérification :
|
||||||
|
|
||||||
# Vérifier que Kubernetes fonctionne
|
# Vérifier que Kubernetes fonctionne
|
||||||
@@ -601,6 +630,7 @@ kubectl get nodes
|
|||||||
|
|
||||||
kubectl get pods --all-namespaces
|
kubectl get pods --all-namespaces
|
||||||
# Doit montrer les pods système
|
# Doit montrer les pods système
|
||||||
|
|
||||||
#5.3 Fichier : kubernetes\manifests\namespace.yaml
|
#5.3 Fichier : kubernetes\manifests\namespace.yaml
|
||||||
|
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -610,6 +640,7 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
name: devops-demo
|
name: devops-demo
|
||||||
environment: development
|
environment: development
|
||||||
|
|
||||||
#5.4 Fichier : kubernetes\manifests\configmap.yaml (NOUVEAU)
|
#5.4 Fichier : kubernetes\manifests\configmap.yaml (NOUVEAU)
|
||||||
|
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -622,6 +653,7 @@ data:
|
|||||||
APP_NAME: "devops-windows-app"
|
APP_NAME: "devops-windows-app"
|
||||||
LOG_LEVEL: "INFO"
|
LOG_LEVEL: "INFO"
|
||||||
PYTHONUNBUFFERED: "1"
|
PYTHONUNBUFFERED: "1"
|
||||||
|
|
||||||
#5.5 Fichier : kubernetes\manifests\deployment.yaml (SIMPLIFIÉ)
|
#5.5 Fichier : kubernetes\manifests\deployment.yaml (SIMPLIFIÉ)
|
||||||
|
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
@@ -695,6 +727,7 @@ spec:
|
|||||||
protocol: TCP
|
protocol: TCP
|
||||||
name: http
|
name: http
|
||||||
type: NodePort # CORRIGÉ : NodePort au lieu de LoadBalancer pour Windows
|
type: NodePort # CORRIGÉ : NodePort au lieu de LoadBalancer pour Windows
|
||||||
|
|
||||||
#5.6 Déploiement Kubernetes :
|
#5.6 Déploiement Kubernetes :
|
||||||
|
|
||||||
# 1. Build l'image Docker avec un tag spécifique
|
# 1. Build l'image Docker avec un tag spécifique
|
||||||
@@ -718,7 +751,10 @@ kubectl get svc -n devops-demo devops-app-service -o jsonpath='{.spec.ports[0].n
|
|||||||
|
|
||||||
# 5. Accéder à l'application
|
# 5. Accéder à l'application
|
||||||
# http://localhost:[PORT] (ex: http://localhost:30456)
|
# http://localhost:[PORT] (ex: http://localhost:30456)
|
||||||
|
|
||||||
|
|
||||||
#🏗️ ÉTAPE 6 : TERRAFORM SIMPLIFIÉ (OPTIONNEL)
|
#🏗️ ÉTAPE 6 : TERRAFORM SIMPLIFIÉ (OPTIONNEL)
|
||||||
|
|
||||||
#⚠️ IMPORTANT : Terraform + Docker sur Windows/WSL2 est complexe.
|
#⚠️ IMPORTANT : Terraform + Docker sur Windows/WSL2 est complexe.
|
||||||
#Je recommande de SAUTER cette étape pour les débutants.
|
#Je recommande de SAUTER cette étape pour les débutants.
|
||||||
Si vous voulez quand même essayer :
|
Si vous voulez quand même essayer :
|
||||||
@@ -838,6 +874,7 @@ output "application_url" {
|
|||||||
output "namespace" {
|
output "namespace" {
|
||||||
value = kubernetes_namespace.devops.metadata[0].name
|
value = kubernetes_namespace.devops.metadata[0].name
|
||||||
}
|
}
|
||||||
|
|
||||||
#6.2 Utilisation Terraform :
|
#6.2 Utilisation Terraform :
|
||||||
|
|
||||||
cd C:\DevOpsProject\terraform
|
cd C:\DevOpsProject\terraform
|
||||||
@@ -853,7 +890,10 @@ terraform apply
|
|||||||
|
|
||||||
# Pour détruire
|
# Pour détruire
|
||||||
terraform destroy
|
terraform destroy
|
||||||
|
|
||||||
|
|
||||||
#📦 ÉTAPE 7 : HELM SIMPLE POUR WINDOWS
|
#📦 ÉTAPE 7 : HELM SIMPLE POUR WINDOWS
|
||||||
|
|
||||||
#7.1 Création d'un chart Helm simple :
|
#7.1 Création d'un chart Helm simple :
|
||||||
|
|
||||||
cd C:\DevOpsProject\kubernetes\helm
|
cd C:\DevOpsProject\kubernetes\helm
|
||||||
@@ -910,6 +950,7 @@ app:
|
|||||||
monitoring:
|
monitoring:
|
||||||
enabled: true
|
enabled: true
|
||||||
prometheusScrape: true
|
prometheusScrape: true
|
||||||
|
|
||||||
#7.4 Fichier : kubernetes\helm\devops-chart\templates\deployment.yaml
|
#7.4 Fichier : kubernetes\helm\devops-chart\templates\deployment.yaml
|
||||||
|
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
@@ -956,6 +997,7 @@ spec:
|
|||||||
port: {{ .Values.app.service.targetPort }}
|
port: {{ .Values.app.service.targetPort }}
|
||||||
initialDelaySeconds: 10
|
initialDelaySeconds: 10
|
||||||
periodSeconds: 15
|
periodSeconds: 15
|
||||||
|
|
||||||
#7.5 Installation avec Helm :
|
#7.5 Installation avec Helm :
|
||||||
|
|
||||||
cd C:\DevOpsProject\kubernetes\helm
|
cd C:\DevOpsProject\kubernetes\helm
|
||||||
@@ -971,7 +1013,10 @@ helm upgrade devops-release ./devops-chart -n devops-demo
|
|||||||
|
|
||||||
# Désinstaller
|
# Désinstaller
|
||||||
helm uninstall devops-release -n devops-demo
|
helm uninstall devops-release -n devops-demo
|
||||||
|
|
||||||
|
|
||||||
#🔄 ÉTAPE 8 : GITHUB ACTIONS CORRIGÉ
|
#🔄 ÉTAPE 8 : GITHUB ACTIONS CORRIGÉ
|
||||||
|
|
||||||
#8.1 Fichier : .github\workflows\ci-cd.yml (PRATIQUE)
|
#8.1 Fichier : .github\workflows\ci-cd.yml (PRATIQUE)
|
||||||
|
|
||||||
name: CI/CD DevOps Windows
|
name: CI/CD DevOps Windows
|
||||||
@@ -1070,7 +1115,10 @@ jobs:
|
|||||||
echo "kubectl apply -f kubernetes/manifests/"
|
echo "kubectl apply -f kubernetes/manifests/"
|
||||||
echo "ou"
|
echo "ou"
|
||||||
echo "helm upgrade --install ..."
|
echo "helm upgrade --install ..."
|
||||||
|
|
||||||
|
|
||||||
#📊 ÉTAPE 9 : MONITORING FONCTIONNEL
|
#📊 ÉTAPE 9 : MONITORING FONCTIONNEL
|
||||||
|
|
||||||
#9.1 Dashboard Grafana prêt à l'emploi :
|
#9.1 Dashboard Grafana prêt à l'emploi :
|
||||||
|
|
||||||
# Créer un dossier pour les dashboards Grafana
|
# Créer un dossier pour les dashboards Grafana
|
||||||
@@ -1102,6 +1150,7 @@ mkdir C:\DevOpsProject\docker\grafana-dashboards
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
'@ | Out-File -FilePath "C:\DevOpsProject\docker\grafana-dashboards\dashboard.json" -Encoding UTF8
|
'@ | Out-File -FilePath "C:\DevOpsProject\docker\grafana-dashboards\dashboard.json" -Encoding UTF8
|
||||||
|
|
||||||
#9.2 Accès aux interfaces :
|
#9.2 Accès aux interfaces :
|
||||||
|
|
||||||
✅ Après docker-compose up -d :
|
✅ Après docker-compose up -d :
|
||||||
@@ -1117,7 +1166,10 @@ mkdir C:\DevOpsProject\docker\grafana-dashboards
|
|||||||
|
|
||||||
1. Application K8s : http://localhost:[NODE_PORT]
|
1. Application K8s : http://localhost:[NODE_PORT]
|
||||||
(trouvez le port avec : kubectl get svc -n devops-demo)
|
(trouvez le port avec : kubectl get svc -n devops-demo)
|
||||||
|
|
||||||
|
|
||||||
#🛠️ ÉTAPE 10 : SCRIPTS PRATIQUES
|
#🛠️ ÉTAPE 10 : SCRIPTS PRATIQUES
|
||||||
|
|
||||||
#10.1 Script : scripts\setup.ps1 (AMÉLIORÉ)
|
#10.1 Script : scripts\setup.ps1 (AMÉLIORÉ)
|
||||||
|
|
||||||
# DevOps Windows Setup Script
|
# DevOps Windows Setup Script
|
||||||
@@ -1386,7 +1438,10 @@ Write-Host "✅ Toutes les ressources ont été nettoyées" -ForegroundColor Gre
|
|||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "Pour recommencer :" -ForegroundColor Cyan
|
Write-Host "Pour recommencer :" -ForegroundColor Cyan
|
||||||
Write-Host " .\setup.ps1" -ForegroundColor Gray
|
Write-Host " .\setup.ps1" -ForegroundColor Gray
|
||||||
|
|
||||||
|
|
||||||
#🎯 VALIDATION FINALE
|
#🎯 VALIDATION FINALE
|
||||||
|
|
||||||
#Testez votre installation :
|
#Testez votre installation :
|
||||||
|
|
||||||
# 1. Lancer le setup
|
# 1. Lancer le setup
|
||||||
@@ -1444,7 +1499,7 @@ Votre stack DevOps Windows est maintenant fonctionnelle et prête à l'emploi !
|
|||||||
|
|
||||||
|
|
||||||
# Commentaire de Oualim
|
# 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
|
PS C:\DevOpsProject\docker> docker-compose ps
|
||||||
"....Found orphan containers ([gitea logstash kibana filebeat elasticsearch devops-db])...."
|
"....Found orphan containers ([gitea logstash kibana filebeat elasticsearch devops-db])...."
|
||||||
|
|||||||
@@ -16,4 +16,7 @@
|
|||||||
- se connecter pour ouvrir l'accès ==> "url = https://git..." (url ==> C:\DevOpsProject\.git\config)
|
- se connecter pour ouvrir l'accès ==> "url = https://git..." (url ==> C:\DevOpsProject\.git\config)
|
||||||
- "git push origin main"
|
- "git push origin main"
|
||||||
|
|
||||||
|
# Puller une partie de projet modifié en preservant les modifs non pushé
|
||||||
|
-
|
||||||
|
-
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000096
|
MANIFEST-000114
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-000094
|
MANIFEST-000112
|
||||||
|
|||||||
@@ -415,3 +415,84 @@
|
|||||||
13:52:44.428084 version@stat F·[0 1] S·577B[0B 577B] Sc·[0.00 0.00]
|
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.486849 db@janitor F·3 G·0
|
||||||
13:52:44.487042 db@open done T·69.246442ms
|
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
|
||||||
|
|||||||
16
src/app/.dockerignore
Normal file
16
src/app/.dockerignore
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
.pytest_cache
|
||||||
|
.coverage
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
README.md
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
|
.env
|
||||||
|
*.log
|
||||||
|
node_modules
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
tests/
|
||||||
|
docs/
|
||||||
@@ -1,66 +1,32 @@
|
|||||||
# ==========================
|
# Phase de base
|
||||||
# STAGE 1 : Construction
|
FROM python:3.11-slim AS base
|
||||||
# ==========================
|
|
||||||
FROM python:3.11-slim AS builder
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Installer les dépendances système
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
build-essential \
|
build-essential libpq-dev gcc libpq5 && rm -rf /var/lib/apt/lists/*
|
||||||
libpq-dev \
|
|
||||||
gcc \
|
|
||||||
postgresql-client \
|
|
||||||
&& 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
|
RUN python -m venv /venv
|
||||||
ENV PATH="/venv/bin:$PATH"
|
ENV PATH="/venv/bin:$PATH"
|
||||||
|
RUN /venv/bin/pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
# Installer les dépendances
|
# Phase finale
|
||||||
COPY src/app/requirements.txt .
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
|
|
||||||
# ==========================
|
|
||||||
# STAGE 2 : Production
|
|
||||||
# ==========================
|
|
||||||
FROM python:3.11-slim AS runtime
|
FROM python:3.11-slim AS runtime
|
||||||
|
|
||||||
# Définir le répertoire de travail
|
WORKDIR /app # 🔴 Ajouté : définit le répertoire de travail
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Installer les bibliothèques système
|
COPY --from=base /venv /venv
|
||||||
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
|
|
||||||
ENV PATH="/venv/bin:$PATH"
|
ENV PATH="/venv/bin:$PATH"
|
||||||
|
|
||||||
# Copier le code
|
|
||||||
COPY src/app /app
|
COPY src/app /app
|
||||||
|
COPY TpDevOpsProject.md /app/TpDevOpsProject.md
|
||||||
|
|
||||||
# Changer les droits
|
RUN useradd -m -u 1000 devopsuser && chown -R devopsuser:devopsuser /app
|
||||||
RUN chown -R devopsuser:devopsuser /app
|
|
||||||
USER devopsuser
|
USER devopsuser
|
||||||
|
|
||||||
# Variables d'environnement
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
|
||||||
ENV ENV=production
|
|
||||||
ENV HOSTNAME=devops-container
|
|
||||||
ENV PYTHONPATH="/app"
|
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
# Lancer l'application
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--app-dir", "/app"]
|
||||||
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"]
|
|
||||||
BIN
src/app/__pycache__/main.cpython-314.pyc
Normal file
BIN
src/app/__pycache__/main.cpython-314.pyc
Normal file
Binary file not shown.
160
src/app/main.py
160
src/app/main.py
@@ -1,153 +1,79 @@
|
|||||||
# ==========================
|
import traceback
|
||||||
# IMPORTS DES DÉPENDANCES
|
import os
|
||||||
# ==========================
|
from pathlib import Path
|
||||||
from fastapi import FastAPI, Request, HTTPException, Response
|
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
|
from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
|
||||||
import time
|
import time
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict
|
import markdown
|
||||||
|
|
||||||
# Import du routeur pour /users
|
|
||||||
from routes import router as routes_app
|
from routes import router as routes_app
|
||||||
|
|
||||||
# ==========================
|
|
||||||
# CONFIGURATION DE L'APPLICATION
|
|
||||||
# ==========================
|
|
||||||
# Configuration du logging
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger(__name__)
|
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",
|
# 🔹 Utilise un chemin absolu pour le dossier templates
|
||||||
description="Application de démonstration DevOps sous Windows",
|
BASE_DIR = Path(__file__).resolve().parent
|
||||||
version="1.0.0"
|
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"])
|
app.include_router(routes_app, prefix="/users", tags=["users"])
|
||||||
|
|
||||||
# ==========================
|
REQUEST_COUNT = Counter('http_requests_total', 'Total des requêtes HTTP', ['method', 'endpoint', 'status'])
|
||||||
# MÉTRIQUES PROMETHEUS
|
REQUEST_LATENCY = Histogram('http_request_duration_seconds', 'Temps de réponse HTTP', ['method', 'endpoint'])
|
||||||
# ==========================
|
|
||||||
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']
|
|
||||||
)
|
|
||||||
|
|
||||||
# ==========================
|
|
||||||
# MIDDLEWARE DE MONITORING
|
|
||||||
# ==========================
|
|
||||||
@app.middleware("http")
|
@app.middleware("http")
|
||||||
async def monitor_requests(request: Request, call_next):
|
async def monitor_requests(request: Request, call_next):
|
||||||
"""Middleware pour suivre les requêtes et mesurer la latence."""
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = await call_next(request)
|
response = await call_next(request)
|
||||||
status_code = str(response.status_code)
|
status_code = str(response.status_code)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
status_code = "500"
|
status_code = "500"
|
||||||
response = Response(
|
response = Response(content=f"Erreur serveur : {str(e)}", status_code=500)
|
||||||
content=f"Erreur serveur : {str(e)}",
|
|
||||||
status_code=500
|
|
||||||
)
|
|
||||||
|
|
||||||
process_time = time.time() - start_time
|
process_time = time.time() - start_time
|
||||||
|
REQUEST_COUNT.labels(method=request.method, endpoint=request.url.path, status=status_code).inc()
|
||||||
# Enregistrement des métriques
|
REQUEST_LATENCY.labels(method=request.method, endpoint=request.url.path).observe(process_time)
|
||||||
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
|
|
||||||
response.headers["X-Process-Time"] = f"{process_time:.3f}s"
|
response.headers["X-Process-Time"] = f"{process_time:.3f}s"
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# ==========================
|
@app.get("/", response_class=HTMLResponse)
|
||||||
# ENDPOINTS PRINCIPAUX
|
async def home(request: Request):
|
||||||
# ==========================
|
md_file_path = "/app/TpDevOpsProject.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("/")
|
header_banner = "🚀 <strong>$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ DevOps Stack Windows - Fonctionnel ! $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$</strong>"
|
||||||
async def home():
|
|
||||||
"""Endpoint racine - Statut de l'application."""
|
try:
|
||||||
return {
|
return templates.TemplateResponse("index.html", {
|
||||||
"message": "🚀 DevOps Stack Windows - Fonctionnel !",
|
"request": request,
|
||||||
"environment": os.getenv("ENV", "development"),
|
"header": header_banner,
|
||||||
"status": "running",
|
"content": html_content
|
||||||
"hostname": os.getenv("HOSTNAME", "windows-devops"),
|
})
|
||||||
"version": "1.0.0"
|
except Exception as e:
|
||||||
}
|
return HTMLResponse(f"<h3>Erreur de template :</h3><pre>{traceback.format_exc()}</pre>", status_code=500)
|
||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
async def health():
|
async def health(): return {"status": "healthy", "timestamp": time.time(), "service": "devops-app"}
|
||||||
"""Health check pour Kubernetes."""
|
|
||||||
return {
|
|
||||||
"status": "healthy",
|
|
||||||
"timestamp": time.time(),
|
|
||||||
"service": "devops-app"
|
|
||||||
}
|
|
||||||
|
|
||||||
@app.get("/metrics")
|
@app.get("/metrics")
|
||||||
async def metrics():
|
async def metrics():
|
||||||
"""Endpoint pour Prometheus."""
|
try: return Response(content=generate_latest(), media_type=CONTENT_TYPE_LATEST)
|
||||||
try:
|
except Exception as e: raise HTTPException(status_code=500, detail="Échec des métriques")
|
||||||
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")
|
|
||||||
|
|
||||||
@app.get("/info")
|
@app.get("/info")
|
||||||
async def info():
|
async def info(): return {
|
||||||
"""Informations système."""
|
"python_version": "3.11", "platform": "windows", "service": "FastAPI DevOps",
|
||||||
return {
|
"features": ["docker", "kubernetes", "monitoring", "ci-cd"]
|
||||||
"python_version": "3.11",
|
}
|
||||||
"platform": "windows",
|
|
||||||
"service": "FastAPI DevOps",
|
|
||||||
"features": ["docker", "kubernetes", "monitoring", "ci-cd"]
|
|
||||||
}
|
|
||||||
|
|
||||||
@app.get("/env")
|
@app.get("/env")
|
||||||
async def show_env():
|
async def show_env(): return {"ENV": os.getenv("ENV", "not-set"), "HOSTNAME": os.getenv("HOSTNAME", "not-set")}
|
||||||
"""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
|
|
||||||
)
|
|
||||||
@@ -5,4 +5,6 @@ prometheus-client==0.19.0
|
|||||||
python-dotenv==1.0.0
|
python-dotenv==1.0.0
|
||||||
pytest==7.4.3
|
pytest==7.4.3
|
||||||
httpx==0.25.1
|
httpx==0.25.1
|
||||||
psycopg2==2.9.9
|
psycopg2-binary==2.9.9
|
||||||
|
markdown==3.6
|
||||||
|
jinja2
|
||||||
|
|||||||
9
src/app/templates/index.html
Normal file
9
src/app/templates/index.html
Normal 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>
|
||||||
Reference in New Issue
Block a user