Compare commits
4 Commits
5bc95a7079
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e68016e8a | ||
|
|
908c25840e | ||
|
|
4723f4ebb9 | ||
|
|
7377c00a47 |
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*.log
|
||||
manifest-*
|
||||
*.bak
|
||||
@@ -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é
|
||||
-
|
||||
-
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000096
|
||||
MANIFEST-000114
|
||||
|
||||
@@ -1 +1 @@
|
||||
MANIFEST-000094
|
||||
MANIFEST-000112
|
||||
|
||||
@@ -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
112
readme.md
@@ -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
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 @@
|
||||
# ==========================
|
||||
# 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"]
|
||||
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 @@
|
||||
# ==========================
|
||||
# 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",
|
||||
"features": ["docker", "kubernetes", "monitoring", "ci-cd"]
|
||||
}
|
||||
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")}
|
||||
@@ -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
|
||||
|
||||
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