## Introduction

Automatiser la journalisation Kubernetes avec CI/CD comble le fossé entre la détection d'un problème et la livraison d'un correctif vérifié. Au lieu de modifier manuellement les configurations sous pression, les équipes peuvent codifier l'ensemble du flux de travail : vérifications de version, changements ciblés, vérification automatisée et retour en arrière. Ce guide fournit des exemples pratiques étape par étape pour les développeurs, les consultants DevOps et les équipes de démarrage qui souhaitent apporter une rigueur opérationnelle à leur pile de journalisation.

Nous couvrirons les pratiques essentielles : réaliser un inventaire des versions et de l'environnement, apporter des modifications de configuration sécurisées, vérifier le résultat avec des diagnostics, planifier les échecs et la reprise, et maintenir une liste de contrôle opérationnelle. Chaque recommandation est limitée à une version, observable et réversible lorsque la technologie le permet. L'accent est mis sur la sécurité opérationnelle : observer avant de changer, limiter le rayon d'impact, protéger les secrets, vérifier les résultats et documenter les chemins de reprise.

À la fin, vous serez en mesure d'appliquer ces flux de travail à votre propre infrastructure de journalisation Kubernetes, que vous utilisiez Fluentd, Fluent Bit, Loki ou une autre pile. Commençons par comprendre votre environnement actuel.

## Inventaire des versions et de l'environnement

Avant de modifier quoi que ce soit, vous devez avoir une image claire de ce qui est en cours d'exécution. Un inventaire des versions et de l'environnement répond aux questions : quels composants de journalisation sont déployés, quelles sont leurs versions, quels sont les prérequis et quel est leur état actuel ? Cela évite les incompatibilités accidentelles et vous aide à choisir des modifications compatibles.

Commencez par des commandes en lecture seule pour observer le cluster. Supposons que vous utilisiez Fluent Bit comme DaemonSet pour collecter les journaux et les envoyer à un stockage central. Pour obtenir une vue complète, exécutez :

```bash
kubectl get pods -n logging -o wide
```

La sortie attendue pourrait ressembler à :

```
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE
fluent-bit-abcde         1/1     Running   0          5d    10.0.1.23     node-1
fluent-bit-fghij         1/1     Running   0          5d    10.0.2.17     node-2
fluent-bit-klmno         1/1     Running   0          5d    10.0.3.42     node-3
```

Ensuite, vérifiez la version de Fluent Bit pour assurer la compatibilité avec votre configuration et les plugins éventuels :

```bash
kubectl exec -n logging deploy/fluent-bit -- /fluent-bit/bin/fluent-bit --version
```

La sortie doit inclure une version comme `Fluent Bit v2.1.10`. Notez cette version, la version du cluster Kubernetes (`kubectl version --short`) et le runtime de conteneur (par exemple, `containerd://1.7.2` depuis `kubectl get nodes -o wide`). Pour des informations détaillées sur la planification et les événements, utilisez :

```bash
kubectl describe pod -n logging fluent-bit-abcde
```

Regardez la section `Events` pour tout avertissement, tel que `FailedScheduling` ou `BackOff`. Pour les conteneurs en boucle de crash, vérifiez les journaux précédents :

```bash
kubectl logs -n logging fluent-bit-abcde --previous
```

Inspectez également la configuration déployée pour comprendre quelles entrées, filtres et sorties sont actifs :

```bash
kubectl get configmap -n logging fluent-bit-config -o yaml
```

Un inventaire solide inclut également la topologie de bout en bout du pipeline de journalisation. Notez où les journaux sont envoyés : par exemple, vers Loki à `http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push`, ou vers Elasticsearch à `http://elasticsearch.logging.svc:9200`. Vérifiez l'existence du service :

```bash
kubectl get svc -n logging
```

Une fois que vous avez capturé l'état actuel, enregistrez-le pour une comparaison ultérieure. Par exemple, écrivez la sortie de `kubectl get pods -n logging -o yaml` dans un fichier horodaté :

```bash
kubectl get pods -n logging -o yaml > logging-pods-$(date +%Y%m%d-%H%M%S).yaml
```

Cet inventaire devient votre référence. Il vous aide à détecter les dérives après les modifications et soutient le retour en arrière si nécessaire.

## Chemin de configuration sécurisé

Avec un inventaire clair en main, vous pouvez planifier un changement minimal. Le chemin de configuration sécurisé signifie appliquer une modification ciblée à la fois, la vérifier et avoir un retour en arrière prêt. Ne jamais déverser un gros refactoring en production sans vérifications incrémentales.

Supposons que votre configuration Fluent Bit contienne un filtre qui supprime toutes les lignes de journalisation d'un espace de noms bruyant, mais qu'il utilise par erreur un motif incorrect. Par exemple, le `fluent-bit.conf` actuel contient :

```
[FILTER]
    Name                grep
    Match               kube.*
    Exclude             namespace noisy-ns
```

Si l'espace de noms est en réalité `noisy-namespace`, aucun journal n'est exclu de cet espace de noms. Le changement sécurisé consiste à mettre à jour la ligne `Exclude` en `namespace noisy-namespace`.

Avant de modifier, examinez le ConfigMap actuel :

```bash
kubectl get configmap -n logging fluent-bit-config -o yaml
```

Faites une sauvegarde du ConfigMap actuel :

```bash
kubectl get configmap -n logging fluent-bit-config -o yaml > fluent-bit-config-backup.yaml
```

Ensuite, appliquez le changement minimal. Vous pouvez le faire en modifiant le ConfigMap sur place :

```bash
kubectl edit configmap -n logging fluent-bit-config
```

Alternativement, utilisez une approche déclarative avec un patch. Supposons que le ConfigMap ait une clé `fluent-bit.conf` avec la section filtre. Vous pouvez le patcher avec un nouveau fichier. Créez `fluent-bit-config-patch.yaml` avec seulement la section modifiée :

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluent-bit-config
  namespace: logging
data:
  fluent-bit.conf: |
    [INPUT]
        Name              tail
        Path              /var/log/containers/*.log
        Parser            docker
        Tag               kube.*
    [FILTER]
        Name                grep
        Match               kube.*
        Exclude             namespace noisy-namespace
    [OUTPUT]
        Name                loki
        Match               *
        Host                loki.monitoring.svc.cluster.local
        Port                3100
        Labels              job=fluent-bit
```

Puis appliquez :

```bash
kubectl apply -f fluent-bit-config-patch.yaml
```

Après l'application, redémarrez les pods Fluent Bit pour recharger la configuration :

```bash
kubectl rollout restart -n logging daemonset/fluent-bit
```

Vérifiez ensuite l'état du déploiement :

```bash
kubectl rollout status -n logging daemonset/fluent-bit
```

La sortie attendue :

```
daemon set "fluent-bit" successfully rolled out
```

Pendant ce processus, évitez d'exposer les secrets. Si votre configuration inclut des informations d'identification (par exemple, pour l'authentification au stockage de journaux), assurez-vous qu'elles sont stockées dans un Secret Kubernetes et référencées via des variables d'environnement ou des fichiers montés, pas codées en dur dans le ConfigMap. Par exemple, si Loki nécessite un mot de passe, utilisez :

```yaml
[OUTPUT]
    Name                loki
    Match               *
    Host                ${LOKI_HOST}
    Port                3100
    Http_User           ${LOKI_USERNAME}
    Http_Passwd         ${LOKI_PASSWORD}
```

Et définissez ces variables d'environnement dans le DaemonSet à partir d'un Secret. Cela protège les données sensibles et rend la configuration portable.

Gardez les tests locaux limités : avant de pousser vers un cluster de production, vous pouvez tester la configuration Fluent Bit localement avec un conteneur Docker :

```bash
docker run --rm -v /path/to/fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf fluent/fluent-bit:2.1.10 /fluent-bit/bin/fluent-bit -c /fluent-bit/etc/fluent-bit.conf
```

Observez les journaux de démarrage pour détecter toute erreur de syntaxe. Une fois vérifié, procédez au cluster.

## Vérification et diagnostics

Après avoir appliqué un changement, vous devez vérifier qu'il fonctionne réellement. Cela signifie vérifier les journaux, les métriques et le pipeline de bout en bout. Ne supposez pas le succès ; prouvez-le.

Pour le changement de filtre Fluent Bit, la vérification est simple : générez un journal de test dans l'espace de noms bruyant et confirmez qu'il n'atteint pas le stockage de journaux. Tout d'abord, créez un pod d'exemple dans `noisy-namespace` qui écrit une ligne sur stdout :

```bash
kubectl run test-logger -n noisy-namespace --image=busybox --restart=Never -- /bin/sh -c 'echo "This is a test log from noisy-namespace" && sleep 3600'
```

Attendez que le pod démarre :

```bash
kubectl wait --for=condition=ready pod/test-logger -n noisy-namespace --timeout=60s
```

Ensuite, vérifiez les journaux de Fluent Bit pour voir si la ligne a été traitée et filtrée :

```bash
kubectl logs -n logging daemonset/fluent-bit --since=5m | grep "test log"
```

Vous ne devriez pas voir la ligne de journal si le filtre est correct. Si vous la voyez, le filtre peut ne pas être appliqué, peut-être parce que le tag ne correspond pas. Dans ce cas, examinez la configuration Fluent Bit dans le pod en cours d'exécution :

```bash
kubectl exec -n logging daemonset/fluent-bit -- cat /fluent-bit/etc/fluent-bit.conf
```

Confirmez que le filtre est présent et que le motif `Match` inclut le tag du pod. Les journaux de pod Kubernetes ont généralement des tags comme `kube.var.log.containers.<pod_name>_<namespace>_<container_name>-<container_id>.log`. Puisque notre entrée utilise `Tag kube.*`, le filtre `Match kube.*` devrait être correct.

De plus, interrogez le stockage de journaux (dans ce cas, Loki) directement via son API HTTP. Utilisez `kubectl port-forward` pour accéder au service Loki localement :

```bash
kubectl port-forward -n monitoring svc/loki 3100:3100
```

Dans un autre terminal, exécutez une requête LogQL pour rechercher le journal de test :

```bash
curl -G -s  'http://localhost:3100/loki/api/v1/query_range' --data-urlencode 'query={namespace="noisy-namespace"}' --data-urlencode 'start=5m' | jq '.data.result'
```

Résultat attendu : aucune entrée pour le journal de test. Si vous oubliez d'exclure cet espace de noms ou utilisez un mauvais motif, vous verrez des entrées, indiquant que le filtre a échoué.

Collectez également des métriques : Fluent Bit expose des métriques Prometheus sur `:2020/api/v1/metrics/prometheus`. Vérifiez que les compteurs de filtres supprimés ont augmenté :

```bash
kubectl exec -n logging daemonset/fluent-bit -- curl -s localhost:2020/api/v1/metrics/prometheus | grep -E 'fluentbit_filter_drop_records_total|fluentbit_output_proc_records_total'
```

Vous devriez voir un compteur de records supprimés incrémenté après le test. Par exemple, `fluentbit_filter_drop_records_total{name="grep.0"} 5`. Cela confirme que le filtre supprime activement des enregistrements.

Enfin, vérifiez que les journaux des pods sont propres : aucune erreur de Fluent Bit concernant des problèmes de connexion ou des échecs de rechargement de configuration :

```bash
kubectl logs -n logging daemonset/fluent-bit --tail=20
```

Recherchez des lignes comme `[error] [output:loki:loki.0]` indiquant un problème d'envoi de journaux. Si tout est clair, le changement est vérifié.

## Modes de défaillance et reprise

Même avec une vérification minutieuse, des échecs surviennent. La marque d'un processus robuste est que vous pouvez récupérer rapidement et sans conjecture. Dans cette section, nous identifierons les modes de défaillance courants pour l'automatisation de la journalisation et fournirons des procédures de reprise.

### Mode de défaillance 1 : une configuration invalide provoque un CrashLoopBackOff de Fluent Bit

Si vous appliquez une configuration avec une erreur de syntaxe ou une mauvaise référence de plugin, les pods Fluent Bit peuvent entrer en `CrashLoopBackOff`. Pour détecter :

```bash
kubectl get pods -n logging
```

Vous verrez quelque chose comme :

```
NAME                     READY   STATUS             RESTARTS   AGE
fluent-bit-abcde         0/1     CrashLoopBackOff   5          10m
```

Vérifiez les journaux du pod :

```bash
kubectl logs -n logging fluent-bit-abcde --previous
```

Vous verrez probablement une erreur telle que `[error] [config] error in /fluent-bit/etc/fluent-bit.conf: syntax error` ou `[error] [filter:grep:grep.0] invalid pattern`. Pour récupérer, revenez au ConfigMap précédent. Puisque vous avez fait une sauvegarde plus tôt, réappliquez-la :

```bash
kubectl apply -f fluent-bit-config-backup.yaml
```

Ensuite, redémarrez le DaemonSet :

```bash
kubectl rollout restart -n logging daemonset/fluent-bit
```

Surveillez le déploiement :

```bash
kubectl rollout status -n logging daemonset/fluent-bit
```

En cas de succès, les pods reviendront à `Running`. Réévaluez ensuite votre changement, peut-être en testant localement avec la commande Docker de la section précédente avant de réappliquer.

### Mode de défaillance 2 : le stockage de journaux est inaccessible en raison d'une politique réseau ou DNS

Parfois, la configuration Fluent Bit est correcte, mais il ne peut pas atteindre Loki ou Elasticsearch. Symptômes : les pods fonctionnent mais les journaux montrent des erreurs de sortie comme `[error] [engine] chunk '1-1690000000.123456.flb' cannot be retried: error contacting server`. Vérifiez la connectivité depuis un pod Fluent Bit :

```bash
kubectl exec -n logging fluent-bit-abcde -- nslookup loki.monitoring.svc.cluster.local
```

Si la résolution DNS échoue, vérifiez le service et l'espace de noms. Si le DNS se résout, testez l'accessibilité HTTP :

```bash
kubectl exec -n logging fluent-bit-abcde -- wget -O- http://loki.monitoring.svc.cluster.local:3100/ready
```

Options de reprise : ajustez l'URL du service, assurez-vous que les politiques réseau autorisent le trafic sur le port 3100, ou corrigez le déploiement Loki lui-même (par exemple, augmentez les réplicas). Une fois corrigé, Fluent Bit reprendra automatiquement l'envoi des journaux.

### Mode de défaillance 3 : le filtre supprime trop de journaux

Peut-être que votre motif de filtre est trop large. Par exemple, vous vouliez supprimer uniquement les journaux de noisy-namespace, mais en raison d'une regex, vous avez également supprimé des journaux critiques d'autres espaces de noms. Détection : votre système d'alerte montre des journaux manquants pour un service critique, ou votre requête au stockage de journaux ne renvoie rien pour ce service. Examinez le filtre et corrigez-le. Pour éviter cela, testez toujours les filtres dans un environnement de staging avec des données de journal représentatives avant le déploiement en production.

### Principes généraux de reprise

- Ayez toujours une sauvegarde de tout ConfigMap, Secret ou manifeste que vous modifiez.
- Utilisez le contrôle de version pour vos manifestes Kubernetes et fichiers de configuration.
- Pour les changements de configuration, préférez les mises à jour progressives au remplacement immédiat de tous les pods pour réduire l'impact.
- Si un changement provoque une défaillance généralisée, utilisez `kubectl rollout undo` pour les Deployments ou réappliquez le ConfigMap précédent comme indiqué.
- Documentez les étapes de reprise dans votre runbook, pas seulement dans cet article.

## Liste de contrôle opérationnelle

Cette liste de contrôle résume le flux de travail sécurisé pour automatiser les changements de journalisation Kubernetes. Utilisez-la comme guide pré-vol et post-changement.

### Pré-changement

- [ ] Vérifiez l'accès au cluster : `kubectl cluster-info` et `kubectl auth can-i get pods -n logging --as=system:serviceaccount:default:default` (ajustez pour votre compte de service).
- [ ] Vérifiez l'état actuel des pods : `kubectl get pods -n logging -o wide` ; assurez-vous que tous sont en cours d'exécution.
- [ ] Enregistrez la version actuelle de Fluent Bit et le hash de configuration : `kubectl get configmap -n logging fluent-bit-config -o yaml | sha256sum`.
- [ ] Sauvegardez le ConfigMap actuel et les Secrets associés : `kubectl get configmap,secret -n logging -o yaml > backup-$(date +%Y%m%d).yaml`.
- [ ] Identifiez le changement exact nécessaire et justifiez-le dans un ticket ou un message de commit.
- [ ] Vérifiez les prérequis : le changement nécessite-t-il une version plus récente de Fluent Bit ? Vérifiez par rapport à l'inventaire des versions.

### Pendant le changement

- [ ] Appliquez un changement à la fois en utilisant `kubectl apply` ou `kubectl edit`.
- [ ] Redémarrez uniquement le composant affecté, par exemple, `kubectl rollout restart -n logging daemonset/fluent-bit`.
- [ ] Surveillez le déploiement : `kubectl rollout status -n logging daemonset/fluent-bit`.
- [ ] Surveillez les journaux pour les erreurs : `kubectl logs -n logging daemonset/fluent-bit --tail=50`.
- [ ] Si vous utilisez GitOps (par exemple, Argo CD ou Flux), assurez-vous que le changement est promu via le pipeline et observez l'état de synchronisation.

### Vérification post-changement

- [ ] Générez des journaux de test dans les espaces de noms affectés : `kubectl run test-logger -n noisy-namespace --image=busybox --restart=Never -- /bin/sh -c 'echo test && sleep 60'`.
- [ ] Interrogez le stockage de journaux (par exemple, Loki, Elasticsearch) pour vérifier l'inclusion/exclusion comme prévu.
- [ ] Vérifiez les métriques Fluent Bit pour les compteurs supprimés/traités.
- [ ] Confirmez l'absence d'erreurs dans les journaux Fluent Bit pendant au moins 5 minutes.
- [ ] Nettoyez les pods de test : `kubectl delete pod test-logger -n noisy-namespace`.

### Préparation au retour en arrière

- [ ] Gardez le fichier de sauvegarde accessible.
- [ ] Connaissez la commande de retour en arrière : `kubectl apply -f backup-<date>.yaml`.
- [ ] Si un retour en arrière est effectué, vérifiez à nouveau avec les mêmes étapes de vérification.
- [ ] Documentez l'incident et mettez à jour la liste de contrôle si nécessaire.

En suivant cette liste de contrôle, vous réduisez le risque de temps d'arrêt non intentionnel et construisez une culture de changements sûrs et réversibles.

## Conclusion

Automatiser la journalisation Kubernetes avec CI/CD est plus que d'exécuter quelques commandes ; c'est une approche disciplinée de la gestion du changement dans un système complexe. Nous avons parcouru un cycle complet : inventorier votre environnement, apporter un changement de configuration sécurisé, vérifier son effet avec des diagnostics, planifier les échecs et utiliser une liste de contrôle opérationnelle.

Le point clé à retenir est de toujours observer d'abord, limiter le rayon d'impact, protéger les données sensibles et vérifier avant de célébrer le succès. Lorsque quelque chose tourne mal, vos sauvegardes et procédures documentées seront votre bouée de sauvetage. Intégrez ces pratiques dans vos pipelines CI/CD – par exemple, exécutez automatiquement `kubectl apply --dry-run=client` sur chaque pull request, lancez des tests locaux sur les changements de configuration et appliquez un processus de revue qui vérifie la présence d'un plan de retour en arrière.

Commencez petit : choisissez un changement de configuration de journalisation à faible risque, appliquez ce flux de travail et mesurez les résultats. Au fur et à mesure que vous gagnez en confiance, étendez-vous à des automatisations plus complexes. Rappelez-vous, l'objectif n'est pas seulement d'expédier des journaux, mais de le faire de manière fiable et sûre, en veillant à ce que votre pile d'observabilité soit elle-même observable et résiliente.

Maintenant, allez faire de votre pipeline de journalisation Kubernetes un modèle d'excellence opérationnelle.