## Introduction

Les événements Kubernetes sont souvent négligés jusqu'à ce qu'un incident critique nécessite une chronologie de ce qui s'est passé. Les événements enregistrent des transitions comme la planification des pods, les échecs de vérification de santé et les problèmes de nœuds, mais ils sont éphémères : par défaut, le serveur d'API ne les conserve qu'environ une heure. Perdre cet historique peut compliquer le dépannage, les audits et les post-mortems. Ce guide fournit une approche pratique pour sauvegarder et restaurer les événements Kubernetes, avec des commandes concrètes, des validations et des procédures de récupération. À la fin, vous disposerez d'un processus reproductible qui s'intègre à vos opérations existantes.

## Inventaire des versions et de l'environnement

Avant de mettre en œuvre une solution de sauvegarde, documentez votre environnement de cluster et les versions des outils. Cet inventaire garantit la cohérence et aide à éviter les problèmes de compatibilité. Vérifiez les éléments suivants :

- **Version de Kubernetes** : exécutez `kubectl version --short` (ou `kubectl version` dans les versions plus récentes). Exemple de sortie : `Client Version: v1.29.2`, `Server Version: v1.29.1`.
- **Version de l'API Events** : exécutez `kubectl api-resources | grep events`. Confirmez quel groupe d'API est disponible : `events.k8s.io/v1` ou `events.k8s.io/v1beta1` (obsolète depuis la v1.19). Exemple de sortie :
  ```
  events                         events.k8s.io/v1            true         Event
  events                         v1                          true         Event
  ```
  Cela montre à la fois les événements core v1 et le groupe plus récent `events.k8s.io/v1`.
- **TTL des événements du serveur d'API** : vérifiez le drapeau `--event-ttl` sur le `kube-apiserver`. La valeur par défaut est 1 heure. Cela définit la durée de conservation des événements sans sauvegarde. Vous pouvez inspecter la spécification du pod du serveur d'API ou le fichier de configuration. Par exemple, dans un cluster kubeadm, consultez `/etc/kubernetes/manifests/kube-apiserver.yaml` et recherchez `--event-ttl`. S'il n'est pas défini, la valeur par défaut est `1h0m0s`.
- **Topologie du cluster** : identifiez les espaces de noms et les charges de travail qui génèrent des événements critiques. Pour un projet pilote, concentrez-vous sur un espace de noms d'application, par exemple `default` ou un espace de noms personnalisé comme `payments`.
- **Permissions d'accès** : vous avez besoin d'un accès en lecture aux événements dans l'espace de noms cible. Exécutez `kubectl auth can-i get events -n votre-espace-de-noms`. Si la réponse est `yes`, vous pouvez continuer. Si c'est `no`, vous devrez peut-être accorder des autorisations via RBAC. Exemple de sortie lorsque c'est autorisé : `yes`.
- **Emplacement de stockage de la sauvegarde** : décidez où stocker les événements exportés (par exemple, système de fichiers local, stockage d'objets). Pour ce guide, nous utilisons des fichiers JSON locaux.

Exemple de commande pour vérifier le support des événements :

```bash
kubectl get --raw /apis/events.k8s.io/v1 | jq .
```

La sortie attendue montre la version du groupe d'API :

```json
{
  "kind": "APIResourceList",
  "apiVersion": "v1",
  "groupVersion": "events.k8s.io/v1",
  "resources": [
    {
      "name": "events",
      "singularName": "event",
      "namespaced": true,
      "kind": "Event",
      "verbs": ["create", "delete", "get", "list", "patch", "update", "watch"]
    }
  ]
}
```

Si l'API `events.k8s.io` n'est pas disponible, utilisez l'API des événements core v1 (`/api/v1/namespaces/{namespace}/events`), qui a une structure similaire mais des champs différents.

## Chemin de configuration sûr

Un processus de sauvegarde sûr doit être limité, idempotent et éviter d'altérer le cluster. Nous utiliserons des commandes `kubectl` natives pour exporter les événements en JSON, qui peuvent être restaurés plus tard en recréant les événements via l'API. Pour la production, vous pouvez automatiser cela avec un CronJob, mais les étapes manuelles sont essentielles pour la validation.

### Sauvegarde limitée

Sauvegardez d'abord les événements d'un seul espace de noms :

```bash
kubectl get events -n votre-espace-de-noms -o json > events-backup-$(date +%Y%m%d-%H%M%S).json
```

Sortie attendue : un fichier JSON avec la liste des événements. Exemple d'extrait :

```json
{
  "apiVersion": "v1",
  "items": [
    {
      "metadata": {
        "name": "my-pod.16a1b2c3d4e5f6g7",
        "namespace": "votre-espace-de-noms",
        "uid": "12345678-1234-1234-1234-123456789abc",
        "resourceVersion": "12345",
        "creationTimestamp": "2023-05-01T10:00:00Z"
      },
      "involvedObject": {
        "kind": "Pod",
        "namespace": "votre-espace-de-noms",
        "name": "my-pod",
        "uid": "abcdef12-3456-7890-abcd-ef1234567890"
      },
      "reason": "Scheduled",
      "message": "Successfully assigned votre-espace-de-noms/my-pod to node-1",
      "type": "Normal",
      "count": 1,
      "firstTimestamp": "2023-05-01T10:00:00Z",
      "lastTimestamp": "2023-05-01T10:00:00Z"
    }
  ],
  "kind": "List",
  "metadata": {
    "resourceVersion": ""
  }
}
```

### Filtrage pour la pertinence

Vous pouvez vouloir sauvegarder uniquement les événements d'avertissement ou les événements d'une ressource spécifique :

```bash
kubectl events -n votre-espace-de-noms --types=Warning -o json > warnings-backup.json
```

Cette commande exporte uniquement les événements avec `type: Warning`. Le fichier de sortie contient des événements comme `FailedScheduling`, `BackOff`, etc. Vous pouvez également filtrer par objet impliqué, par exemple :

```bash
kubectl events -n votre-espace-de-noms --for pod/my-pod -o json > my-pod-events.json
```

Pour un filtrage plus complexe, utilisez `jq` sur le fichier exporté pour sélectionner des événements en fonction des champs.

### Automatisation avec CronJob

Pour des sauvegardes continues, créez un CronJob qui exécute un script en utilisant un compte de service avec un accès en lecture aux événements. Exemple de manifeste CronJob (exemple construit) :

```yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: event-backup
  namespace: backup-tools
spec:
  schedule: "0 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: event-backup-sa
          restartPolicy: OnFailure
          containers:
          - name: backup
            image: bitnami/kubectl:latest
            command:
            - /bin/sh
            - -c
            - |
              kubectl get events --all-namespaces -o json > /backups/events-$(date +%Y%m%d-%H%M%S).json
            volumeMounts:
            - name: backup-volume
              mountPath: /backups
          volumes:
          - name: backup-volume
            persistentVolumeClaim:
              claimName: event-backup-pvc
```

Remarque : cela nécessite un PersistentVolumeClaim et des RBAC appropriés. Pour un projet pilote, une sauvegarde manuelle est suffisante.

Pour configurer les RBAC pour le compte de service du CronJob, créez un Role et un RoleBinding. Exemple :

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: event-reader
  namespace: backup-tools
rules:
- apiGroups: [""]
  resources: ["events"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["events.k8s.io"]
  resources: ["events"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: event-backup-binding
  namespace: backup-tools
subjects:
- kind: ServiceAccount
  name: event-backup-sa
  namespace: backup-tools
roleRef:
  kind: Role
  name: event-reader
  apiGroup: rbac.authorization.k8s.io
```

Appliquez-les avec `kubectl apply -f rbac.yaml`.

Pour le PersistentVolumeClaim, vous pouvez utiliser un provisionneur dynamique ou un simple hostPath pour les tests. Exemple de PVC :

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: event-backup-pvc
  namespace: backup-tools
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
```

## Vérification et diagnostics

Après la sauvegarde, vérifiez que le fichier de sauvegarde est valide et complet. Utilisez `jq` pour inspecter et compter les événements :

```bash
jq '.items | length' events-backup-*.json
```

Sortie attendue : un nombre (par exemple, `42`).

Vérifiez que le fichier contient les champs attendus :

```bash
jq '.items[0] | {reason, message, type, involvedObject}' events-backup-*.json
```

Exemple de sortie :

```json
{
  "reason": "Scheduled",
  "message": "Successfully assigned votre-espace-de-noms/my-pod to node-1",
  "type": "Normal",
  "involvedObject": {
    "kind": "Pod",
    "name": "my-pod",
    "namespace": "votre-espace-de-noms"
  }
}
```

Comparez avec le nombre d'événements en direct pour détecter les événements manqués :

```bash
LIVE_COUNT=$(kubectl get events -n votre-espace-de-noms --no-headers | wc -l)
BACKUP_COUNT=$(jq '.items | length' events-backup-*.json)
echo "Live: $LIVE_COUNT, Backup: $BACKUP_COUNT"
```

Sortie attendue : `Live: 50, Backup: 50` (les nombres peuvent différer légèrement en raison de la création d'événements entre les commandes). Si le nombre de sauvegardes est nettement inférieur, cela peut indiquer que certains événements ont expiré avant la sauvegarde ou que la sauvegarde était incomplète.

Pour les sauvegardes automatisées, vérifiez le statut du CronJob :

```bash
kubectl get cronjob event-backup -n backup-tools
```

La sortie attendue montre `LAST SCHEDULE` et `SUSPEND` comme `False` :

```
NAME           SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
event-backup   0 * * * *   False     0        3m20s          1d
```

Vérifiez les exécutions des jobs :

```bash
kubectl get jobs -n backup-tools
```

Exemple :

```
NAME                      COMPLETIONS   DURATION   AGE
event-backup-1651234567   1/1           5s         3m20s
```

Si un job échoue, inspectez les journaux :

```bash
kubectl logs job/event-backup-1651234567 -n backup-tools
```

## Modes de défaillance et récupération

Plusieurs modes de défaillance peuvent affecter la sauvegarde et la restauration des événements. Les comprendre vous aide à planifier la récupération.

### Modes de défaillance courants

| Mode de défaillance                        | Symptôme                                                                 | Atténuation                                                                 |
|--------------------------------------------|--------------------------------------------------------------------------|-----------------------------------------------------------------------------|
| Fichier de sauvegarde manquant ou vide     | `jq` renvoie une erreur ou le compte est zéro                            | Ajouter une étape de vérification ; vérifier la disponibilité du stockage  |
| La restauration échoue en raison de doublons | Le serveur d'API rejette les événements avec le même nom                 | Utiliser `kubectl replace` ou supprimer les événements existants avant la restauration |
| Permissions RBAC incorrectes               | `kubectl get events` renvoie Forbidden                                  | Mettre à jour les rôles du compte de service                               |
| Expiration du TTL des événements avant la sauvegarde | Certains événements manquent dans la sauvegarde                         | Réduire l'intervalle de sauvegarde ou augmenter `--event-ttl`              |
| Incompatibilité de version d'API           | Les événements ne sont pas reconnus lors de la restauration              | Convertir entre core v1 et events.k8s.io/v1 si nécessaire                  |

### Retour en arrière et récupération

Si une tentative de restauration cause des problèmes (par exemple, des événements indésirables inondent le cluster), vous pouvez supprimer tous les événements restaurés dans un espace de noms :

```bash
kubectl delete events --all -n votre-espace-de-noms
```

Avertissement : cela supprime tous les événements, y compris les événements en direct. Pour être plus sélectif, étiquetez les événements restaurés avant de les appliquer, puis supprimez-les par étiquette.

Exemple de retour en arrière sélectif :

- Lors de la restauration, ajoutez une étiquette personnalisée en modifiant le fichier de sauvegarde avant de l'appliquer. Vous pouvez utiliser `jq` pour ajouter une étiquette à tous les événements de la sauvegarde :

```bash
jq '.items[].metadata.labels.restored = "true"' events-backup.json > events-backup-with-label.json
kubectl apply -f events-backup-with-label.json
```

- Pour revenir en arrière, supprimez les événements avec cette étiquette :

```bash
kubectl delete events -n votre-espace-de-noms -l restored=true
```

### Procédure de restauration

Pour restaurer des événements à partir d'un fichier de sauvegarde, vous devez recréer chaque objet événement. Comme les événements sont immuables dans certains champs (par exemple, `eventTime` pour events.k8s.io), vous devrez peut-être supprimer certains champs comme `metadata.resourceVersion`, `metadata.uid` et `eventTime` avant de les appliquer. Utilisez un script pour nettoyer et appliquer :

```bash
jq 'del(.items[].metadata.resourceVersion, .items[].metadata.uid, .items[].eventTime)' events-backup.json | kubectl apply -f -
```

Sortie attendue : `event/event-name created` pour chaque événement (ou `configured` s'il existe).

Important : l'API des événements core v1 ne prend pas en charge `apply` ; vous devrez peut-être utiliser `kubectl create` après le nettoyage. Pour events.k8s.io, `apply` fonctionne si vous omettez les champs immuables.

Pour les événements core v1, utilisez une boucle pour créer chaque événement individuellement après le nettoyage :

```bash
while read -r event; do
  echo "$event" | kubectl create -f -
done < <(jq -c '.items[]' cleaned-events.json)
```

Alternativement, utilisez `kubectl replace` si l'événement existe déjà et que vous voulez le mettre à jour (bien que les événements soient largement immuables, certains champs peuvent être mis à jour).

## Liste de contrôle des opérations

Utilisez la liste de contrôle suivante pour les opérations de sauvegarde d'événements en continu :

- [ ] Inventorier les versions de Kubernetes et de l'API Events ; les enregistrer dans le runbook. Exemple : Kubernetes v1.29, API Events events.k8s.io/v1.
- [ ] Confirmer les permissions RBAC pour le compte de service de sauvegarde (le cas échéant). Vérifier avec `kubectl auth can-i get events --as=system:serviceaccount:backup-tools:event-backup-sa -n votre-espace-de-noms`.
- [ ] Sélectionner l'espace de noms pilote et documenter le volume d'événements. Exemple : `kubectl get events -n default --no-headers | wc -l` renvoie 120 événements dans la dernière heure.
- [ ] Exécuter la sauvegarde manuelle avec `kubectl get events -n <ns> -o json > backup.json`.
- [ ] Valider la sauvegarde : compter les événements, vérifier que le fichier n'est pas vide, inspecter un événement d'exemple.
- [ ] Tester la restauration dans un espace de noms hors production d'abord. Utiliser un espace de noms séparé comme `test-restore` et nettoyer après.
- [ ] Configurer l'automatisation (CronJob) seulement après que la validation manuelle réussit.
- [ ] Configurer des alertes de surveillance pour les échecs de job de sauvegarde (par exemple, vérifier le statut du CronJob ou définir une alerte Prometheus sur `kube_job_status_failed`).
- [ ] Planifier des exercices de restauration périodiques (par exemple, trimestriels) pour s'assurer que les sauvegardes sont utilisables.
- [ ] Réviser et mettre à jour la politique de rétention des sauvegardes ; supprimer les anciennes sauvegardes du stockage. Exemple : conserver les 30 dernières sauvegardes quotidiennes, supprimer automatiquement les plus anciennes.

Exemple de commande de surveillance pour les échecs de CronJob :

```bash
kubectl get jobs -n backup-tools -l job-name=event-backup-<suffix> --field-selector status.successful=0
```

Si un job n'a pas réussi, examinez les journaux avec `kubectl logs job/event-backup-<suffix> -n backup-tools`.

Pour une alerte plus robuste, vous pouvez configurer une règle d'alerte Prometheus comme :

```yaml
groups:
- name: kubernetes-events
  rules:
  - alert: EventBackupJobFailed
    expr: kube_job_status_failed{job_name=~"event-backup-.*", namespace="backup-tools"} > 0
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "Échec du job de sauvegarde d'événements"
      description: "Le CronJob event-backup a échoué. Consultez les journaux pour plus de détails."
```

## Conclusion

La sauvegarde des événements Kubernetes est une pratique à faible effort et à forte valeur pour le dépannage et la conformité. Commencez par un projet pilote étroit : sauvegardez manuellement les événements d'un espace de noms, vérifiez le fichier et testez la restauration. Ensuite, automatisez avec un CronJob si nécessaire. Utilisez la liste de contrôle des opérations pour maintenir un processus fiable. En suivant les exemples de ce guide, vous pouvez préserver l'historique des événements du cluster et le récupérer en cas de besoin, réduisant les temps d'arrêt et améliorant la réponse aux incidents.