Files
Tuto-Devops-A---Z/TpDevOpsProject.md

1495 lines
41 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TP DevOps
...et en cours de restructuration par Oualim (commentaires pour le futur pour tester une autre création à l'IA d'un tp, en tenant compte des manquements et des erreurs pour ne pas laisser l'IA les reproduire)
Original pourrit: https://cloud.bonisco.fr/s/Cb2bFdLXeFEFcLm
> Commentaire de Oualim (Celui de Deepseek est juste un peu moins pourri mais c'était aussi de la merde)
> Ce TP contient encore beaucoup de fautes sur les manips et fichiers et aucun sens sur la structure car l'IA a juste pris les mots clefs de "devops" sur internet, copié des fichiers et mélangé des concepts sans aucune présentation ni introduction ou explications (ex : correctif de l'ancien tp tout en bas :-/ ; terraform sur des docker ??? ; kub en faisant un doublon d'appli potentiellement conflictuel, aucune explication ni structure d'étape pour comprendre les logiques de docker et k8')
#📚 RÉCAPITULATIF DES CORRECTIONS APPORTÉES
## ✅ Corrections majeures :
* Python : Ajout de Response dans les imports FastAPI
* Docker Compose : Chemins corrigés, versions spécifiées
* Kubernetes : Changé LoadBalancer → NodePort pour Windows
* Image Docker : Tag :local au lieu de :latest pour K8s
* Terraform : Suppression du provider Docker problématique
* Scripts : Ajout de gestion d'erreurs robuste
* Tests : Ajout de tests unitaires Python
* Health checks : Ajout dans Docker Compose et K8s
## 🎯 Améliorations :
* Structure de projet logique et organisée
* Scripts PowerShell avec paramètres et gestion d'erreurs
* Configuration monitoring fonctionnelle
* Documentation claire étape par étape
* Solutions de dépannage incluses
* Versionning spécifique des images Docker
> Commentaire de Oualim
> Ce TP permet pour l'instant, de réaliser le paysage de docker pour un débutant, de comprendre une organisation de dossiers et fichiers, de créer qq containeurs docker :
> - http://localhost:8000 (App)
> - http://localhost:8000/docs (Documentation API)
> - http://localhost:9090 (Prometheus)
> - http://localhost:3000 (Grafana - admin/admin123)
> - http://localhost:9000 (Portainer)
# 🚀 TP DevOps Windows - Stack Complète Locale (Corrigé & Optimisé)
## 📋 PRÉ-REQUIS WINDOWS - Installation Pas à Pas
### 🔧 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
```
2. Installer WSL2 et Ubuntu
```
wsl --install -d Ubuntu-22.04
```
3. Définir WSL2 comme version par défaut
```
wsl --set-default-version 2
```
4. Redémarrer l'ordinateur (OBLIGATOIRE)
```
Restart-Computer
```
### 📥 2. Installation des outils (après redémarrage)
1. Installer Chocolatey (package manager Windows)
```
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
```
2. Installer tous les outils
```
choco install -y git docker-desktop vscode kubernetes-cli minikube terraform helm postman
```
3. Configuration WSL2 et Ubuntu
```
# Vérifier l'installation WSL
wsl --list --verbose
# Doit afficher : Ubuntu-22.04 Running 2
```
Entrer dans WSL pour configurer
```
wsl
```
Dans le terminal Ubuntu WSL :
```
sudo apt update
sudo apt upgrade -y
sudo apt install -y python3 python3-pip python3-venv nodejs npm curl wget
```
Créer un alias pratique
```
echo "alias k=kubectl" >> ~/.bashrc
source ~/.bashrc
exit # Retour à PowerShell
```
## 🐋 ÉTAPE 1 : CONFIGURATION DOCKER DESKTOP
### ⚙️ Configuration manuelle obligatoire :
Ouvrir Docker Desktop après installation
Settings → General :
* ✅ Use WSL 2 based engine
* ✅ Expose daemon on tcp://localhost:2375 without TLS
Settings → Resources → WSL Integration :
* ✅ Enable integration with my default WSL distro
* ✅ Ubuntu-22.04
Settings → Kubernetes :
* ✅ Enable Kubernetes
* ✅ Deploy Docker Stacks to Kubernetes by default
Settings → Advanced :
* CPUs : 4 (ou 50% de vos CPUs)
* Memory : 4.0 GB (ou 50% de votre RAM)
* Swap : 1.0 GB
Appliquer et redémarrer Docker Desktop
### ✅ Vérification Docker/WSL2 :
```
# Dans PowerShell
docker --version
# Doit afficher : Docker version 24.0.x
docker run hello-world
# Doit afficher "Hello from Docker!"
```
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 :
Créer le dossier principal
```
mkdir C:\DevOpsProject
cd C:\DevOpsProject
```
Structure ORGANISÉE et LOGIQUE
```
New-Item -ItemType Directory -Path @(
"src\app",
"src\app\tests",
"docker",
"kubernetes\manifests",
"kubernetes\helm",
"terraform",
".github\workflows",
"monitoring",
"scripts",
"docs",
"config"
)
```
Structure finale :
```
C:\DevOpsProject\
├── src\ # Code source
│ ├── app\ # Application Python
│ └── app\tests\ # Tests unitaires
├── docker\ # Dockerfiles & Compose
├── kubernetes\ # K8s manifests
├── terraform\ # Infrastructure as Code
├── monitoring\ # Prometheus, Grafana
├── scripts\ # Scripts PowerShell
├── .github\workflows\ # CI/CD
├── config\ # Fichiers de config
└── docs\ # Documentation
```
#🐍 ÉTAPE 3 : APPLICATION PYTHON CORRIGÉE
#3.1 Fichier : src\app\requirements.txt
fastapi==0.104.1
uvicorn[standard]==0.24.0
pydantic==2.5.0
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É)
from fastapi import FastAPI, Request, Response, HTTPException
from prometheus_client import Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
import time
import os
import logging
from typing import Dict
# Configuration du logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI(
title="DevOps Windows API",
description="Application de démonstration DevOps sous Windows",
version="1.0.0"
)
# Métriques Prometheus - CORRIGÉ
REQUEST_COUNT = Counter(
'http_requests_total',
'Total HTTP Requests',
['method', 'endpoint', 'status']
)
REQUEST_LATENCY = Histogram(
'http_request_duration_seconds',
'HTTP Request latency',
['method', 'endpoint']
)
@app.middleware("http")
async def monitor_requests(request: Request, call_next):
"""Middleware pour monitorer les requêtes"""
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"Internal Server Error: {str(e)}",
status_code=500
)
process_time = time.time() - start_time
# Enregistrement des métriques - CORRIGÉ
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)
# Ajouter le temps de traitement dans les headers
response.headers["X-Process-Time"] = f"{process_time:.3f}s"
return response
@app.get("/")
async def home():
"""Endpoint principal"""
return {
"message": "🚀 DevOps Stack Windows - Fonctionnel !",
"environment": os.getenv("ENV", "development"),
"status": "running",
"hostname": os.getenv("HOSTNAME", "windows-devops"),
"version": "1.0.0"
}
@app.get("/health")
async def health():
"""Health check pour Kubernetes et load balancers"""
return {
"status": "healthy",
"timestamp": time.time(),
"service": "devops-app"
}
@app.get("/metrics")
async def metrics():
"""Endpoint Prometheus - CORRIGÉ"""
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"Error generating metrics: {e}")
raise HTTPException(status_code=500, detail="Metrics generation failed")
@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"]
}
@app.get("/env")
async def show_env():
"""Afficher les variables d'environnement (sécurisé)"""
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
# Pour le développement local
if __name__ == "__main__":
import uvicorn
logger.info("Starting FastAPI server...")
uvicorn.run(
app,
host="0.0.0.0",
port=8000,
log_level="info",
reload=True # Auto-reload en développement
)
#3.3 Fichier : src\app\tests\test_main.py (NOUVEAU)
import pytest
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_home_endpoint():
"""Test de l'endpoint principal"""
response = client.get("/")
assert response.status_code == 200
data = response.json()
assert "message" in data
assert "status" in data
assert data["status"] == "running"
def test_health_endpoint():
"""Test du health check"""
response = client.get("/health")
assert response.status_code == 200
data = response.json()
assert data["status"] == "healthy"
assert "service" in data
def test_metrics_endpoint():
"""Test des métriques Prometheus"""
response = client.get("/metrics")
assert response.status_code == 200
assert "text/plain" in response.headers["content-type"]
assert "http_requests_total" in response.text
def test_info_endpoint():
"""Test des informations"""
response = client.get("/info")
assert response.status_code == 200
data = response.json()
assert "python_version" in data
assert "platform" in data
def test_env_endpoint():
"""Test des variables d'environnement"""
response = client.get("/env")
assert response.status_code == 200
data = response.json()
assert "ENV" in data
#3.4 Fichier : src\app\Dockerfile (OPTIMISÉ)
# Étape 1 : Build
FROM python:3.11-slim AS builder
WORKDIR /app
# Copier les requirements d'abord (cache Docker)
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Étape 2 : Runtime
FROM python:3.11-slim
WORKDIR /app
# Copier les packages depuis le builder
COPY --from=builder /root/.local /root/.local
COPY . .
# Ajouter au PATH
ENV PATH=/root/.local/bin:$PATH
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV ENV=production
ENV HOSTNAME=devops-container
# Exposer le port
EXPOSE 8000
# Utiliser un user non-root pour la sécurité
RUN useradd -m -u 1000 devopsuser && chown -R devopsuser:devopsuser /app
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É)
version: '3.8'
services:
# Application principale
app:
build:
context: ../src/app
dockerfile: Dockerfile
container_name: devops-app
ports:
- "8000:8000"
environment:
- ENV=development
- HOSTNAME=devops-local
volumes:
- ../src/app:/app
- app-logs:/app/logs
networks:
- devops-network
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
labels:
- "com.devops.description=Application FastAPI"
- "prometheus.scrape=true"
- "prometheus.port=8000"
- "prometheus.path=/metrics"
# Prometheus pour le monitoring
prometheus:
image: prom/prometheus:v2.47.2
container_name: devops-prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- 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:
- devops-network
restart: unless-stopped
depends_on:
- app
# Grafana pour les dashboards
grafana:
image: grafana/grafana:10.2.0
container_name: devops-grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin123
- GF_SECURITY_ADMIN_USER=admin
- GF_INSTALL_PLUGINS=grafana-piechart-panel,grafana-clock-panel
- GF_USERS_ALLOW_SIGN_UP=false
- GF_SERVER_DOMAIN=localhost
volumes:
- grafana-data:/var/lib/grafana
- ./grafana-dashboards:/etc/grafana/provisioning/dashboards
- ./grafana-datasources:/etc/grafana/provisioning/datasources
networks:
- devops-network
restart: unless-stopped
depends_on:
- prometheus
# Portainer pour gérer Docker
portainer:
image: portainer/portainer-ce:2.19.3
container_name: devops-portainer
ports:
- "9000:9000"
- "9443:9443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- portainer-data:/data
networks:
- devops-network
restart: unless-stopped
command: -H unix:///var/run/docker.sock
# Nginx comme reverse proxy (optionnel)
nginx:
image: nginx:alpine
container_name: devops-nginx
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
networks:
- devops-network
restart: unless-stopped
depends_on:
- app
networks:
devops-network:
driver: bridge
name: devops-network
volumes:
prometheus-data:
name: prometheus-data
grafana-data:
name: grafana-data
portainer-data:
name: portainer-data
app-logs:
name: app-logs
#4.2 Fichier : docker\prometheus.yml (À CRÉER)
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: 'windows-devops'
environment: 'development'
# Règles d'alerte
rule_files:
# - "alerts.yml"
# Configuration de scraping
scrape_configs:
# Scraper l'application FastAPI
- job_name: 'fastapi-app'
static_configs:
- targets: ['app:8000']
labels:
app: 'devops-app'
component: 'backend'
tier: 'application'
# Scraper Prometheus lui-même
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
labels:
component: 'monitoring'
# Découverte de service Docker
- job_name: 'docker'
static_configs:
- targets: ['host.docker.internal:9323']
metrics_path: /metrics
scheme: http
# Alerting (exemple)
# alerting:
# alertmanagers:
# - static_configs:
# - targets: []
#4.3 Exécution Docker Compose :
# Se placer dans le dossier docker
cd C:\DevOpsProject\docker
# Lancer en arrière-plan
docker-compose up -d
# Vérifier que tout fonctionne
docker-compose ps
# Voir les logs de l'application
docker-compose logs app
# Tester l'application
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 :
1. Docker Desktop → Settings (roue crantée)
2. Onglet Kubernetes
3. ✅ Enable Kubernetes
4. ✅ Show system containers (optional)
5. Apply & Restart (patienter 2-3 minutes)
#5.2 Vérification :
# Vérifier que Kubernetes fonctionne
kubectl cluster-info
# Doit afficher : Kubernetes control plane is running at https://...
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
apiVersion: v1
kind: Namespace
metadata:
name: devops-demo
labels:
name: devops-demo
environment: development
#5.4 Fichier : kubernetes\manifests\configmap.yaml (NOUVEAU)
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: devops-demo
data:
ENV: "production"
APP_NAME: "devops-windows-app"
LOG_LEVEL: "INFO"
PYTHONUNBUFFERED: "1"
#5.5 Fichier : kubernetes\manifests\deployment.yaml (SIMPLIFIÉ)
apiVersion: apps/v1
kind: Deployment
metadata:
name: devops-app
namespace: devops-demo
labels:
app: devops-app
version: v1
spec:
replicas: 2
selector:
matchLabels:
app: devops-app
template:
metadata:
labels:
app: devops-app
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8000"
prometheus.io/path: "/metrics"
spec:
containers:
- name: app
image: devops-app:local # IMPORTANT : Utiliser l'image locale
imagePullPolicy: IfNotPresent # Ne pas pull depuis Docker Hub
ports:
- containerPort: 8000
name: http
envFrom:
- configMapRef:
name: app-config
env:
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: metadata.name
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 15
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
name: devops-app-service
namespace: devops-demo
spec:
selector:
app: devops-app
ports:
- port: 80
targetPort: 8000
protocol: TCP
name: http
type: NodePort # CORRIGÉ : NodePort au lieu de LoadBalancer pour Windows
#5.6 Déploiement Kubernetes :
# 1. Build l'image Docker avec un tag spécifique
cd C:\DevOpsProject\src\app
docker build -t devops-app:local .
# 2. Appliquer les manifests Kubernetes
cd C:\DevOpsProject\kubernetes\manifests
# Dans l'ordre :
kubectl apply -f namespace.yaml
kubectl apply -f configmap.yaml
kubectl apply -f deployment.yaml
# 3. Vérifier le déploiement
kubectl get all -n devops-demo
# 4. Obtenir l'URL d'accès
kubectl get svc -n devops-demo devops-app-service -o jsonpath='{.spec.ports[0].nodePort}'
# Notez le numéro de port (ex: 30456)
# 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 :
#6.1 Fichier : terraform\main.tf (VERSION SIMPLIFIÉE)
# Terraform minimal pour Windows - KUBERNETES UNIQUEMENT
terraform {
required_version = ">= 1.5.0"
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.23"
}
}
}
# Provider Kubernetes avec Docker Desktop
provider "kubernetes" {
config_path = "~/.kube/config"
config_context = "docker-desktop"
}
# Namespace
resource "kubernetes_namespace" "devops" {
metadata {
name = "terraform-ns"
labels = {
created-by = "terraform"
environment = "development"
}
}
}
# Déploiement simple
resource "kubernetes_deployment" "app" {
metadata {
name = "terraform-app"
namespace = kubernetes_namespace.devops.metadata[0].name
labels = {
app = "terraform-app"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "terraform-app"
}
}
template {
metadata {
labels = {
app = "terraform-app"
}
}
spec {
container {
name = "app"
image = "nginx:alpine" # Image simple pour test
port {
container_port = 80
}
resources {
limits = {
cpu = "100m"
memory = "128Mi"
}
requests = {
cpu = "50m"
memory = "64Mi"
}
}
}
}
}
}
depends_on = [kubernetes_namespace.devops]
}
# Service
resource "kubernetes_service" "app" {
metadata {
name = "terraform-service"
namespace = kubernetes_namespace.devops.metadata[0].name
}
spec {
selector = {
app = kubernetes_deployment.app.spec[0].template[0].metadata[0].labels.app
}
port {
port = 8080
target_port = 80
}
type = "NodePort"
}
}
# Output utile
output "application_url" {
value = "http://localhost:${kubernetes_service.app.spec[0].port[0].node_port}"
}
output "namespace" {
value = kubernetes_namespace.devops.metadata[0].name
}
#6.2 Utilisation Terraform :
cd C:\DevOpsProject\terraform
# Initialiser
terraform init
# Voir ce qui va être créé
terraform plan
# Appliquer (tapez 'yes' quand demandé)
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
# Créer un chart Helm
helm create devops-chart
# Supprimer les fichiers inutiles créés par défaut
Remove-Item devops-chart\templates\* -Recurse -Force
# Créer une structure propre
New-Item -ItemType Directory -Path @(
"devops-chart\templates",
"devops-chart\charts"
)
#7.2 Fichier : kubernetes\helm\devops-chart\Chart.yaml
apiVersion: v2
name: devops-chart
description: Chart Helm pour DevOps Windows
type: application
version: 0.1.0
appVersion: "1.0.0"
#7.3 Fichier : kubernetes\helm\devops-chart\values.yaml
# Configuration de l'application
app:
name: "devops-helm-app"
image:
repository: "devops-app"
tag: "local"
pullPolicy: "IfNotPresent"
replicaCount: 2
service:
type: NodePort
port: 80
targetPort: 8000
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
env:
ENV: "production"
LOG_LEVEL: "INFO"
# Monitoring
monitoring:
enabled: true
prometheusScrape: true
#7.4 Fichier : kubernetes\helm\devops-chart\templates\deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.app.name }}
labels:
app: {{ .Values.app.name }}
chart: {{ .Chart.Name }}
version: {{ .Chart.Version }}
spec:
replicas: {{ .Values.app.replicaCount }}
selector:
matchLabels:
app: {{ .Values.app.name }}
template:
metadata:
labels:
app: {{ .Values.app.name }}
{{- if .Values.monitoring.enabled }}
annotations:
prometheus.io/scrape: "{{ .Values.monitoring.prometheusScrape }}"
prometheus.io/port: "{{ .Values.app.service.targetPort }}"
prometheus.io/path: "/metrics"
{{- end }}
spec:
containers:
- name: {{ .Values.app.name }}
image: "{{ .Values.app.image.repository }}:{{ .Values.app.image.tag }}"
imagePullPolicy: {{ .Values.app.image.pullPolicy }}
ports:
- containerPort: {{ .Values.app.service.targetPort }}
name: http
env:
{{- range $key, $value := .Values.app.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
resources:
{{- toYaml .Values.app.resources | nindent 10 }}
readinessProbe:
httpGet:
path: /health
port: {{ .Values.app.service.targetPort }}
initialDelaySeconds: 10
periodSeconds: 15
#7.5 Installation avec Helm :
cd C:\DevOpsProject\kubernetes\helm
# Installer le chart
helm install devops-release ./devops-chart -n devops-demo --create-namespace
# Vérifier l'installation
helm list -n devops-demo
# Mettre à jour
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
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
workflow_dispatch: # Permet de déclencher manuellement
jobs:
# Job 1 : Tests de l'application
test:
runs-on: windows-latest
steps:
- name: Checkout du code
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r src/app/requirements.txt
- name: Run tests
run: |
cd src/app
python -m pytest tests/ -v --cov=. --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./src/app/coverage.xml
flags: unittests
# Job 2 : Build Docker
build:
needs: test
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub (seulement sur main)
if: github.ref == 'refs/heads/main'
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker image
uses: docker/build-push-action@v4
with:
context: ./src/app
push: ${{ github.ref == 'refs/heads/main' }}
tags: |
${{ secrets.DOCKER_USERNAME }}/devops-app:latest
${{ secrets.DOCKER_USERNAME }}/devops-app:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Job 3 : Déploiement (optionnel pour Windows)
deploy:
needs: build
runs-on: windows-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Setup kubectl
uses: azure/setup-kubectl@v3
with:
version: 'latest'
- name: Configure kubeconfig
run: |
# Pour une vraie installation, configurez votre kubeconfig ici
# Pour la démo, on affiche juste un message
echo "Dans un environnement réel, vous configureriez kubeconfig ici"
echo "Utilisez des secrets GitHub pour stocker votre configuration"
- name: Deploy to Kubernetes
run: |
echo "Déploiement simulé"
echo "En production, vous utiliseriez :"
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
mkdir C:\DevOpsProject\docker\grafana-dashboards
# Créer un fichier de dashboard simple
@'
{
"dashboard": {
"title": "DevOps Windows Dashboard",
"panels": [
{
"title": "Requêtes HTTP",
"type": "graph",
"targets": [{
"expr": "rate(http_requests_total[5m])",
"legendFormat": "{{method}} {{endpoint}}"
}]
},
{
"title": "Latence",
"type": "graph",
"targets": [{
"expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))",
"legendFormat": "p95"
}]
}
]
}
}
'@ | Out-File -FilePath "C:\DevOpsProject\docker\grafana-dashboards\dashboard.json" -Encoding UTF8
#9.2 Accès aux interfaces :
✅ Après docker-compose up -d :
1. Application FastAPI : http://localhost:8000
2. Documentation API : http://localhost:8000/docs (Swagger UI)
3. Métriques Prometheus : http://localhost:9090
4. Grafana Dashboard : http://localhost:3000
→ Login : admin / admin123
5. Portainer : http://localhost:9000
✅ Après déploiement Kubernetes :
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
# PowerShell 5.1+ requis
param(
[switch]$SkipDocker = $false,
[switch]$SkipK8s = $false,
[switch]$Help = $false
)
if ($Help) {
Write-Host "Usage: .\setup.ps1 [-SkipDocker] [-SkipK8s] [-Help]" -ForegroundColor Cyan
Write-Host " -SkipDocker : Ne pas démarrer Docker Compose" -ForegroundColor Gray
Write-Host " -SkipK8s : Ne pas déployer sur Kubernetes" -ForegroundColor Gray
Write-Host " -Help : Afficher cette aide" -ForegroundColor Gray
exit 0
}
Write-Host "========================================" -ForegroundColor Green
Write-Host " DEVOPS WINDOWS SETUP" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""
# 1. Vérification des outils
Write-Host "[1/5] Vérification des outils..." -ForegroundColor Yellow
$tools = @(
@{Name="Docker"; Cmd="docker --version"},
@{Name="kubectl"; Cmd="kubectl version --client"},
@{Name="helm"; Cmd="helm version"},
@{Name="python"; Cmd="python --version"}
)
foreach ($tool in $tools) {
try {
$output = Invoke-Expression $tool.Cmd 2>&1
Write-Host " ✅ $($tool.Name) : OK" -ForegroundColor Green
} catch {
Write-Host " ❌ $($tool.Name) : MANQUANT" -ForegroundColor Red
Write-Host " Installez avec: choco install $($tool.Name.ToLower())" -ForegroundColor Gray
}
}
Write-Host ""
# 2. Build de l'application
Write-Host "[2/5] Build de l'application Docker..." -ForegroundColor Yellow
try {
Set-Location "$PSScriptRoot\..\src\app"
docker build -t devops-app:local .
Write-Host " ✅ Image Docker construite" -ForegroundColor Green
Set-Location $PSScriptRoot
} catch {
Write-Host " ❌ Erreur lors du build Docker" -ForegroundColor Red
Write-Host $_.Exception.Message
exit 1
}
# 3. Docker Compose
if (-not $SkipDocker) {
Write-Host "[3/5] Démarrage Docker Compose..." -ForegroundColor Yellow
try {
Set-Location "$PSScriptRoot\..\docker"
# Arrêter si déjà en cours
docker-compose down 2>$null
# Démarrer
docker-compose up -d
# Attendre que les services soient prêts
Start-Sleep -Seconds 10
Write-Host " ✅ Docker Compose démarré" -ForegroundColor Green
Write-Host " Attente supplémentaire pour les services..." -ForegroundColor Gray
# Vérifier l'application
$attempts = 0
$maxAttempts = 6
while ($attempts -lt $maxAttempts) {
try {
$response = Invoke-WebRequest -Uri "http://localhost:8000/health" -UseBasicParsing -TimeoutSec 5
if ($response.StatusCode -eq 200) {
Write-Host " ✅ Application accessible" -ForegroundColor Green
break
}
} catch {
$attempts++
Write-Host " ⏳ Tentative $attempts/$maxAttempts..." -ForegroundColor Yellow
Start-Sleep -Seconds 10
if ($attempts -eq $maxAttempts) {
Write-Host " ⚠️ Application lente à démarrer" -ForegroundColor Yellow
}
}
}
Set-Location $PSScriptRoot
} catch {
Write-Host " ⚠️ Erreur Docker Compose : $($_.Exception.Message)" -ForegroundColor Yellow
Set-Location $PSScriptRoot
}
}
# 4. Kubernetes
if (-not $SkipK8s) {
Write-Host "[4/5] Déploiement Kubernetes..." -ForegroundColor Yellow
try {
Set-Location "$PSScriptRoot\..\kubernetes\manifests"
# Vérifier que Kubernetes est activé
$k8sContext = kubectl config current-context 2>$null
if ($LASTEXITCODE -ne 0) {
Write-Host " Kubernetes non configuré, passage au mode Docker uniquement" -ForegroundColor Yellow
} else {
# Appliquer les manifests
kubectl apply -f namespace.yaml
kubectl apply -f configmap.yaml
kubectl apply -f deployment.yaml
Write-Host " ✅ Déploiement Kubernetes terminé" -ForegroundColor Green
# Obtenir les infos
$service = kubectl get svc -n devops-demo devops-app-service -o json | ConvertFrom-Json
$nodePort = $service.spec.ports[0].nodePort
Write-Host " Accès K8s : http://localhost:$nodePort" -ForegroundColor Cyan
}
Set-Location $PSScriptRoot
} catch {
Write-Host " ⚠️ Erreur Kubernetes : $($_.Exception.Message)" -ForegroundColor Yellow
Set-Location $PSScriptRoot
}
}
Write-Host "[5/5] Récapitulatif..." -ForegroundColor Yellow
Write-Host ""
Write-Host "========================================" -ForegroundColor Green
Write-Host " SETUP TERMINÉ !" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""
Write-Host "🌐 ACCèS AUX SERVICES :" -ForegroundColor White
Write-Host ""
Write-Host " 📊 Application FastAPI :" -ForegroundColor Cyan
Write-Host " • Interface : http://localhost:8000" -ForegroundColor Gray
Write-Host " • Health : http://localhost:8000/health" -ForegroundColor Gray
Write-Host " • Docs : http://localhost:8000/docs" -ForegroundColor Gray
Write-Host " • Métriques : http://localhost:8000/metrics" -ForegroundColor Gray
Write-Host ""
Write-Host " 📈 Monitoring :" -ForegroundColor Cyan
Write-Host " • Prometheus : http://localhost:9090" -ForegroundColor Gray
Write-Host " • Grafana : http://localhost:3000" -ForegroundColor Gray
Write-Host " Login : admin / admin123" -ForegroundColor DarkGray
Write-Host ""
Write-Host " 🐳 Gestion Docker :" -ForegroundColor Cyan
Write-Host " • Portainer : http://localhost:9000" -ForegroundColor Gray
Write-Host ""
if (-not $SkipK8s) {
Write-Host " ☸️ Kubernetes :" -ForegroundColor Cyan
Write-Host " • Vérifier : kubectl get pods -n devops-demo" -ForegroundColor Gray
Write-Host " • Logs : kubectl logs -f -n devops-demo -l app=devops-app" -ForegroundColor Gray
}
Write-Host ""
Write-Host "🔧 COMMANDES UTILES :" -ForegroundColor White
Write-Host " * Voir les logs : docker-compose logs -f [app|prometheus|grafana]" -ForegroundColor DarkGray
Write-Host " * Arrêter tout : docker-compose down" -ForegroundColor DarkGray
Write-Host " * Nettoyer : docker system prune -a -f --volumes" -ForegroundColor DarkGray
Write-Host ""
Write-Host "💡 CONSEIL :" -ForegroundColor Yellow
Write-Host " Testez avec : curl http://localhost:8000 ou dans PowerShell :" -ForegroundColor Gray
Write-Host " Invoke-WebRequest -Uri 'http://localhost:8000' -UseBasicParsing" -ForegroundColor DarkGray
Write-Host ""
# Test automatique
try {
$test = Invoke-WebRequest -Uri "http://localhost:8000/health" -UseBasicParsing -TimeoutSec 5
if ($test.StatusCode -eq 200) {
Write-Host "✅ Test de santé réussi !" -ForegroundColor Green
}
} catch {
Write-Host "⚠️ L'application n'est pas encore accessible, patientez..." -ForegroundColor Yellow
}
#10.2 Script : scripts\cleanup.ps1 (COMPLET)
# Nettoyage complet DevOps Stack
Write-Host "🧹 NETTOYAGE DEVOPS STACK" -ForegroundColor Yellow
Write-Host "==========================" -ForegroundColor Yellow
Write-Host ""
# 1. Arrêter Docker Compose
Write-Host "[1/4] Arrêt Docker Compose..." -ForegroundColor Yellow
try {
if (Test-Path "..\docker\docker-compose.yml") {
Set-Location "..\docker"
docker-compose down -v # -v pour supprimer les volumes
Write-Host " ✅ Docker Compose arrêté" -ForegroundColor Green
Set-Location $PSScriptRoot
}
} catch {
Write-Host " ⚠️ Aucun service Docker Compose en cours" -ForegroundColor Gray
}
# 2. Nettoyer Kubernetes
Write-Host "[2/4] Nettoyage Kubernetes..." -ForegroundColor Yellow
try {
# Supprimer le namespace (supprime tout à l'intérieur)
kubectl delete namespace devops-demo --ignore-not-found=true
kubectl delete namespace terraform-ns --ignore-not-found=true
# Désinstaller Helm
helm uninstall devops-release --namespace devops-demo --ignore-not-found=true
Write-Host " ✅ Kubernetes nettoyé" -ForegroundColor Green
} catch {
Write-Host " ⚠️ Kubernetes non configuré ou déjà nettoyé" -ForegroundColor Gray
}
# 3. Nettoyer Docker
Write-Host "[3/4] Nettoyage Docker..." -ForegroundColor Yellow
try {
# Arrêter tous les conteneurs
docker stop $(docker ps -aq) 2>$null
# Supprimer tous les conteneurs
docker rm $(docker ps -aq) 2>$null
# Supprimer toutes les images
docker rmi $(docker images -q) -f 2>$null
# Nettoyer le système
docker system prune -a -f --volumes
Write-Host " ✅ Docker nettoyé" -ForegroundColor Green
} catch {
Write-Host " Aucune ressource Docker à nettoyer" -ForegroundColor Gray
}
# 4. Nettoyer Terraform
Write-Host "[4/4] Nettoyage Terraform..." -ForegroundColor Yellow
try {
if (Test-Path "..\terraform") {
Set-Location "..\terraform"
# Détruire l'infrastructure si terraform.tfstate existe
if (Test-Path "terraform.tfstate") {
terraform destroy -auto-approve 2>$null
}
# Supprimer les fichiers temporaires
Remove-Item -Path "*.tfstate*", ".terraform*", "terraform.tfstate.backup" -Force -ErrorAction SilentlyContinue
Write-Host " ✅ Terraform nettoyé" -ForegroundColor Green
Set-Location $PSScriptRoot
}
} catch {
Write-Host " Terraform non configuré" -ForegroundColor Gray
}
Write-Host ""
Write-Host "========================================" -ForegroundColor Green
Write-Host " NETTOYAGE TERMINÉ !" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""
Write-Host "✅ Toutes les ressources ont été nettoyées" -ForegroundColor Green
Write-Host ""
Write-Host "Pour recommencer :" -ForegroundColor Cyan
Write-Host " .\setup.ps1" -ForegroundColor Gray
#🎯 VALIDATION FINALE
#Testez votre installation :
# 1. Lancer le setup
cd C:\DevOpsProject\scripts
.\setup.ps1
# 2. Tester chaque service
# Application
curl http://localhost:8000
# ou
Invoke-WebRequest -Uri "http://localhost:8000" -UseBasicParsing | Select-Object -ExpandProperty Content
# Health check
curl http://localhost:8000/health
# Métriques Prometheus
curl http://localhost:8000/metrics
# 3. Vérifier Docker
docker ps
docker-compose ps
# 4. Vérifier Kubernetes
kubectl get pods --all-namespaces
kubectl get svc -n devops-demo
# 5. Accéder aux interfaces web
# Ouvrez votre navigateur et allez sur :
# - http://localhost:8000 (App)
# - http://localhost:8000/docs (Documentation API)
# - http://localhost:9090 (Prometheus)
# - http://localhost:3000 (Grafana - admin/admin123)
# - http://localhost:9000 (Portainer)
#Problèmes courants et solutions :
Problème
Solution
WSL2 ne démarre pas
wsl --shutdown puis redémarrer Docker Desktop
Docker Desktop ne démarre pas
Vérifier Hyper-V dans "Fonctionnalités Windows"
Port déjà utilisé
`netstat -ano
kubectl non reconnu
Réinstaller : choco install kubernetes-cli -y
Prometheus ne scrape pas
Vérifier docker\prometheus.yml et les labels
Application inaccessible
Vérifier les logs : docker-compose logs app
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 :
PS C:\DevOpsProject\docker> docker-compose ps
"....Found orphan containers ([gitea logstash kibana filebeat elasticsearch devops-db])...."
# 6. Pour aller plus loin :
- Ajouter une base de données (PostgreSQL)
- Implémenter un vrai pipeline CI/CD avec déploiement automatique
- Ajouter du logging centralisé (ELK Stack)
- Configurer des alertes Prometheus
# Commentaire de Oualim
# 7. Basculer sur kubernets (découverte nodes & pods)
- Mettre en place du GitOps avec ArgoCD
- Configurer HTTPS avec un reverse proxy
# Commentaire de Oualim
# 8. Simuler une prod qu'on pourrait relancer en 5mn from scratch après un reset du cluster k8' ou une réinstall de docker desktop
- Créer des scripts regroupant tous les démarrages pour :
- les dockers (Deploy.ctnrs.ps1)
- les pods (deploy.Pods.ps1)
- créer le dashbord et générer le kubeconfig (dashboard.kubeconfig) pour s'y connecter (GnrkbCfOpnDash.ps1)
- créer argo et lancer la page web de connexion avec id et mdp (start-argocd.ps1)