veylant/docs/runbooks/migration-client.md
2026-02-23 13:35:04 +01:00

321 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Runbook — Migration Client Pilote vers Production
**Applicable à :** Clients A (TechVision ESN) et B (RH Conseil)
**Durée estimée :** 24 heures par client (fenêtre de maintenance recommandée)
**Prérequis :** Cluster production opérationnel (EKS eu-west-3), Keycloak prod configuré
---
## Vue d'ensemble
```
Staging (api-staging.veylant.ai) Production (api.veylant.ai)
│ │
├── PostgreSQL staging DB →→→→→→→→ ├── PostgreSQL production DB
├── Keycloak staging realm →→→→→→→→ ├── Keycloak production realm
├── Redis staging ├── Redis production
└── Utilisateurs staging └── Utilisateurs production
```
---
## Phase 1 — Pré-migration (J-1)
### 1.1 Backup complet du staging
```bash
# Backup PostgreSQL staging
kubectl exec -n veylant deploy/postgres -- \
pg_dump -U veylant veylant_db | gzip > backup_staging_$(date +%Y%m%d).sql.gz
# Vérifier le backup
gunzip -t backup_staging_$(date +%Y%m%d).sql.gz && echo "Backup OK"
# Uploader vers S3 (conservation pendant la migration)
aws s3 cp backup_staging_$(date +%Y%m%d).sql.gz \
s3://veylant-backups-production/migration/
```
### 1.2 Inventaire des utilisateurs à migrer
```bash
# Exporter la liste des utilisateurs Keycloak staging
kubectl exec -n keycloak deploy/keycloak -- \
/opt/keycloak/bin/kcadm.sh get users \
-r veylant-staging \
--server http://localhost:8080 \
--realm master \
--user admin --password admin \
> users_staging.json
# Compter les utilisateurs actifs (30 derniers jours)
psql "$STAGING_DB_URL" -c \
"SELECT COUNT(*) FROM users WHERE last_login > NOW() - INTERVAL '30 days';"
```
### 1.3 Validation de l'environnement production
```bash
# Vérifier que le cluster production est opérationnel
kubectl get nodes -n veylant --context=production
kubectl get pods -n veylant --context=production
# Vérifier la connectivité API production
curl -sf https://api.veylant.ai/healthz | jq .
# Vérifier Keycloak production
curl -sf https://auth.veylant.ai/realms/veylant/.well-known/openid-configuration | jq .issuer
# Confirmer le backup automatique actif
kubectl get cronjob veylant-postgres-backup -n veylant --context=production
```
### 1.4 Communication client
- [ ] Envoyer email de notification J-1 (fenêtre de maintenance, impact estimé)
- [ ] Confirmer contact technique côté client disponible pendant la migration
- [ ] Partager le runbook rollback avec le client
---
## Phase 2 — Migration des données PostgreSQL
### 2.1 Export depuis staging
```bash
# Export complet avec données clients seulement (pas les configs système)
pg_dump \
--host="$STAGING_DB_HOST" \
--username="$STAGING_DB_USER" \
--dbname="$STAGING_DB_NAME" \
--table=users \
--table=api_keys \
--table=routing_rules \
--table=gdpr_processing_registry \
--table=ai_act_classifications \
--format=custom \
--no-privileges \
--no-owner \
-f migration_data.dump
echo "Export size: $(du -sh migration_data.dump)"
```
### 2.2 Import vers production
```bash
# Appliquer les migrations DDL d'abord (production doit être à jour)
kubectl exec -n veylant deploy/veylant-proxy --context=production -- \
/app/proxy migrate up
# Import des données
pg_restore \
--host="$PROD_DB_HOST" \
--username="$PROD_DB_USER" \
--dbname="$PROD_DB_NAME" \
--no-privileges \
--no-owner \
--clean \
--if-exists \
-v \
migration_data.dump
# Vérifier l'intégrité
psql "$PROD_DB_URL" -c "SELECT COUNT(*) FROM users;"
psql "$PROD_DB_URL" -c "SELECT COUNT(*) FROM routing_rules;"
```
### 2.3 Vérification post-import
```bash
# Comparer les compteurs staging vs production
STAGING_USERS=$(psql "$STAGING_DB_URL" -t -c "SELECT COUNT(*) FROM users;")
PROD_USERS=$(psql "$PROD_DB_URL" -t -c "SELECT COUNT(*) FROM users;")
echo "Staging users: $STAGING_USERS | Production users: $PROD_USERS"
if [ "$STAGING_USERS" != "$PROD_USERS" ]; then
echo "ERROR: User count mismatch — abort migration"
exit 1
fi
```
---
## Phase 3 — Reconfiguration Keycloak Production
### 3.1 Création du realm production
```bash
# Se connecter à Keycloak production
KEYCLOAK_URL="https://auth.veylant.ai"
KEYCLOAK_ADMIN_TOKEN=$(curl -s \
-d "client_id=admin-cli" \
-d "username=admin" \
-d "password=$KEYCLOAK_ADMIN_PASSWORD" \
-d "grant_type=password" \
"$KEYCLOAK_URL/realms/master/protocol/openid-connect/token" | jq -r .access_token)
# Importer la configuration du realm depuis staging
# (exportée au format JSON lors de la phase 1.2)
curl -sf -X POST \
-H "Authorization: Bearer $KEYCLOAK_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d @realm-export.json \
"$KEYCLOAK_URL/admin/realms"
```
### 3.2 Import des utilisateurs
```bash
# Importer les utilisateurs avec leurs rôles
# Note: les mots de passe ne peuvent pas être migrés — les utilisateurs recevront un email de reset
for user in $(jq -r '.[].id' users_staging.json); do
USER_DATA=$(jq --arg id "$user" '.[] | select(.id == $id)' users_staging.json)
curl -sf -X POST \
-H "Authorization: Bearer $KEYCLOAK_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d "$USER_DATA" \
"$KEYCLOAK_URL/admin/realms/veylant/users"
done
echo "Imported $(jq length users_staging.json) users"
```
### 3.3 Réinitialisation des mots de passe
```bash
# Envoyer un email de reset de mot de passe à tous les utilisateurs migrés
USER_IDS=$(curl -sf \
-H "Authorization: Bearer $KEYCLOAK_ADMIN_TOKEN" \
"$KEYCLOAK_URL/admin/realms/veylant/users?max=1000" | jq -r '.[].id')
for USER_ID in $USER_IDS; do
curl -sf -X PUT \
-H "Authorization: Bearer $KEYCLOAK_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '["UPDATE_PASSWORD"]' \
"$KEYCLOAK_URL/admin/realms/veylant/users/$USER_ID/execute-actions-email"
sleep 0.1 # Rate limit emails
done
```
---
## Phase 4 — Validation
### 4.1 Smoke tests API
```bash
# Obtenir un token de test (compte admin pré-créé)
TOKEN=$(curl -sf \
-d "client_id=veylant-api" \
-d "username=admin-test@veylant.ai" \
-d "password=$TEST_ADMIN_PASSWORD" \
-d "grant_type=password" \
"https://auth.veylant.ai/realms/veylant/protocol/openid-connect/token" | jq -r .access_token)
# Test endpoints principaux
curl -sf -H "Authorization: Bearer $TOKEN" https://api.veylant.ai/v1/admin/users | jq length
curl -sf -H "Authorization: Bearer $TOKEN" https://api.veylant.ai/v1/admin/routing-rules | jq length
# Test proxy (avec model user-role)
curl -sf -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Hello"}]}' \
https://api.veylant.ai/v1/chat/completions | jq .choices[0].message.content
echo "Smoke tests passed"
```
### 4.2 Validation des audit logs
```bash
# Vérifier que les logs sont bien envoyés à ClickHouse
curl -sf -H "Authorization: Bearer $TOKEN" \
"https://api.veylant.ai/v1/admin/logs?limit=5" | jq '.[].request_id'
```
### 4.3 Validation du dashboard
```bash
# Ouvrir le dashboard client et vérifier les métriques
open "https://dashboard.veylant.ai"
# Vérifier manuellement : graphiques RPS, latence, erreurs, PII
```
---
## Phase 5 — Cutover SSO (Go-Live)
### 5.1 Mise à jour des URLs côté client
Informer le contact technique du client de mettre à jour :
| Paramètre | Staging | Production |
|-----------|---------|------------|
| `base_url` OpenAI SDK | `https://api-staging.veylant.ai/v1` | `https://api.veylant.ai/v1` |
| OIDC Issuer (si SAML) | `https://auth-staging.veylant.ai/realms/veylant` | `https://auth.veylant.ai/realms/veylant` |
| Dashboard | `https://dashboard-staging.veylant.ai` | `https://dashboard.veylant.ai` |
### 5.2 Mise à jour CORS production
```bash
# Ajouter le domaine dashboard client dans config.yaml production
# Exemple Client B (RH Conseil) : dashboard sur dashboard.rh-conseil.fr
kubectl edit configmap veylant-proxy-config -n veylant --context=production
# Ajouter sous server.allowed_origins:
# - "https://dashboard.rh-conseil.fr"
# Redémarrer le proxy pour prendre en compte la nouvelle config
kubectl rollout restart deployment/veylant-proxy-blue -n veylant --context=production
kubectl rollout status deployment/veylant-proxy-blue -n veylant --context=production
```
### 5.3 Confirmation Go-Live
- [ ] Envoyer email de confirmation au client : migration réussie
- [ ] Planifier NPS de suivi J+7
- [ ] Archiver le dump staging utilisé pour la migration
---
## Rollback
### Rollback Phase 2 (avant cutover)
```bash
# Restaurer la base production depuis le backup staging
pg_restore \
--host="$PROD_DB_HOST" \
--username="$PROD_DB_USER" \
--dbname="$PROD_DB_NAME" \
--clean \
migration_data.dump
echo "Rollback Phase 2 terminé — base production restaurée"
```
### Rollback Phase 5 (après cutover)
```bash
# Rediriger le trafic vers staging (intervention DNS)
# Contact ops@veylant.ai immédiatement
# Informer le client : retour en staging, investigation en cours
# ETA rollback DNS : < 5 minutes (TTL court configuré en préparation)
```
---
## Checklist finale
- [ ] Backup staging conservé 30 jours
- [ ] Tous les utilisateurs ont reçu l'email de reset mot de passe
- [ ] Smoke tests API passés
- [ ] Dashboard client accessible
- [ ] CORS mis à jour avec domaine client
- [ ] NPS suivi planifié J+7
- [ ] Staging désactivé après 2 semaines (coûts)