Modèles de Runbook d'Incident
Modèles prêts pour la production destinés aux runbooks de réponse aux incidents, couvrant la détection, le triage, l'atténuation, la résolution et la communication.
Quand utiliser cette compétence
- Créer des procédures de réponse aux incidents
- Construire des runbooks spécifiques à un service
- Établir des chemins d'escalade
- Documenter les procédures de récupération
- Répondre aux incidents actifs
- Former les ingénieurs en service
Concepts fondamentaux
1. Niveaux de gravité d'incident
| Gravité | Impact | Temps de réponse | Exemple |
|---|---|---|---|
| SEV1 | Indisponibilité complète, perte de données | 15 min | Production down |
| SEV2 | Dégradation majeure | 30 min | Fonctionnalité critique cassée |
| SEV3 | Impact mineur | 2 heures | Bug non critique |
| SEV4 | Impact minimal | Jour ouvrable suivant | Problème cosmétique |
2. Structure du Runbook
1. Vue d'ensemble et impact
2. Détection et alertes
3. Triage initial
4. Étapes d'atténuation
5. Investigation de la cause racine
6. Procédures de résolution
7. Vérification et rollback
8. Modèles de communication
9. Matrice d'escalade
Modèles de Runbook
Template 1: Runbook d'indisponibilité de service
# Runbook d'indisponibilité [Nom du service]
## Vue d'ensemble
**Service**: Service de traitement des paiements
**Propriétaire**: Équipe Platform
**Slack**: #payments-incidents
**PagerDuty**: payments-oncall
## Évaluation de l'impact
- [ ] Quels clients sont affectés?
- [ ] Quel pourcentage du trafic est impacté?
- [ ] Y a-t-il des implications financières?
- [ ] Quel est le rayon d'explosion?
## Détection
### Alertes
- `payment_error_rate > 5%` (PagerDuty)
- `payment_latency_p99 > 2s` (Slack)
- `payment_success_rate < 95%` (PagerDuty)
### Tableaux de bord
- [Payment Service Dashboard](https://grafana/d/payments)
- [Error Tracking](https://sentry.io/payments)
- [Dependency Status](https://status.stripe.com)
## Triage initial (5 premières minutes)
### 1. Évaluer la portée
```bash
# Vérifier l'état du service
kubectl get pods -n payments -l app=payment-service
# Vérifier les déploiements récents
kubectl rollout history deployment/payment-service -n payments
# Vérifier les taux d'erreur
curl -s "http://prometheus:9090/api/v1/query?query=sum(rate(http_requests_total{status=~'5..'}[5m]))"
```
### 2. Vérifications rapides de l'état
- [ ] Pouvez-vous accéder au service? `curl -I https://api.company.com/payments/health`
- [ ] Connectivité de la base de données? Vérifier les métriques du pool de connexion
- [ ] Dépendances externes? Vérifier l'état de Stripe, API bancaire
- [ ] Changements récents? Vérifier l'historique des déploiements
### 3. Classification initiale
| Symptôme | Cause probable | Aller à |
| -------- | -------------- | ------- |
| Toutes les requêtes échouent | Service down | Section 4.1 |
| Latence élevée | Base de données/dépendance | Section 4.2 |
| Échecs partiels | Bug dans le code | Section 4.3 |
| Pic d'erreurs | Surge de trafic | Section 4.4 |
## Procédures d'atténuation
### 4.1 Service complètement indisponible
```bash
# Étape 1: Vérifier l'état des pods
kubectl get pods -n payments
# Étape 2: Si les pods sont en crash-loop, vérifier les logs
kubectl logs -n payments -l app=payment-service --tail=100
# Étape 3: Vérifier les déploiements récents
kubectl rollout history deployment/payment-service -n payments
# Étape 4: ROLLBACK si le déploiement récent est suspect
kubectl rollout undo deployment/payment-service -n payments
# Étape 5: Scale up si ressources contraintes
kubectl scale deployment/payment-service -n payments --replicas=10
# Étape 6: Vérifier la récupération
kubectl rollout status deployment/payment-service -n payments
```
### 4.2 Latence élevée
```bash
# Étape 1: Vérifier les connexions de base de données
kubectl exec -n payments deploy/payment-service -- \
curl localhost:8080/metrics | grep db_pool
# Étape 2: Vérifier les requêtes lentes (si problème DB)
psql -h $DB_HOST -U $DB_USER -c "
SELECT pid, now() - query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active' AND duration > interval '5 seconds'
ORDER BY duration DESC;"
# Étape 3: Tuer les requêtes longues si nécessaire
psql -h $DB_HOST -U $DB_USER -c "SELECT pg_terminate_backend(pid);"
# Étape 4: Vérifier la latence de dépendance externe
curl -w "@curl-format.txt" -o /dev/null -s https://api.stripe.com/v1/health
# Étape 5: Activer le circuit breaker si la dépendance est lente
kubectl set env deployment/payment-service \
STRIPE_CIRCUIT_BREAKER_ENABLED=true -n payments
```
### 4.3 Échecs partiels (erreurs spécifiques)
```bash
# Étape 1: Identifier le motif d'erreur
kubectl logs -n payments -l app=payment-service --tail=500 | \
grep -i error | sort | uniq -c | sort -rn | head -20
# Étape 2: Vérifier le suivi des erreurs
# Aller à Sentry: https://sentry.io/payments
# Étape 3: Si endpoint spécifique, activer feature flag pour désactiver
curl -X POST https://api.company.com/internal/feature-flags \
-d '{"flag": "DISABLE_PROBLEMATIC_FEATURE", "enabled": true}'
# Étape 4: Si problème de données, vérifier les modifications de données récentes
psql -h $DB_HOST -c "
SELECT * FROM audit_log
WHERE table_name = 'payment_methods'
AND created_at > now() - interval '1 hour';"
```
### 4.4 Surge de trafic
```bash
# Étape 1: Vérifier le taux de requêtes actuel
kubectl top pods -n payments
# Étape 2: Scale horizontalement
kubectl scale deployment/payment-service -n payments --replicas=20
# Étape 3: Activer le rate limiting
kubectl set env deployment/payment-service \
RATE_LIMIT_ENABLED=true \
RATE_LIMIT_RPS=1000 -n payments
# Étape 4: Si attaque, bloquer les IPs suspectes
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: block-suspicious
namespace: payments
spec:
podSelector:
matchLabels:
app: payment-service
ingress:
- from:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 192.168.1.0/24 # Plage suspecte
EOF
```
## Étapes de vérification
```bash
# Vérifier que le service est sain
curl -s https://api.company.com/payments/health | jq
# Vérifier que le taux d'erreur est revenu à la normale
curl -s "http://prometheus:9090/api/v1/query?query=sum(rate(http_requests_total{status=~'5..'}[5m]))" | jq '.data.result[0].value[1]'
# Vérifier que la latence est acceptable
curl -s "http://prometheus:9090/api/v1/query?query=histogram_quantile(0.99,sum(rate(http_request_duration_seconds_bucket[5m]))by(le))" | jq
# Test de fumée pour les flux critiques
./scripts/smoke-test-payments.sh
```
## Procédures de rollback
```bash
# Rollback du déploiement Kubernetes
kubectl rollout undo deployment/payment-service -n payments
# Rollback de migration de base de données (si applicable)
./scripts/db-rollback.sh $MIGRATION_VERSION
# Rollback du feature flag
curl -X POST https://api.company.com/internal/feature-flags \
-d '{"flag": "NEW_PAYMENT_FLOW", "enabled": false}'
```
## Matrice d'escalade
| Condition | Escalader à | Contact |
| --------- | ----------- | ------- |
| > 15 min non résolu SEV1 | Engineering Manager | @manager (Slack) |
| Breach de données suspecté | Équipe Sécurité | #security-incidents |
| Impact financier > $10k | Finance + Juridique | @finance-oncall |
| Communication client nécessaire | Support Lead | @support-lead |
## Modèles de communication
### Notification initiale (interne)
```
🚨 INCIDENT: Dégradation du service de paiement
Gravité: SEV2
Statut: Investigation
Impact: ~20% des requêtes de paiement échouent
Heure de début: [HEURE]
Commandant d'incident: [NOM]
Actions en cours:
- Investigation de la cause racine
- Scale up du service
- Monitoring des tableaux de bord
Mises à jour dans #payments-incidents
```
### Mise à jour de statut
```
📊 MISE À JOUR: Incident du service de paiement
Statut: Atténuation
Impact: Réduit à ~5% de taux d'échec
Durée: 25 minutes
Actions prises:
- Rollback du déploiement v2.3.4 → v2.3.3
- Scale du service de 5 → 10 replicas
Prochaines étapes:
- Monitoring continu
- Analyse de cause racine en cours
ETA de résolution: ~15 minutes
```
### Notification de résolution
```
✅ RÉSOLU: Incident du service de paiement
Durée: 45 minutes
Impact: ~5 000 transactions affectées
Cause racine: Fuite mémoire dans v2.3.4
Résolution:
- Rollback à v2.3.3
- Transactions auto-renvoyées avec succès
Suivi:
- Postmortem planifié pour [DATE]
- Correction du bug en cours
```
Template 2: Runbook d'incident de base de données
# Runbook d'incident de base de données
## Référence rapide
| Problème | Commande |
|----------|----------|
| Vérifier les connexions | `SELECT count(*) FROM pg_stat_activity;` |
| Tuer une requête | `SELECT pg_terminate_backend(pid);` |
| Vérifier le lag de réplication | `SELECT extract(epoch from (now() - pg_last_xact_replay_timestamp()));` |
| Vérifier les verrous | `SELECT * FROM pg_locks WHERE NOT granted;` |
## Épuisement du pool de connexion
```sql
-- Vérifier les connexions actives
SELECT datname, usename, state, count(*)
FROM pg_stat_activity
GROUP BY datname, usename, state
ORDER BY count(*) DESC;
-- Identifier les connexions longues
SELECT pid, usename, datname, state, query_start, query
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY query_start;
-- Terminer les connexions inactives
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND query_start < now() - interval '10 minutes';
Lag de réplication
-- Vérifier le lag sur le replica
SELECT
CASE
WHEN pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn() THEN 0
ELSE extract(epoch from now() - pg_last_xact_replay_timestamp())
END AS lag_seconds;
-- Si lag > 60s, envisager:
-- 1. Vérifier le réseau entre primary/replica
-- 2. Vérifier l'I/O disque du replica
-- 3. Envisager le failover si irrécupérable
Espace disque critique
# Vérifier l'utilisation disque
df -h /var/lib/postgresql/data
# Trouver les grandes tables
psql -c "SELECT relname, pg_size_pretty(pg_total_relation_size(relid))
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;"
# VACUUM pour récupérer l'espace
psql -c "VACUUM FULL large_table;"
# Si urgence, supprimer les anciennes données ou étendre le disque
## Bonnes pratiques
### À faire
- **Maintenir les runbooks à jour** - Revoir après chaque incident
- **Tester les runbooks régulièrement** - Game days, chaos engineering
- **Inclure les étapes de rollback** - Toujours avoir une échappatoire
- **Documenter les hypothèses** - Ce qui doit être vrai pour que les étapes fonctionnent
- **Lier aux tableaux de bord** - Accès rapide sous stress
### À éviter
- **Ne pas supposer les connaissances** - Écrire pour un cerveau à 3 h du matin
- **Ne pas sauter la vérification** - Confirmer que chaque étape a fonctionné
- **Ne pas oublier la communication** - Tenir les parties prenantes informées
- **Ne pas travailler seul** - Escalader tôt
- **Ne pas sauter les postmortems** - Apprendre de chaque incident
## Dépannage
### Les étapes du runbook fonctionnent en staging mais échouent lors d'un incident réel
Les étapes supposent souvent des préconditions vraies dans un environnement sain mais pas pendant une panne. Pour chaque commande de votre runbook, ajoutez une vérification des prérequis et une note « que faire si cette commande échoue »:
```bash
# Étape: Vérifier l'état des pods
kubectl get pods -n payments
# Prérequis: kubectl configuré, kubeconfig pointe vers le bon cluster
# Si cela échoue: exécuter `aws eks update-kubeconfig --name prod-cluster --region us-east-1`
# Résultat attendu: pods en état Running
L'ingénieur en service panique et saute les étapes dans le désordre
Ajoutez une checklist numérotée en haut du runbook qui reflète les numéros de section, afin que les répondants puissent suivre la progression sous stress sans lire le document complet:
## Checklist rapide
- [ ] 1. Déclarer la gravité de l'incident et ouvrir la war room
- [ ] 2. Vérifier l'état du service (Section 4.1)
- [ ] 3. Vérifier les déploiements récents (Section 4.1)
- [ ] 4. Rollback si le déploiement est suspect (Section 4.1)
- [ ] 5. Poster une notification initiale dans #payments-incidents
- [ ] 6. Escalader si > 15 min non résolu
Le runbook est obsolète — les commandes font référence à d'anciens noms de cluster ou endpoints
Les runbooks se dégradent parce qu'ils sont mis à jour manuellement. Incluez une date « Last Verified » et un propriétaire en haut, et ajoutez une vérification CI qui valide tous les endpoints curl et les noms de contexte kubectl sont toujours valides:
## Métadonnées du runbook
| Champ | Valeur |
|---|---|
| Dernière vérification | 2024-11-15 |
| Propriétaire | @platform-team |
| Cadence d'examen | Après chaque SEV1/SEV2 |
La communication aux parties prenantes est retardée pendant que les ingénieurs se concentrent
Assignez un rôle de communicant d'incident dédié (séparé du commandant d'incident) dont le seul travail est de poster les mises à jour de statut. Ajoutez un agenda permanent dans le modèle de communication:
Mise à jour toutes les 15 minutes (même s'il n'y a pas de nouvelles informations):
- Statut actuel (Enquête / Atténuation / Monitoring)
- Impact (ce qui est cassé, qui est affecté, % du trafic)
- Ce que nous faisons en ce moment
- Prochaine mise à jour dans: 15 minutes
Les commandes du runbook de base de données causent une indisponibilité supplémentaire si exécutées incorrectement
Ajoutez des avertissements explicites avant les commandes SQL destructrices et exigez une vérification de la sortie en exécution sèche avant l'exécution:
-- AVERTISSEMENT: Ceci termine les connexions actives. Vérifier le nombre d'abord.
-- EXÉCUTION SÈCHE (vérifier le nombre avant de terminer):
SELECT count(*) FROM pg_stat_activity WHERE state = 'idle' AND query_start < now() - interval '10 minutes';
-- EXÉCUTER seulement après vérification que le nombre est raisonnable (< 50):
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE state = 'idle' AND query_start < now() - interval '10 minutes';
Compétences connexes
postmortem-writing- Après résolution d'un incident, utiliser les modèles de postmortem pour capturer la cause racine et les actions préventiveson-call-handoff-patterns- Structurer les passages de shift afin que le répondant entrant ait un contexte complet sur les incidents actifs