xpeditis2.0/docs/mise-en-prod/14-runbook-go-live.md
David b22f4e0b74 docs: procedure de mise en production pas a pas
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
2026-09-07 21:40:50 +02:00

8.0 KiB
Raw Permalink Blame History

14 — Runbook de mise en ligne

Le déroulé du dernier jour et de l'ouverture. Imprimez-le ou gardez-le ouvert à côté de vous — ce n'est pas le moment de chercher une commande dans un autre fichier.


Choisir le moment

Bon moment Mauvais moment
Mardi ou mercredi matin, 9 h–10 h Vendredi, quel que soit l'argument
Vous êtes disponible les 48 h suivantes La veille de vos congés
Aucune migration lourde en attente Pendant une maintenance Hetzner annoncée

Mardi matin laisse trois jours ouvrés pour découvrir et corriger ce qui n'a pas été anticipé.


J-1 : répétition générale

1. Contrôle complet (30 min)

export KUBECONFIG=~/.kube/xpeditis-prod.yaml
cd infra/prod
DB_PUBLIC_IP=<ip_db> make preflight

Aucun point bloquant ne doit subsister. Consignez les avertissements dans un registre des risques daté, avec pour chacun une décision explicite : accepté, ou corrigé avant l'ouverture.

2. Parcours fonctionnels de bout en bout (1 h)

À faire dans un navigateur, comme un vrai client, pas en curl.

[ ] Inscription d'un nouveau compte
[ ] Réception de l'e-mail de validation (vérifier : boîte principale, pas spam)
[ ] Validation, puis connexion
[ ] Recherche de tarifs → au moins un résultat s'affiche
[ ] Création d'une réservation
[ ] Réception de l'e-mail de confirmation
[ ] Génération et téléchargement d'un PDF
[ ] Lien magique transporteur : réception, ouverture, acceptation
[ ] Souscription à un abonnement en mode Live (petit montant, puis remboursement)
[ ] Réception du webhook Stripe (Dashboard Stripe → Webhooks → Tentatives)
[ ] Notification temps réel visible dans l'interface
[ ] Déconnexion, mot de passe oublié, réinitialisation
[ ] Espace d'administration accessible avec votre compte ADMIN
[ ] Import d'une grille tarifaire CSV
[ ] Navigation sur mobile

Le test Stripe en mode Live est indispensable. Les clés de test et de production ont des comportements différents, et le secret de webhook n'est pas le même. Une souscription à 1 €, immédiatement remboursée, vaut mieux que la découverte du problème par le premier client.

La notification temps réel peut ne pas arriver : c'est attendu avec deux replicas. Voir 15 § Points de vigilance.

3. Répétition du retour arrière (20 min)

Exercez-vous pendant que l'enjeu est nul.

# Déployer sciemment une version antérieure
kubectl -n xpeditis-prod set image deploy/xpeditis-backend \
  backend=rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:prod-<sha_precedent>
kubectl -n xpeditis-prod rollout status deploy/xpeditis-backend

# Puis revenir
make rollback
bash scripts/smoke-test.sh

Chronométrez. C'est votre temps de retour réel.

4. Sauvegarde manuelle (10 min)

ssh deploy@<db_ip> 'sudo systemctl start xpeditis-backup.service'
ssh deploy@<db_ip> 'sudo journalctl -u xpeditis-backup -n 30 --no-pager'

Notez l'horodatage : c'est votre point de retour du jour J.

5. Décision go / no-go

Critère Bloquant ?
preflight-check.sh sans point bloquant oui
Test PITR réussi (12) oui
Clé SMTP Brevo compromise révoquée oui
Comptes de démonstration neutralisés (401) oui
Un seul ADMIN actif oui
Parcours d'inscription et de réservation fonctionnels oui
Paiement Stripe testé en Live oui
Alerte de test reçue sur Discord oui
Supervision externe active oui
Retour arrière répété oui
SSL Labs ≥ A non — corriger sous 7 j
Notifications temps réel fiables non — dégradation connue
Sentry connecté non

Un seul « oui » en échec = report. Reporter d'une semaine coûte infiniment moins cher que d'ouvrir avec un administrateur au mot de passe public.


J0 : ouverture

T-30 min

export KUBECONFIG=~/.kube/xpeditis-prod.yaml
cd infra/prod

make status          # tous les pods Running, certificats Ready
make smoke           # tout au vert

# Sauvegarde de dernière minute
ssh deploy@<db_ip> 'sudo systemctl start xpeditis-backup.service'

Ouvrez et gardez sous les yeux :

  • Grafana : https://grafana.xpeditis.com
  • Le canal Discord #alertes
  • Le tableau de bord Stripe
  • Un terminal avec make -C infra/prod logs

T-0 : rendre public

Si vous aviez restreint l'accès pendant la préparation (règle Cloudflare, liste d'IP), retirez-la maintenant.

# Vérification finale, depuis un réseau extérieur (partage de connexion mobile)
curl -sI https://xpeditis.com/           | head -1
curl -sI https://app.xpeditis.com/       | head -1
curl -s  https://api.xpeditis.com/api/v1/health | jq

Publiez : site vitrine, réseaux sociaux, e-mail aux premiers clients.

T+15 min

make smoke
kubectl -n xpeditis-prod get pods
kubectl -n xpeditis-prod top pods 2>/dev/null || true

Dans Grafana :

  • taux d'erreur 5xx — doit rester à 0 ;
  • latence P95 — sous 1 s ;
  • mémoire des pods — stable, pas de croissance continue.

T+1 h, T+4 h, puis fin de journée

Les mêmes contrôles. Ce que vous cherchez :

Signal Interprétation
Mémoire du backend en croissance continue Fuite mémoire → surveiller, redémarrer si besoin
Erreurs 401 en rafale Problème de cookie (COOKIE_DOMAIN) ou de CORS
Requêtes PostgreSQL lentes Index manquant sur une table qui grossit
Connexions PostgreSQL en hausse Pool non libéré
Espace disque en baisse rapide Journaux ou WAL — vérifier que l'archivage fonctionne

Si ça tourne mal

Le site est cassé pour tout le monde

make -C infra/prod rollback
make -C infra/prod smoke

Si le retour arrière ne suffit pas : voir 15 § Le site est hors ligne.

Il faut refermer temporairement

Cloudflare → Security → Settings → Under Attack Mode. Les visiteurs passent par une page d'interstitiel ; vos IP restent autorisées. C'est réversible en un clic, contrairement à une modification de firewall.

Perte ou corruption de données

Ne rien faire d'autre, et suivre 12 § Restauration. Chaque écriture supplémentaire complique la remise en état.


J+1 à J+7

Chaque jour

make -C infra/prod status
[ ] Aucune alerte non traitée sur Discord
[ ] Sauvegarde de la nuit réussie (battement de cœur vert)
[ ] Taux d'erreur stable
[ ] Aucun pod redémarré sans raison
[ ] Aucun paiement en échec inexpliqué côté Stripe

J+7 : bilan

[ ] Vérification hebdomadaire de restauration passée (dimanche 04h00)
[ ] Consommation réelle vs dimensionnement — le CPX41 est-il bien calibré ?
[ ] Coût réel vs prévision (Xpeditis_Previsions_Couts.xlsx)
[ ] Registre des risques relu : les avertissements acceptés sont-ils traités ?
[ ] Retours utilisateurs : quelque chose casse-t-il de façon récurrente ?
[ ] HSTS : passer de 1 mois à 12 mois + preload si tout est stable

Contacts et accès en urgence

À remplir et à garder hors du dépôt (gestionnaire de mots de passe, ou papier dans un tiroir) :

Hetzner Cloud        console.hetzner.cloud        compte : ____________
Hetzner Robot        robot.hetzner.com            (Storage Box)
Cloudflare           dash.cloudflare.com          compte : ____________
Registrar            ____________
Scaleway             console.scaleway.com
Stripe               dashboard.stripe.com
Brevo                app.brevo.com
GitHub               github.com/____________

SSH admin       ssh -i ~/.ssh/xpeditis_prod deploy@<app_ip>
SSH base        ssh -i ~/.ssh/xpeditis_prod deploy@<db_ip>
Kubeconfig      ~/.kube/xpeditis-prod.yaml
Clé age         ~/.config/sops/age/keys.txt  (+ copie hors ligne : ________)
Clé de secours  emplacement physique : ____________

→ Suite : 15 — Exploitation et incidents