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

41 KiB
Raw 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)

  1. Activer les fonctionnalités Windows nécessaires
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
  1. Installer WSL2 et Ubuntu
wsl --install -d Ubuntu-22.04
  1. Définir WSL2 comme version par défaut
wsl --set-default-version 2
  1. 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
  1. 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)