Fluent Bit est un collecteur de logs ultra-léger, écrit en C, projet CNCF Graduated. Il consomme quelques mégaoctets de mémoire et s'est imposé comme l'agent de collecte de logs de référence sur chaque nœud Kubernetes, avant d'envoyer vers un agrégateur ou un backend comme Loki ou Elasticsearch.
Ce guide s'adresse aux profils intermédiaires et avancés qui exploitent des logs à grande échelle. Vous allez installer Fluent Bit, comprendre son pipeline (input, parser, filter, output), le configurer pour Kubernetes, écrire des parsers et router les logs vers Loki.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Comprendre le pipeline Fluent Bit : input, parser, filter, output.
- Installer Fluent Bit proprement (dépôt signé, image épinglée).
- Collecter les logs de conteneurs et les enrichir avec les métadonnées Kubernetes.
- Écrire des parsers pour structurer les logs bruts.
- Router les logs vers Loki, Elasticsearch ou un agrégateur.
Pourquoi Fluent Bit ?
Section intitulée « Pourquoi Fluent Bit ? »Fluent Bit est conçu pour les environnements contraints en ressources et les architectures cloud-native à grande échelle.
| Caractéristique | Description |
|---|---|
| Licence | Apache 2.0 |
| Maturité | CNCF Graduated |
| Langage | C |
| Mémoire | ~1 MB |
| Throughput | 100k+ events/sec |
Fluent Bit vs Fluentd
Section intitulée « Fluent Bit vs Fluentd »| Critère | Fluent Bit | Fluentd |
|---|---|---|
| Mémoire | ~1 MB | ~40 MB |
| Langage | C | Ruby |
| Plugins | 100+ intégrés | 500+ externes |
| Rôle | Collecte (edge) | Agrégation (central) |
| Performances | Plus rapide | Plus flexible |
Architecture
Section intitulée « Architecture »┌─────────────────────────────────────────────────────────────────┐│ Fluent Bit Pipeline ││ ││ ┌────────┐ ┌────────┐ ┌─────────────┐ ┌──────────────────┐ ││ │ Input │──│ Parser │──│ Filter │──│ Output │ ││ └────────┘ └────────┘ └─────────────┘ └──────────────────┘ ││ ││ - tail - JSON - kubernetes - loki ││ - systemd - regex - record_modifier - elasticsearch ││ - forward - logfmt - grep - forward ││ - syslog - docker - lua - prometheus_exporter│└─────────────────────────────────────────────────────────────────┘Installation
Section intitulée « Installation »# Clé GPG officielle Fluent Bit (dépôt signé, pas de pipe-to-shell)sudo mkdir -p /usr/share/keyringscurl -fsSL https://packages.fluentbit.io/fluentbit.key \ | sudo gpg --dearmor -o /usr/share/keyrings/fluentbit-keyring.gpg
# Dépôt signé (adapter le nom de version : noble, jammy, bookworm...)echo "deb [signed-by=/usr/share/keyrings/fluentbit-keyring.gpg] https://packages.fluentbit.io/ubuntu/noble noble main" \ | sudo tee /etc/apt/sources.list.d/fluent-bit.list
sudo apt-get update && sudo apt-get install -y fluent-bitsudo systemctl enable --now fluent-bit
fluent-bit --versiondocker run -d \ --name fluent-bit \ -v /var/log:/var/log:ro \ -v $(pwd)/fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf \ fluent/fluent-bit:4.0.5helm repo add fluent https://fluent.github.io/helm-chartshelm repo update
helm install fluent-bit fluent/fluent-bit \ --namespace logging \ --create-namespace \ -f values.yamlConfiguration
Section intitulée « Configuration »Fluent Bit supporte deux formats de configuration : classique et YAML.
Format classique (.conf)
Section intitulée « Format classique (.conf) »[SERVICE] flush 1 log_level info parsers_file parsers.conf
[INPUT] name tail path /var/log/containers/*.log tag kube.* parser docker
[FILTER] name kubernetes match kube.*
[OUTPUT] name stdout match *Format YAML (recommandé Kubernetes)
Section intitulée « Format YAML (recommandé Kubernetes) »service: flush: 1 log_level: info
pipeline: inputs: - name: tail path: /var/log/containers/*.log tag: kube.* parser: cri
filters: - name: kubernetes match: kube.* merge_log: on k8s-logging.parser: on
outputs: - name: loki match: "*" host: loki-gateway port: 3100 labels: job=fluentbitCollecte Kubernetes
Section intitulée « Collecte Kubernetes »Configuration complète
Section intitulée « Configuration complète »config: service: | [SERVICE] Daemon Off Flush 1 Log_Level info Parsers_File parsers.conf HTTP_Server On HTTP_Listen 0.0.0.0 HTTP_Port 2020 Health_Check On
inputs: | [INPUT] Name tail Path /var/log/containers/*.log multiline.parser docker, cri Tag kube.* Mem_Buf_Limit 50MB Skip_Long_Lines On Refresh_Interval 10
filters: | [FILTER] Name kubernetes Match kube.* Merge_Log On Keep_Log Off K8S-Logging.Parser On K8S-Logging.Exclude On Labels On Annotations Off
[FILTER] Name nest Match kube.* Operation lift Nested_under kubernetes Add_prefix kubernetes_
outputs: | [OUTPUT] Name loki Match kube.* Host loki-gateway.logging.svc Port 3100 Labels job=fluentbit, namespace=$kubernetes_namespace_name Remove_keys kubernetes_container_hash,kubernetes_docker_id
customParsers: | [PARSER] Name json Format json Time_Key time Time_Format %Y-%m-%dT%H:%M:%S.%L%zDaemonSet manifest
Section intitulée « DaemonSet manifest »apiVersion: apps/v1kind: DaemonSetmetadata: name: fluent-bit namespace: loggingspec: selector: matchLabels: app: fluent-bit template: metadata: labels: app: fluent-bit spec: serviceAccountName: fluent-bit containers: - name: fluent-bit image: fluent/fluent-bit:4.0.5 ports: - containerPort: 2020 volumeMounts: - name: varlog mountPath: /var/log readOnly: true - name: varlibdockercontainers mountPath: /var/lib/docker/containers readOnly: true - name: config mountPath: /fluent-bit/etc/ resources: limits: memory: 100Mi cpu: 100m requests: memory: 50Mi cpu: 50m volumes: - name: varlog hostPath: path: /var/log - name: varlibdockercontainers hostPath: path: /var/lib/docker/containers - name: config configMap: name: fluent-bit-configLes parsers transforment les logs bruts en structure JSON.
Parsers intégrés
Section intitulée « Parsers intégrés »[PARSER] Name docker Format json Time_Key time Time_Format %Y-%m-%dT%H:%M:%S.%L%z
[PARSER] Name cri Format regex Regex ^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>[^ ]*) (?<log>.*)$ Time_Key time Time_Format %Y-%m-%dT%H:%M:%S.%L%z
[PARSER] Name syslog-rfc3164 Format regex Regex /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/ Time_Key time Time_Format %b %d %H:%M:%S
[PARSER] Name json_logs Format json Time_Key timestamp Time_Format %Y-%m-%dT%H:%M:%S.%LZParser personnalisé
Section intitulée « Parser personnalisé »[PARSER] Name nginx_access Format regex Regex ^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$ Time_Key time Time_Format %d/%b/%Y:%H:%M:%S %zKubernetes metadata
Section intitulée « Kubernetes metadata »Enrichit chaque log avec les métadonnées du pod.
[FILTER] Name kubernetes Match kube.* Kube_URL https://kubernetes.default.svc:443 Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token Merge_Log On K8S-Logging.Parser On K8S-Logging.Exclude On Labels On Annotations OffRecord modifier
Section intitulée « Record modifier »[FILTER] Name record_modifier Match * Record cluster production-us-east-1 Record environment prodGrep (inclusion/exclusion)
Section intitulée « Grep (inclusion/exclusion) »# Exclure les logs de health checks[FILTER] Name grep Match kube.* Exclude log /health|/ready|/metrics/
# Garder seulement les erreurs[FILTER] Name grep Match kube.* Regex level (error|fatal|critical)Lua (transformation avancée)
Section intitulée « Lua (transformation avancée) »[FILTER] Name lua Match * script /fluent-bit/scripts/transform.lua call transform
# transform.luafunction transform(tag, timestamp, record) if record["level"] == nil then record["level"] = "info" end return 1, timestamp, recordend[OUTPUT] Name loki Match * Host loki-gateway Port 3100 Labels job=fluentbit, app=$kubernetes_labels['app'] Line_Format json Auto_Kubernetes_Labels onElasticsearch
Section intitulée « Elasticsearch »[OUTPUT] Name es Match * Host elasticsearch Port 9200 Index logs-%Y.%m.%d Type _doc Suppress_Type_Name On Logstash_Format On Retry_Limit 5Forward (vers Fluentd)
Section intitulée « Forward (vers Fluentd) »[OUTPUT] Name forward Match * Host fluentd-aggregator Port 24224 Require_ack_response TrueMulti-output
Section intitulée « Multi-output »# Dupliquer vers plusieurs destinations[OUTPUT] Name loki Match * Host loki
[OUTPUT] Name s3 Match * bucket my-logs-bucket region eu-west-1 total_file_size 50MMultiline logging
Section intitulée « Multiline logging »Gérer les logs multi-lignes (stack traces Java, Python).
[MULTILINE_PARSER] name java_multiline type regex flush_timeout 1000 rule "start_state" "^(\d{4}-\d{2}-\d{2})" "cont" rule "cont" "^(?!\d{4}-\d{2}-\d{2})" "cont"
[INPUT] name tail path /var/log/app/*.log multiline.parser java_multilineMonitoring
Section intitulée « Monitoring »Métriques HTTP
Section intitulée « Métriques HTTP »[SERVICE] HTTP_Server On HTTP_Listen 0.0.0.0 HTTP_Port 2020
# Endpoints disponibles :# GET /api/v1/health# GET /api/v1/metrics# GET /api/v1/metrics/prometheusPrometheus ServiceMonitor
Section intitulée « Prometheus ServiceMonitor »apiVersion: monitoring.coreos.com/v1kind: ServiceMonitormetadata: name: fluent-bit namespace: loggingspec: selector: matchLabels: app: fluent-bit endpoints: - port: http path: /api/v1/metrics/prometheus interval: 30sBonnes pratiques
Section intitulée « Bonnes pratiques »-
Limitez la mémoire
Configurez
Mem_Buf_Limitpour éviter les OOM.[INPUT]Name tailMem_Buf_Limit 50MB -
Activez les health checks
[SERVICE]Health_Check On -
Utilisez des labels Kubernetes
Filtrez par namespace pour ne pas tout envoyer.
[FILTER]Name grepMatch kube.*Regex kubernetes_namespace_name ^(prod-|staging-) -
Gérez le backpressure
En cas de destination lente, évitez d'accumuler en mémoire.
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
| Logs manquants | Path incorrect | Vérifier le pattern glob |
| Parser échoue | Format non reconnu | Tester avec fluent-bit -c ... -i dummy |
| Mémoire élevée | Buffer plein | Réduire Mem_Buf_Limit |
| Connection refused | Output down | Vérifier la destination |
# Test de configurationfluent-bit -c /etc/fluent-bit/fluent-bit.conf --dry-run
# Mode debugfluent-bit -c /etc/fluent-bit/fluent-bit.conf -vvv
# Parser testecho '{"level":"info","msg":"test"}' | fluent-bit -i stdin -o stdout -p format=jsonFAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »parsers.conf. Un parser transforme une ligne brute en JSON structuré : les parsers json, cri ou docker pour les conteneurs, ou un parser regex personnalisé pour un format applicatif (logs nginx, par exemple). On l'associe à l'input tail ou au filtre Kubernetes.loki : on indique le host et le port de Loki (3100) et les labels à appliquer. Fluent Bit tail les fichiers de logs, les enrichit éventuellement avec les métadonnées Kubernetes, puis pousse chaque entrée vers l'endpoint de Loki. C'est un pipeline validé, lisible ensuite dans Grafana via LogQL.À retenir
Section intitulée « À retenir »- Ultra-léger : ~1 MB de mémoire
- CNCF Graduated : standard Kubernetes
- Parser CRI/Docker : natif pour les conteneurs
- Kubernetes filter : enrichissement auto des métadonnées
- Multi-output : dupliquer vers plusieurs destinations