Guide de déploiement - API Diagramme PH
Déploiement sur AWS Elastic Beanstalk
Prérequis
- Compte AWS avec droits IAM appropriés
- AWS CLI installé et configuré
- EB CLI (Elastic Beanstalk CLI) installé
- Docker installé localement
- Fichiers DLL/SO pour Linux préparés
Installation des outils
# AWS CLI
pip install awscli
aws configure
# EB CLI
pip install awsebcli
# Vérification
aws --version
eb --version
Configuration Docker
Dockerfile (Production)
# docker/Dockerfile
FROM python:3.12-slim
# Variables d'environnement
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1
# Installer dépendances système pour les .so
RUN apt-get update && apt-get install -y \
gcc \
g++ \
libgomp1 \
&& rm -rf /var/lib/apt/lists/*
# Créer utilisateur non-root
RUN useradd -m -u 1000 appuser
# Répertoire de travail
WORKDIR /app
# Copier requirements et installer dépendances Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copier le code de l'application
COPY app/ ./app/
COPY libs/ ./libs/
# Permissions pour fichiers .so
RUN chmod -R 755 libs/so/ && \
chown -R appuser:appuser /app
# Basculer vers utilisateur non-root
USER appuser
# Exposer le port
EXPOSE 8000
# Healthcheck
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD python -c "import requests; requests.get('http://localhost:8000/api/v1/health')"
# Commande de démarrage
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
Dockerfile.dev (Développement)
# docker/Dockerfile.dev
FROM python:3.12-slim
ENV PYTHONUNBUFFERED=1
RUN apt-get update && apt-get install -y \
gcc g++ libgomp1 vim curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt requirements-dev.txt ./
RUN pip install -r requirements.txt -r requirements-dev.txt
COPY . .
RUN chmod -R 755 libs/
EXPOSE 8000
# Mode rechargement automatique pour dev
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
docker-compose.yml (Développement local)
# docker/docker-compose.yml
version: '3.8'
services:
api:
build:
context: ..
dockerfile: docker/Dockerfile.dev
ports:
- "8000:8000"
volumes:
- ../app:/app/app
- ../libs:/app/libs
- ../tests:/app/tests
environment:
- ENV=development
- LOG_LEVEL=DEBUG
- PYTHONPATH=/app
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
# Redis pour cache (optionnel)
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
redis_data:
Configuration AWS Elastic Beanstalk
Dockerrun.aws.json (Single Container)
{
"AWSEBDockerrunVersion": "1",
"Image": {
"Name": "your-ecr-repo/diagram-ph-api:latest",
"Update": "true"
},
"Ports": [
{
"ContainerPort": 8000,
"HostPort": 80
}
],
"Logging": "/var/log/nginx",
"Volumes": [],
"Environment": [
{
"Name": "ENV",
"Value": "production"
},
{
"Name": "LOG_LEVEL",
"Value": "INFO"
}
]
}
.ebextensions/01_packages.config
# deployment/aws/.ebextensions/01_packages.config
packages:
yum:
gcc: []
gcc-c++: []
files:
"/etc/nginx/conf.d/01_timeout.conf":
mode: "000644"
owner: root
group: root
content: |
client_max_body_size 20M;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
container_commands:
01_reload_nginx:
command: "sudo service nginx reload"
.ebextensions/02_python.config
# deployment/aws/.ebextensions/02_python.config
option_settings:
aws:elasticbeanstalk:container:python:
WSGIPath: app.main:app
aws:elasticbeanstalk:application:environment:
PYTHONPATH: "/var/app/current"
aws:elasticbeanstalk:environment:proxy:
ProxyServer: nginx
aws:autoscaling:launchconfiguration:
InstanceType: t3.medium
EC2KeyName: your-key-pair
aws:autoscaling:asg:
MinSize: 2
MaxSize: 10
aws:elasticbeanstalk:cloudwatch:logs:
StreamLogs: true
DeleteOnTerminate: false
RetentionInDays: 7
.ebextensions/03_https_redirect.config
# deployment/aws/.ebextensions/03_https_redirect.config
files:
"/etc/nginx/conf.d/https_redirect.conf":
mode: "000644"
owner: root
group: root
content: |
server {
listen 80;
return 301 https://$host$request_uri;
}
cloudwatch-config.json
{
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/nginx/access.log",
"log_group_name": "/aws/elasticbeanstalk/diagram-ph-api/nginx/access",
"log_stream_name": "{instance_id}"
},
{
"file_path": "/var/log/nginx/error.log",
"log_group_name": "/aws/elasticbeanstalk/diagram-ph-api/nginx/error",
"log_stream_name": "{instance_id}"
},
{
"file_path": "/var/log/eb-docker/containers/eb-current-app/*.log",
"log_group_name": "/aws/elasticbeanstalk/diagram-ph-api/app",
"log_stream_name": "{instance_id}"
}
]
}
}
},
"metrics": {
"namespace": "DiagramPH/API",
"metrics_collected": {
"cpu": {
"measurement": [
{
"name": "cpu_usage_idle",
"rename": "CPU_IDLE",
"unit": "Percent"
}
],
"metrics_collection_interval": 60
},
"mem": {
"measurement": [
{
"name": "mem_used_percent",
"rename": "MEMORY_USED",
"unit": "Percent"
}
],
"metrics_collection_interval": 60
}
}
}
}
Scripts de déploiement
deploy.sh
#!/bin/bash
# deployment/scripts/deploy.sh
set -e # Exit on error
# Configuration
APP_NAME="diagram-ph-api"
ENV_NAME="diagram-ph-api-prod"
REGION="eu-west-1"
ECR_REPO="123456789012.dkr.ecr.eu-west-1.amazonaws.com/diagram-ph-api"
VERSION_LABEL="v$(date +%Y%m%d-%H%M%S)"
echo "🚀 Starting deployment of $APP_NAME..."
# 1. Build Docker image
echo "📦 Building Docker image..."
docker build -f docker/Dockerfile -t $APP_NAME:latest .
# 2. Tag image for ECR
echo "🏷️ Tagging image for ECR..."
docker tag $APP_NAME:latest $ECR_REPO:latest
docker tag $APP_NAME:latest $ECR_REPO:$VERSION_LABEL
# 3. Login to ECR
echo "🔐 Logging in to ECR..."
aws ecr get-login-password --region $REGION | \
docker login --username AWS --password-stdin $ECR_REPO
# 4. Push to ECR
echo "⬆️ Pushing images to ECR..."
docker push $ECR_REPO:latest
docker push $ECR_REPO:$VERSION_LABEL
# 5. Update Dockerrun.aws.json
echo "📝 Updating Dockerrun.aws.json..."
cat > Dockerrun.aws.json << EOF
{
"AWSEBDockerrunVersion": "1",
"Image": {
"Name": "$ECR_REPO:$VERSION_LABEL",
"Update": "true"
},
"Ports": [{"ContainerPort": 8000, "HostPort": 80}],
"Environment": [
{"Name": "ENV", "Value": "production"},
{"Name": "LOG_LEVEL", "Value": "INFO"}
]
}
EOF
# 6. Create application version
echo "📋 Creating application version..."
eb appversion create $VERSION_LABEL \
--source Dockerrun.aws.json \
--label $VERSION_LABEL
# 7. Deploy to Elastic Beanstalk
echo "🎯 Deploying to Elastic Beanstalk..."
eb deploy $ENV_NAME --version $VERSION_LABEL
# 8. Verify deployment
echo "✅ Verifying deployment..."
sleep 30
./deployment/scripts/health_check.sh
echo "✨ Deployment completed successfully!"
echo "Version: $VERSION_LABEL"
echo "Environment: $ENV_NAME"
health_check.sh
#!/bin/bash
# deployment/scripts/health_check.sh
set -e
ENV_NAME="diagram-ph-api-prod"
# Get environment URL
URL=$(eb status $ENV_NAME | grep CNAME | awk '{print $2}')
HEALTH_ENDPOINT="https://$URL/api/v1/health"
echo "🏥 Checking health at $HEALTH_ENDPOINT..."
# Retry logic
MAX_RETRIES=5
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_ENDPOINT)
if [ $HTTP_CODE -eq 200 ]; then
echo "✅ Health check passed (HTTP $HTTP_CODE)"
# Get full response
RESPONSE=$(curl -s $HEALTH_ENDPOINT)
echo "Response: $RESPONSE"
exit 0
else
echo "⚠️ Health check failed (HTTP $HTTP_CODE). Retrying..."
RETRY_COUNT=$((RETRY_COUNT + 1))
sleep 10
fi
done
echo "❌ Health check failed after $MAX_RETRIES retries"
exit 1
rollback.sh
#!/bin/bash
# deployment/scripts/rollback.sh
set -e
ENV_NAME="diagram-ph-api-prod"
echo "⏮️ Rolling back to previous version..."
# Get previous version
PREVIOUS_VERSION=$(eb appversion --query "ApplicationVersions[1].VersionLabel" --output text)
echo "Rolling back to version: $PREVIOUS_VERSION"
# Deploy previous version
eb deploy $ENV_NAME --version $PREVIOUS_VERSION
echo "✅ Rollback completed"
Procédure de déploiement complète
1. Préparation initiale (une seule fois)
# Initialiser EB dans le projet
cd diagram-ph-api
eb init -p docker -r eu-west-1 diagram-ph-api
# Créer l'environnement
eb create diagram-ph-api-prod \
--instance-type t3.medium \
--instance-profile aws-elasticbeanstalk-ec2-role \
--service-role aws-elasticbeanstalk-service-role \
--scale 2 \
--envvars ENV=production,LOG_LEVEL=INFO
# Créer le repository ECR
aws ecr create-repository \
--repository-name diagram-ph-api \
--region eu-west-1
2. Déploiement d'une nouvelle version
# Tester localement
docker-compose -f docker/docker-compose.yml up --build
# Exécuter les tests
pytest tests/
# Déployer
chmod +x deployment/scripts/deploy.sh
./deployment/scripts/deploy.sh
3. Surveillance post-déploiement
# Voir les logs en temps réel
eb logs --stream
# Vérifier le statut
eb status
# Voir les métriques CloudWatch
aws cloudwatch get-metric-statistics \
--namespace DiagramPH/API \
--metric-name APICallDuration \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 300 \
--statistics Average,Maximum \
--region eu-west-1
4. Rollback en cas de problème
chmod +x deployment/scripts/rollback.sh
./deployment/scripts/rollback.sh
Configuration HTTPS avec Certificate Manager
# Demander un certificat SSL
aws acm request-certificate \
--domain-name api.diagramph.com \
--validation-method DNS \
--region eu-west-1
# Configurer le Load Balancer pour utiliser HTTPS
eb config
# Dans la configuration, ajouter:
# aws:elbv2:listener:443:
# Protocol: HTTPS
# SSLCertificateArns: arn:aws:acm:eu-west-1:xxx:certificate/xxx
Auto-scaling configuration
# .ebextensions/04_autoscaling.config
option_settings:
aws:autoscaling:asg:
MinSize: 2
MaxSize: 10
aws:autoscaling:trigger:
MeasureName: CPUUtilization
Statistic: Average
Unit: Percent
UpperThreshold: 70
UpperBreachScaleIncrement: 2
LowerThreshold: 30
LowerBreachScaleIncrement: -1
Coûts estimés (AWS)
Configuration minimale (production)
| Service |
Configuration |
Coût mensuel (approx.) |
| EC2 (2x t3.medium) |
2 vCPU, 4 GB RAM |
~$60 |
| Load Balancer |
Application LB |
~$20 |
| Data Transfer |
100 GB/mois |
~$9 |
| CloudWatch |
Logs + métriques |
~$5 |
| TOTAL |
|
~$94/mois |
Configuration haute disponibilité
| Service |
Configuration |
Coût mensuel (approx.) |
| EC2 (4x t3.medium) |
2 vCPU, 4 GB RAM |
~$120 |
| Load Balancer |
Application LB |
~$20 |
| RDS Redis |
cache.t3.small |
~$30 |
| Data Transfer |
500 GB/mois |
~$45 |
| CloudWatch |
Logs + métriques détaillées |
~$15 |
| TOTAL |
|
~$230/mois |
Checklist pré-déploiement
Troubleshooting
Problème: Image Docker ne démarre pas
# Vérifier les logs
eb logs --all
# Tester l'image localement
docker run -p 8000:8000 your-image
# Vérifier les dépendances .so
docker run -it your-image bash
ldd libs/so/libR134a.so
Problème: High CPU usage
# Vérifier les métriques
eb health --refresh
# Augmenter les instances temporairement
eb scale 5
# Profiler l'application
# Ajouter py-spy dans requirements-dev.txt
Problème: DLL/SO not found
# Vérifier présence des fichiers
docker run -it your-image ls -la libs/so/
# Vérifier permissions
docker run -it your-image ls -la libs/so/*.so
# Tester chargement
docker run -it your-image python -c "import ctypes; ctypes.CDLL('libs/so/librefifc.so')"
Maintenance
Mise à jour des dépendances
# Mettre à jour requirements.txt
pip install --upgrade -r requirements.txt
pip freeze > requirements.txt
# Tester localement
docker-compose up --build
# Déployer
./deployment/scripts/deploy.sh
Nettoyage des anciennes versions
# Lister les versions
eb appversion
# Supprimer les anciennes versions (garder les 10 dernières)
aws elasticbeanstalk describe-application-versions \
--application-name diagram-ph-api \
--query 'ApplicationVersions[10:].VersionLabel' \
--output text | xargs -n1 eb appversion delete