incident-runbook-templates

Par wshobson · agents

Créez des runbooks de réponse aux incidents structurés avec des procédures étape par étape, des chemins d'escalade et des actions de récupération. Utilisez cette compétence pour construire un runbook de panne de service pour un système de traitement des paiements ; créer des procédures d'incident pour les bases de données couvrant l'épuisement du pool de connexions, le décalage de réplication et les alertes d'espace disque ; former les nouveaux ingénieurs d'astreinte qui ont besoin de guides de récupération pas à pas conçus pour un cerveau en pleine nuit ; ou standardiser les matrices d'escalade entre plusieurs équipes d'ingénierie.

npx skills add https://github.com/wshobson/agents --skill incident-runbook-templates

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éventives
  • on-call-handoff-patterns - Structurer les passages de shift afin que le répondant entrant ait un contexte complet sur les incidents actifs

Skills similaires