664 lines
14 KiB
Markdown
664 lines
14 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# AWS CLI
|
|
pip install awscli
|
|
aws configure
|
|
|
|
# EB CLI
|
|
pip install awsebcli
|
|
|
|
# Vérification
|
|
aws --version
|
|
eb --version
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration Docker
|
|
|
|
### Dockerfile (Production)
|
|
|
|
```dockerfile
|
|
# 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)
|
|
|
|
```dockerfile
|
|
# 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)
|
|
|
|
```yaml
|
|
# 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)
|
|
|
|
```json
|
|
{
|
|
"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
|
|
|
|
```yaml
|
|
# 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
|
|
|
|
```yaml
|
|
# 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
|
|
|
|
```yaml
|
|
# 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
|
|
|
|
```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
|
|
|
|
```bash
|
|
#!/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
|
|
|
|
```bash
|
|
#!/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
|
|
|
|
```bash
|
|
#!/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)
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
chmod +x deployment/scripts/rollback.sh
|
|
./deployment/scripts/rollback.sh
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration HTTPS avec Certificate Manager
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```yaml
|
|
# .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
|
|
|
|
- [ ] Tests unitaires passent (`pytest`)
|
|
- [ ] Tests d'intégration passent
|
|
- [ ] Image Docker se build sans erreur
|
|
- [ ] Variables d'environnement configurées
|
|
- [ ] Fichiers .so Linux présents et testés
|
|
- [ ] Certificat SSL configuré
|
|
- [ ] IAM roles configurés
|
|
- [ ] CloudWatch alarms configurées
|
|
- [ ] Documentation API à jour
|
|
- [ ] Plan de rollback préparé
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Problème: Image Docker ne démarre pas
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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 |