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

42 KiB
Raw Permalink Blame History

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 :

🚀 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)

#🚀 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

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'))
  1. 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

# 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
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É)

## 🐳 É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 :

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 :

### 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

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)

### 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É)

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 #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])...." 




# 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)