# 08 — Redis Setup Redis est utilisé dans Xpeditis pour : 1. **Cache des rate quotes** — clés `rate:{origin}:{destination}:{containerType}`, TTL 15 min 2. **Pub/sub WebSocket** — Socket.IO multi-pods nécessite Redis pour broadcaster les notifications --- ## Option A — Upstash (recommandé pour MVP) ### Pourquoi Upstash - Redis serverless, pay-per-use ($0.2 per 100K commands) - Free tier : 10 000 commandes/jour, 256 MB (suffisant pour 100 users) - Compatible avec l'interface Redis standard (ioredis) - Support TLS natif - Régions EU disponibles (Frankfurt) - **Pas de serveur à gérer** ### Setup Upstash 1. Créez un compte sur https://upstash.com 2. **Create Database** - Name: `xpeditis-prod` - Region: `EU-WEST-1 (Frankfurt)` ← le plus proche de Hetzner FSN1 - Type: **Regional** (pas Global pour commencer) - Eviction: **Allkeys-LRU** (expire les clés les plus anciennes si mémoire pleine) - TLS: **Enabled** 3. Copiez les credentials affichés ### Variables d'environnement ```bash # Upstash fournit une URL Redis complète REDIS_HOST=your-redis.upstash.io REDIS_PORT=6379 REDIS_PASSWORD= REDIS_DB=0 # OU avec URL (si le code le supporte) REDIS_URL=redis://:password@your-redis.upstash.io:6379 ``` ### Vérification de la connexion ```bash # Test avec redis-cli redis-cli -h your-redis.upstash.io -p 6379 -a --tls ping # PONG # Test de set/get redis-cli -h your-redis.upstash.io -p 6379 -a --tls \ SET test:connection "xpeditis-ok" EX 60 redis-cli -h your-redis.upstash.io -p 6379 -a --tls \ GET test:connection # "xpeditis-ok" ``` ### Configuration dans l'app Xpeditis Le code NestJS utilise `ioredis`. Vérifiez que TLS est activé dans la config cache : Dans `apps/backend/src/infrastructure/cache/cache.module.ts`, assurez-vous que la config Redis accepte TLS : ```typescript // La config doit inclure TLS pour Upstash const redisOptions = { host: configService.get('REDIS_HOST'), port: configService.get('REDIS_PORT', 6379), password: configService.get('REDIS_PASSWORD'), db: configService.get('REDIS_DB', 0), // TLS requis pour Upstash tls: configService.get('NODE_ENV') === 'production' ? {} : undefined, }; ``` > Si la config actuelle ne supporte pas TLS, ajoutez la variable `REDIS_TLS=true` et adaptez le cache module en conséquence. --- ## Option B — Redis self-hosted dans k3s ### Quand choisir cette option - 1 000+ users (le free tier Upstash devient limité) - Besoin de Redis Cluster pour le WebSocket à grande échelle - Contrôle total des données ### StatefulSet Redis dans Kubernetes ```bash # Créer le namespace si pas encore fait kubectl create namespace xpeditis-prod 2>/dev/null || true # Créer le Secret Redis cat > /tmp/redis-secret.yaml << 'EOF' apiVersion: v1 kind: Secret metadata: name: redis-secret namespace: xpeditis-prod type: Opaque stringData: REDIS_PASSWORD: "" EOF kubectl apply -f /tmp/redis-secret.yaml # Créer la ConfigMap Redis cat > /tmp/redis-config.yaml << 'EOF' apiVersion: v1 kind: ConfigMap metadata: name: redis-config namespace: xpeditis-prod data: redis.conf: | # Sécurité requirepass protected-mode yes # Persistance (AOF pour durabilité) appendonly yes appendfsync everysec auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb # Mémoire maxmemory 512mb maxmemory-policy allkeys-lru # Réseau bind 0.0.0.0 tcp-backlog 511 timeout 0 tcp-keepalive 300 # Logging loglevel notice # Performances lazyfree-lazy-eviction yes lazyfree-lazy-expire yes EOF kubectl apply -f /tmp/redis-config.yaml # Créer le StatefulSet Redis cat > /tmp/redis-statefulset.yaml << 'EOF' apiVersion: apps/v1 kind: StatefulSet metadata: name: redis namespace: xpeditis-prod spec: serviceName: redis-headless replicas: 1 selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - name: redis image: redis:7-alpine ports: - containerPort: 6379 name: redis command: - redis-server - /etc/redis/redis.conf env: - name: REDIS_PASSWORD valueFrom: secretKeyRef: name: redis-secret key: REDIS_PASSWORD resources: requests: cpu: 100m memory: 256Mi limits: cpu: 500m memory: 512Mi volumeMounts: - name: redis-config-vol mountPath: /etc/redis - name: redis-data mountPath: /data readinessProbe: exec: command: - redis-cli - -a - $(REDIS_PASSWORD) - ping initialDelaySeconds: 10 periodSeconds: 5 livenessProbe: exec: command: - redis-cli - -a - $(REDIS_PASSWORD) - ping initialDelaySeconds: 30 periodSeconds: 30 volumes: - name: redis-config-vol configMap: name: redis-config volumeClaimTemplates: - metadata: name: redis-data spec: accessModes: ["ReadWriteOnce"] storageClassName: hcloud-volumes resources: requests: storage: 5Gi --- apiVersion: v1 kind: Service metadata: name: redis-headless namespace: xpeditis-prod spec: clusterIP: None selector: app: redis ports: - port: 6379 targetPort: 6379 --- apiVersion: v1 kind: Service metadata: name: redis namespace: xpeditis-prod spec: selector: app: redis ports: - port: 6379 targetPort: 6379 type: ClusterIP EOF kubectl apply -f /tmp/redis-statefulset.yaml # Attendre que Redis soit prêt kubectl rollout status statefulset/redis -n xpeditis-prod --timeout=120s # Tester Redis kubectl exec -it redis-0 -n xpeditis-prod -- redis-cli -a ping # PONG ``` ### Variables d'environnement pour Redis self-hosted ```bash REDIS_HOST=redis.xpeditis-prod.svc.cluster.local REDIS_PORT=6379 REDIS_PASSWORD= REDIS_DB=0 # Pas de TLS (réseau privé interne k3s) ``` --- ## Vérification du cache Redis dans Xpeditis Après déploiement de l'application, vérifiez que le cache fonctionne : ```bash # Se connecter à Redis kubectl exec -it redis-0 -n xpeditis-prod -- redis-cli -a # Après quelques rate searches depuis l'app : KEYS rate:* # 1) "rate:FRNCE:DEHAM:20ft" # 2) "rate:FRNCE:NLRTM:20ft" # ... # Vérifier un TTL (doit être < 900 = 15 min) TTL "rate:FRNCE:DEHAM:20ft" # (integer) 647 # Stats globales INFO stats # keyspace_hits: 1234 # keyspace_misses: 156 # → Taux de hit = 1234/(1234+156) = 88% ✅ ``` --- ## Comparaison des options | Critère | Upstash (Option A) | Self-hosted (Option B) | |---|---|---| | **Coût 100 users** | $0 (free tier) | ~€5/mois (stockage) | | **Coût 1 000 users** | ~$5-10/mois | ~€5-10/mois | | **Setup** | 5 minutes | 30 minutes | | **HA** | Automatique | Non (StatefulSet 1 replica) | | **TLS** | Forcé | Non (cluster interne) | | **Ops** | Aucun | Monitoring mémoire | | **Latence** | ~5-10ms (Frankfurt) | <1ms (cluster interne) | **Recommandation :** - MVP → **Upstash free tier** (zéro coût, zéro ops) - 1 000+ users → **Self-hosted dans k3s** (latence minimale, contrôle complet)