Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
8.0 KiB
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