-
Notifications
You must be signed in to change notification settings - Fork 0
TP9 cmd
PasRP-Theo edited this page Jun 5, 2025
·
2 revisions
# Se connecter avec votre token
docker login -u pasrptheoo
# À l'invite du mot de passe, entrez : dckr_pat__qNuhqj21A4HFR2FlHMiKTYa3DYLa directive build dans docker-compose.yml ne fonctionne pas avec Docker Swarm car :
- Swarm est distribué : Les nœuds du swarm n'ont pas accès au contexte de build local
- Images pré-construites requises : Swarm nécessite des images déjà construites et disponibles dans un registry
- Sécurité : Évite l'exécution de builds sur les nœuds de production
# docker-compose-dev.yml
version: '3.8'
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
depends_on:
- backend
backend:
build: ./backend
ports:
- "5000:5000"
depends_on:
- database
environment:
- DATABASE_URL=postgresql://user:password@database:5432/woodytoys
database:
image: postgres:13
environment:
POSTGRES_DB: woodytoys
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db_data:/var/lib/postgresql/data
ports:
- "5432:5432"
volumes:
db_data:#!/bin/bash
# build_push.sh
# Configuration
DOCKER_USER="pasrptheoo"
PROJECT_NAME="woodytoys"
TAG="latest"
# Build et push frontend
echo "Building frontend..."
docker build -t ${DOCKER_USER}/${PROJECT_NAME}-frontend:${TAG} ./frontend
docker push ${DOCKER_USER}/${PROJECT_NAME}-frontend:${TAG}
# Build et push backend
echo "Building backend..."
docker build -t ${DOCKER_USER}/${PROJECT_NAME}-backend:${TAG} ./backend
docker push ${DOCKER_USER}/${PROJECT_NAME}-backend:${TAG}
echo "All images pushed successfully!"# docker-compose-stack.yml
version: '3.8'
services:
frontend:
image: pasrptheoo/woodytoys-frontend:latest
ports:
- "3000:3000"
deploy:
replicas: 2
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
placement:
constraints:
- node.role == worker
depends_on:
- backend
networks:
- woodytoys-network
backend:
image: pasrptheoo/woodytoys-backend:latest
ports:
- "5000:5000"
deploy:
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
placement:
constraints:
- node.role == worker
depends_on:
- database
environment:
- DATABASE_URL=postgresql://user:password@database:5432/woodytoys
networks:
- woodytoys-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 30s
timeout: 10s
retries: 3
database:
image: postgres:13
environment:
POSTGRES_DB: woodytoys
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db_data:/var/lib/postgresql/data
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints:
- node.role == manager
networks:
- woodytoys-network
volumes:
db_data:
networks:
woodytoys-network:
driver: overlay# Déployer la stack
docker stack deploy -c docker-compose-stack.yml woodytoys-l2-2
# Vérifier le déploiement
docker stack services woodytoys-l2-2
docker stack ps woodytoys-l2-2# Test de performance basique
time wget -r http://votre-url-swarm
# Test avec curl (plus détaillé)
curl -w "@curl-format.txt" -o /dev/null -s http://votre-url-swarm
# Monitoring en temps réel
watch docker service lsCréez le fichier curl-format.txt :
time_namelookup: %{time_namelookup}\n
time_connect: %{time_connect}\n
time_appconnect: %{time_appconnect}\n
time_pretransfer: %{time_pretransfer}\n
time_redirect: %{time_redirect}\n
time_starttransfer: %{time_starttransfer}\n
----------\n
time_total: %{time_total}\n
# Augmenter les replicas sans arrêter le service
docker service scale woodytoys-l2-2_backend=5
docker service scale woodytoys-l2-2_frontend=4
# Vérifier la mise à l'échelle
docker service ps woodytoys-l2-2_backend# Ajouter ce service à docker-compose-stack.yml
redis:
image: redis:7-alpine
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints:
- node.role == manager
networks:
- woodytoys-network
command: redis-server --appendonly yes
volumes:
- redis_data:/data
# Ajouter aux volumes
volumes:
db_data:
redis_data:# backend/cache.py
import redis
import json
import functools
from flask import current_app
def get_redis_client():
return redis.Redis(host='redis', port=6379, db=0, decode_responses=True)
def cache_aside(expiration=300):
"""
Décorateur pour implémenter le pattern Cache Aside
"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Générer une clé unique basée sur la fonction et ses arguments
cache_key = f"{func.__name__}:{hash(str(args) + str(kwargs))}"
r = get_redis_client()
# Essayer de récupérer depuis le cache
cached_result = r.get(cache_key)
if cached_result:
current_app.logger.info(f"Cache HIT for {cache_key}")
return json.loads(cached_result)
# Cache MISS - exécuter la fonction
current_app.logger.info(f"Cache MISS for {cache_key}")
result = func(*args, **kwargs)
# Mettre en cache le résultat
r.setex(cache_key, expiration, json.dumps(result, default=str))
return result
return wrapper
return decorator
# Exemple d'utilisation dans votre API
@app.route('/api/products')
@cache_aside(expiration=60) # Cache pendant 1 minute
def get_products():
# Simulation d'une requête coûteuse
products = db.execute("SELECT * FROM products").fetchall()
return [dict(product) for product in products]# backend/app.py (exemple d'intégration)
from flask import Flask, jsonify
import redis
import time
import psycopg2
from cache import cache_aside, get_redis_client
app = Flask(__name__)
@app.route('/health')
def health_check():
return jsonify({"status": "healthy"}), 200
@app.route('/api/products')
@cache_aside(expiration=60)
def get_products():
# Simulation du throttling artificiel
time.sleep(0.5) # Ne pas supprimer - limitation volontaire
# Requête à la base de données
# ... votre logique métier ici
return {"products": ["toy1", "toy2", "toy3"]}
@app.route('/api/cache/stats')
def cache_stats():
"""Endpoint pour monitorer les statistiques du cache"""
r = get_redis_client()
info = r.info()
return jsonify({
"keyspace_hits": info.get("keyspace_hits", 0),
"keyspace_misses": info.get("keyspace_misses", 0),
"used_memory": info.get("used_memory_human", "0B"),
"connected_clients": info.get("connected_clients", 0)
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)-
Inscription sur GCore : Créez un compte sur https://gcore.com
-
Création d'un CDN Resource :
- Origin :
http://votre-domaine-swarm - CNAME :
cdn-woodytoys.votre-domaine.com
- Origin :
-
Configuration DNS :
# Ajoutez ce CNAME à votre zone DNS
cdn-woodytoys.l2-2.votre-domaine.com CNAME cl-xyz.gcdn.co
<!-- frontend/public/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>WoodyToys</title>
<!-- Ressources statiques via CDN -->
<link rel="stylesheet" href="https://cdn-woodytoys.l2-2.votre-domaine.com/css/style.css">
<script src="https://cdn-woodytoys.l2-2.votre-domaine.com/js/app.js"></script>
</head>
<body>
<!-- Contenu de votre application -->
<div id="app">
<img src="https://cdn-woodytoys.l2-2.votre-domaine.com/images/logo.png" alt="WoodyToys">
</div>
</body>
</html>#!/bin/bash
# performance_test.sh
URL="http://votre-swarm-url"
RESULTS_DIR="./performance_results"
mkdir -p $RESULTS_DIR
echo "=== Test de Performance WoodyToys ==="
date > $RESULTS_DIR/test_$(date +%Y%m%d_%H%M%S).log
# Test sans cache
echo "Test sans cache..." | tee -a $RESULTS_DIR/test_$(date +%Y%m%d_%H%M%S).log
for i in {1..10}; do
curl -w "%{time_total}\n" -o /dev/null -s $URL/api/products
done | awk '{sum+=$1; n++} END {print "Temps moyen:", sum/n, "secondes"}' | tee -a $RESULTS_DIR/test_$(date +%Y%m%d_%H%M%S).log
# Test avec cache (après warmup)
echo "Test avec cache..." | tee -a $RESULTS_DIR/test_$(date +%Y%m%d_%H%M%S).log
curl -s $URL/api/products > /dev/null # Warmup
for i in {1..10}; do
curl -w "%{time_total}\n" -o /dev/null -s $URL/api/products
done | awk '{sum+=$1; n++} END {print "Temps moyen:", sum/n, "secondes"}' | tee -a $RESULTS_DIR/test_$(date +%Y%m%d_%H%M%S).log
# Test de charge avec ab (Apache Bench)
echo "Test de charge concurrent..." | tee -a $RESULTS_DIR/test_$(date +%Y%m%d_%H%M%S).log
ab -n 100 -c 10 $URL/ | tee -a $RESULTS_DIR/test_$(date +%Y%m%d_%H%M%S).log# Monitoring des services
docker service logs woodytoys-l2-2_backend
docker service logs woodytoys-l2-2_redis
# Stats détaillées
docker stats $(docker ps -q --filter "label=com.docker.swarm.service.name=woodytoys-l2-2_backend")# Dans le service backend
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
interval: 15s
timeout: 5s
retries: 3
start_period: 30s# Placement stratégique des services
backend:
deploy:
placement:
constraints:
- node.role == worker
- node.labels.performance == high
preferences:
- spread: node.labels.zone
database:
deploy:
placement:
constraints:
- node.role == manager # Base de données sur manager pour stabilité
- node.labels.storage == ssd# Ajout d'un load balancer dédié
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
configs:
- source: nginx_config
target: /etc/nginx/nginx.conf
deploy:
replicas: 2
placement:
constraints:
- node.role == manager
configs:
nginx_config:
external: trueDescription : Configuration d'une base de données principale pour les écritures et de plusieurs répliques en lecture seule.
Avantages :
- Répartition de la charge de lecture
- Amélioration des performances pour les requêtes SELECT
- Haute disponibilité
Inconvénients :
- Complexité de configuration
- Latence de réplication
- Cohérence éventuelle des données
Configuration Docker :
db-master:
image: postgres:13
environment:
POSTGRES_REPLICATION_USER: replicator
POSTGRES_REPLICATION_PASSWORD: secret
command: |
postgres
-c wal_level=replica
-c max_wal_senders=3
-c max_replication_slots=3
db-slave:
image: postgres:13
environment:
PGUSER: postgres
POSTGRES_MASTER_SERVICE: db-master
command: |
bash -c "
pg_basebackup -h db-master -D /var/lib/postgresql/data -U replicator -v -P -W
postgres -c hot_standby=on"Description : Division des données en plusieurs bases selon une clé de partitionnement.
Avantages :
- Scalabilité horizontale infinie
- Isolation des données
- Performance améliorée pour les requêtes ciblées
Inconvénients :
- Complexité applicative
- Requêtes cross-shard difficiles
- Gestion des clés de partitionnement
Configuration avec PgBouncer :
pgbouncer:
image: pgbouncer/pgbouncer:latest
environment:
DATABASES_HOST: database
DATABASES_PORT: 5432
DATABASES_USER: user
DATABASES_PASSWORD: password
DATABASES_DBNAME: woodytoys
POOL_MODE: transaction
MAX_CLIENT_CONN: 100
DEFAULT_POOL_SIZE: 20# Résultats des Tests de Performance WoodyToys
## Configuration Initiale
- **Replicas Backend** : 1
- **Replicas Frontend** : 1
- **Cache** : Non activé
- **CDN** : Non configuré
### Métriques Initiales
- Temps de réponse moyen : XXX ms
- Throughput : XXX req/s
- Taux d'erreur : XXX%
## Après Scaling (Replicas)
- **Replicas Backend** : 3
- **Replicas Frontend** : 2
### Métriques après Scaling
- Temps de réponse moyen : XXX ms (-XX%)
- Throughput : XXX req/s (+XX%)
- Taux d'erreur : XXX%
## Après Implémentation Cache Redis
### Métriques avec Cache
- Temps de réponse moyen : XXX ms (-XX%)
- Cache Hit Ratio : XX%
- Réduction charge DB : XX%
## Après CDN
### Métriques avec CDN
- Temps de chargement ressources statiques : XXX ms (-XX%)
- Bande passante économisée : XX%
## Conclusions
[Vos analyses et recommandations]# Mise à jour de la stack
docker stack deploy -c docker-compose-stack.yml woodytoys-l2-2
# Scaling manuel
docker service scale woodytoys-l2-2_backend=5
# Nettoyage
docker stack rm woodytoys-l2-2
docker system prune -f
# Logs et debugging
docker service logs -f woodytoys-l2-2_backend
docker service ps woodytoys-l2-2_backend --no-truncCe guide complet vous permettra de réaliser l'ensemble du TP avec succès. N'oubliez pas de documenter chaque étape et vos observations dans votre wiki !