41 KiB
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)
- Activer les fonctionnalités Windows nécessaires
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
- Installer WSL2 et Ubuntu
wsl --install -d Ubuntu-22.04
- Définir WSL2 comme version par défaut
wsl --set-default-version 2
- Redémarrer l'ordinateur (OBLIGATOIRE)
Restart-Computer
📥 2. Installation des outils (après redémarrage)
- 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'))
- Installer tous les outils
choco install -y git docker-desktop vscode kubernetes-cli minikube terraform helm postman
- 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
ou dans PowerShell
Invoke-WebRequest -Uri "http://localhost:8000" -UseBasicParsing #☸️ ÉTAPE 5 : KUBERNETES SIMPLIFIÉ POUR WINDOWS #5.1 Activer Kubernetes dans Docker Desktop :
- Docker Desktop → Settings (roue crantée)
- Onglet Kubernetes
- ✅ Enable Kubernetes
- ✅ Show system containers (optional)
- 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 :
- Application FastAPI : http://localhost:8000
- Documentation API : http://localhost:8000/docs (Swagger UI)
- Métriques Prometheus : http://localhost:9090
- Grafana Dashboard : http://localhost:3000 → Login : admin / admin123
- Portainer : http://localhost:9000
✅ Après déploiement Kubernetes :
- 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
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)