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

9.4 KiB
Raw Blame History

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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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)

# 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)

# 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)