259 lines
6.0 KiB
Markdown
259 lines
6.0 KiB
Markdown
# 06 — Stockage objet S3 (Hetzner Object Storage)
|
|
|
|
---
|
|
|
|
## Migration MinIO → Hetzner Object Storage
|
|
|
|
Bonne nouvelle : **aucune modification de code nécessaire.**
|
|
|
|
Le code Xpeditis utilise déjà le AWS SDK v3 avec `forcePathStyle: true` et un endpoint configurable dans `apps/backend/src/infrastructure/storage/s3-storage.adapter.ts` :
|
|
|
|
```typescript
|
|
// Ce code existant fonctionne avec Hetzner Object Storage
|
|
this.s3Client = new S3Client({
|
|
region,
|
|
endpoint, // ← Changer vers Hetzner
|
|
credentials: { accessKeyId, secretAccessKey },
|
|
forcePathStyle: !!endpoint, // ← true pour Hetzner (path-style S3)
|
|
});
|
|
```
|
|
|
|
Il suffit de **changer 4 variables d'environnement** :
|
|
|
|
```bash
|
|
# AVANT (MinIO local)
|
|
AWS_S3_ENDPOINT=http://localhost:9000
|
|
AWS_ACCESS_KEY_ID=minioadmin
|
|
AWS_SECRET_ACCESS_KEY=minioadmin
|
|
AWS_REGION=us-east-1
|
|
|
|
# APRÈS (Hetzner Object Storage)
|
|
AWS_S3_ENDPOINT=https://fsn1.your-objectstorage.com
|
|
AWS_ACCESS_KEY_ID=<hetzner_access_key>
|
|
AWS_SECRET_ACCESS_KEY=<hetzner_secret_key>
|
|
AWS_REGION=eu-central-1
|
|
AWS_S3_BUCKET=xpeditis-prod
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration détaillée
|
|
|
|
### Variables d'environnement backend (.env.production)
|
|
|
|
```bash
|
|
# S3 / Hetzner Object Storage
|
|
AWS_S3_ENDPOINT=https://fsn1.your-objectstorage.com
|
|
AWS_ACCESS_KEY_ID=<votre_hetzner_access_key>
|
|
AWS_SECRET_ACCESS_KEY=<votre_hetzner_secret_key>
|
|
AWS_REGION=eu-central-1
|
|
AWS_S3_BUCKET=xpeditis-prod
|
|
```
|
|
|
|
> **Endpoint par région :**
|
|
> - Falkenstein : `https://fsn1.your-objectstorage.com`
|
|
> - Nuremberg : `https://nbg1.your-objectstorage.com`
|
|
> - Helsinki : `https://hel1.your-objectstorage.com`
|
|
>
|
|
> Utilisez la même région que vos serveurs pour éviter des frais de transfert inter-région.
|
|
|
|
---
|
|
|
|
## Tester la connexion depuis le code
|
|
|
|
```bash
|
|
# 1. Build l'image Docker backend avec les vars de test
|
|
# 2. Ou tester directement avec AWS CLI
|
|
|
|
# Test avec AWS CLI (profil configuré dans doc 03)
|
|
aws s3 ls s3://xpeditis-prod/ \
|
|
--profile hetzner \
|
|
--endpoint-url https://fsn1.your-objectstorage.com
|
|
|
|
# Uploader un fichier test
|
|
echo "test" | aws s3 cp - s3://xpeditis-prod/test/health.txt \
|
|
--profile hetzner \
|
|
--endpoint-url https://fsn1.your-objectstorage.com
|
|
|
|
# Générer une URL signée (1h)
|
|
aws s3 presign s3://xpeditis-prod/test/health.txt \
|
|
--profile hetzner \
|
|
--endpoint-url https://fsn1.your-objectstorage.com \
|
|
--expires-in 3600
|
|
|
|
# Nettoyage
|
|
aws s3 rm s3://xpeditis-prod/test/health.txt \
|
|
--profile hetzner \
|
|
--endpoint-url https://fsn1.your-objectstorage.com
|
|
```
|
|
|
|
---
|
|
|
|
## Structure du bucket
|
|
|
|
Créez les "dossiers" initiaux (S3 utilise des préfixes, pas de vrais dossiers) :
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
PROFILE="hetzner"
|
|
ENDPOINT="https://fsn1.your-objectstorage.com"
|
|
BUCKET="xpeditis-prod"
|
|
|
|
for PREFIX in documents pdfs exports logos backups/postgres; do
|
|
aws s3api put-object \
|
|
--bucket "$BUCKET" \
|
|
--key "$PREFIX/" \
|
|
--profile "$PROFILE" \
|
|
--endpoint-url "$ENDPOINT" \
|
|
--content-length 0
|
|
echo "✅ Créé: $PREFIX/"
|
|
done
|
|
```
|
|
|
|
---
|
|
|
|
## Lifecycle policies (économies de stockage)
|
|
|
|
Hetzner Object Storage supporte les lifecycle rules S3 pour archiver automatiquement les anciens fichiers.
|
|
|
|
```bash
|
|
# Créer le fichier de lifecycle
|
|
cat > /tmp/lifecycle.json << 'EOF'
|
|
{
|
|
"Rules": [
|
|
{
|
|
"ID": "archive-old-pdfs",
|
|
"Status": "Enabled",
|
|
"Filter": {
|
|
"Prefix": "pdfs/"
|
|
},
|
|
"Transitions": [
|
|
{
|
|
"Days": 90,
|
|
"StorageClass": "GLACIER"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"ID": "archive-old-exports",
|
|
"Status": "Enabled",
|
|
"Filter": {
|
|
"Prefix": "exports/"
|
|
},
|
|
"Expiration": {
|
|
"Days": 365
|
|
}
|
|
},
|
|
{
|
|
"ID": "cleanup-old-backups",
|
|
"Status": "Enabled",
|
|
"Filter": {
|
|
"Prefix": "backups/"
|
|
},
|
|
"Expiration": {
|
|
"Days": 30
|
|
}
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
|
|
# Appliquer le lifecycle
|
|
aws s3api put-bucket-lifecycle-configuration \
|
|
--bucket xpeditis-prod \
|
|
--lifecycle-configuration file:///tmp/lifecycle.json \
|
|
--profile hetzner \
|
|
--endpoint-url https://fsn1.your-objectstorage.com
|
|
|
|
# Vérifier
|
|
aws s3api get-bucket-lifecycle-configuration \
|
|
--bucket xpeditis-prod \
|
|
--profile hetzner \
|
|
--endpoint-url https://fsn1.your-objectstorage.com
|
|
```
|
|
|
|
---
|
|
|
|
## CORS (pour upload direct depuis le navigateur)
|
|
|
|
Si vous implémentez des uploads directs depuis le browser (carrier portal) :
|
|
|
|
```bash
|
|
cat > /tmp/cors.json << 'EOF'
|
|
{
|
|
"CORSRules": [
|
|
{
|
|
"AllowedHeaders": ["*"],
|
|
"AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
|
|
"AllowedOrigins": [
|
|
"https://app.xpeditis.com",
|
|
"https://xpeditis.com"
|
|
],
|
|
"ExposeHeaders": ["ETag"],
|
|
"MaxAgeSeconds": 3000
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
|
|
aws s3api put-bucket-cors \
|
|
--bucket xpeditis-prod \
|
|
--cors-configuration file:///tmp/cors.json \
|
|
--profile hetzner \
|
|
--endpoint-url https://fsn1.your-objectstorage.com
|
|
```
|
|
|
|
---
|
|
|
|
## Intégration dans le Secret Kubernetes
|
|
|
|
Le Secret Kubernetes `backend-secrets` contiendra les credentials S3. Voir le doc 09 pour les manifests complets, mais voici la section S3 :
|
|
|
|
```yaml
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: backend-secrets
|
|
namespace: xpeditis-prod
|
|
type: Opaque
|
|
stringData:
|
|
AWS_S3_ENDPOINT: "https://fsn1.your-objectstorage.com"
|
|
AWS_ACCESS_KEY_ID: "<hetzner_access_key>"
|
|
AWS_SECRET_ACCESS_KEY: "<hetzner_secret_key>"
|
|
AWS_REGION: "eu-central-1"
|
|
AWS_S3_BUCKET: "xpeditis-prod"
|
|
```
|
|
|
|
---
|
|
|
|
## Monitoring du stockage
|
|
|
|
```bash
|
|
# Voir la taille totale du bucket
|
|
aws s3 ls s3://xpeditis-prod/ \
|
|
--recursive \
|
|
--human-readable \
|
|
--summarize \
|
|
--profile hetzner \
|
|
--endpoint-url https://fsn1.your-objectstorage.com \
|
|
| tail -3
|
|
|
|
# Output :
|
|
# Total Objects: 1234
|
|
# Total Size: 4.5 GiB
|
|
```
|
|
|
|
---
|
|
|
|
## Tarifs Hetzner Object Storage
|
|
|
|
| Ressource | Prix |
|
|
|---|---|
|
|
| Stockage | Inclus dans le pack €4.99/mois (1 TB) |
|
|
| Trafic sortant (internet) | Inclus dans le pack (1 TB) |
|
|
| Requêtes | Incluses |
|
|
| Stockage > 1 TB | €0.0067/TB/heure (~€4.90/TB/mois) |
|
|
| Trafic > 1 TB | ~€1/TB |
|
|
|
|
Pour Xpeditis à 1 000 users (~200 GB de fichiers), le coût est de **€4.99/mois fixe**.
|