Fluentd Fluentd

Logs zuverlässig senden: Output-Plugins und Buffering

Installiere ein Output-Plugin, route verschiedene Quellen zu verschiedenen Zielen und konfiguriere Buffering, damit ein ausgefallenes Backend keine Daten verliert.

12 min Fortgeschritten

Logs zu sammeln und zu parsen ist nur die halbe Pipeline. Sie zuverlässig irgendwohin zu bekommen, auch wenn das Ziel vorübergehend nicht erreichbar ist, ist die andere Hälfte. Diese Anleitung behandelt die Installation eines Output-Plugins, das Routen mehrerer Quellen zu eigenen Zielen und die Buffering-Konfiguration, die Zustellung tatsächlich zuverlässig statt nur nach bestem Bemühen macht.

Ein Output-Plugin installieren

Fluentds eingebaute Outputs decken die Grundlagen ab (file, stdout, forward an eine andere Fluentd-Instanz), aber die meisten echten Ziele – Elasticsearch, Cloud-Speicher, eine SaaS-Log-Plattform – kommen als separate Plugins, die du mit fluent-gem installierst, dem von Fluentd verwalteten Wrapper um RubyGems:

sudo fluent-gem install fluent-plugin-elasticsearch

fluent-gem statt eines bloßen gem install zu nutzen ist wichtig: Es installiert in die Ruby-Umgebung, die Fluentd tatsächlich verwendet, statt in das Standard-Ruby des Systems, was eine häufige Quelle für das Missverständnis „ich habe das Plugin installiert, aber Fluentd sagt trotzdem, es fehlt“ ist. Wenn du Fluentd als Container betreibst, installiere das Plugin als Teil des Baus eines eigenen Images auf Basis des offiziellen, statt es von Hand in einen laufenden Container zu installieren, damit es beim nächsten Start dieses Containers tatsächlich vorhanden ist.

Den Output konfigurieren

Einmal installiert, ist ein Elasticsearch-Ziel nur ein weiterer <match>-Block:

<match apache.access>
  @type elasticsearch
  host elasticsearch
  port 9200
  index_name fluentd-apache
</match>

Verschiedene Quellen zu verschiedenen Zielen routen

Nichts verlangt, dass jede Quelle am selben Ort landet. Mehrere <match>-Blöcke, jeweils auf ein anderes Tag beschränkt, senden verschiedene Daten aus derselben Konfiguration an verschiedene Ziele:

<match apache.access>
  @type elasticsearch
  host elasticsearch
  port 9200
  index_name fluentd-apache
</match>

<match docker.**>
  @type elasticsearch
  host elasticsearch
  port 9200
  index_name fluentd-docker
</match>

<match app.**>
  @type forward
  <server>
    host aggregator.internal
    port 24224
  </server>
</match>

Anwendungslogs gehen in einen Index, Container-Logs in einen anderen, und eine dritte Quelle wird zur weiteren Verarbeitung an eine völlig separate Fluentd-Instanz weitergeleitet, alles in derselben Pipeline. So lässt sich auch eine einzelne Quelle gleichzeitig an mehr als ein Ziel senden: Definiere zwei separate <match>-Blöcke, die dasselbe Tag treffen (oder nutze einen <copy>-Abschnitt), denn eine einzelne Fluentd-Pipeline ist nicht auf einen Output pro Quelle beschränkt.

Buffering: was Zustellung tatsächlich zuverlässig macht

Standardmäßig puffert ein Plugin im Speicher, bevor es an sein Ziel schreibt. Das ist schnell, bedeutet aber, dass ein Absturz oder Neustart von Fluentd alles verliert, was noch nicht geflusht war. Konfiguriere für alles, bei dem der Verlust von Log-Daten im Flug zählt, stattdessen einen expliziten File Buffer, sodass gepufferte Einträge auf die Platte geschrieben werden und einen Neustart überleben:

<match apache.access>
  @type elasticsearch
  host elasticsearch
  port 9200
  index_name fluentd-apache

  <buffer>
    @type file
    path /var/log/fluent/buffer/apache
    flush_interval 5s
    retry_max_times 10
    retry_wait 5s
  </buffer>
</match>

Das ist das Verhalten, das Leute oft als „Fluentd verliert bei einem Neustart keine Daten“ beschreiben, aber es lohnt sich, präzise zu sein: Es stimmt wegen eines konfigurierten File Buffers, nicht automatisch. Bei einem Memory Buffer verliert ein Absturz mitten im Flush weiterhin alles, was in der Warteschlange war. Wenn zuverlässige Zustellung für ein bestimmtes Ziel zählt, konfiguriere den File Buffer dafür explizit, statt anzunehmen, dass der Standard das abdeckt.

Mit einem vorübergehend ausgefallenen Ziel umgehen

Dieselbe Buffering-Konfiguration ist es, die ein ausgefallenes Backend elegant behandelt. Wird Elasticsearch (oder was auch immer das Ziel ist) unerreichbar, sammeln sich Einträge im Buffer, statt verworfen zu werden, und Fluentd wiederholt die Zustellung nach dem Zeitplan, den retry_wait und retry_max_times definieren, wobei die gepufferten Daten in der Zwischenzeit sicher auf der Platte liegen, wenn du einen File Buffer konfiguriert hast. Sobald das Ziel wieder erreichbar ist, holt Fluentd dort auf, wo es aufgehört hat. Das macht einen kurzen Netzwerkaussetzer oder einen Backend-Neustart zum Nicht-Ereignis statt zu einer Lücke in deinen Logs.

Schwärzen und Anreichern vor dem endgültigen Output

Ein <filter> läuft weiterhin vor dem passenden Output, wo auch immer er zwischen Source und Match sitzt, sodass sensible Daten unmittelbar vor Erreichen des Ziels entfernt werden können:

<filter apache.access>
  @type record_transformer
  remove_keys remote_addr, user_agent
</filter>

record_transformer ist dasselbe Plugin, das zur Anreicherung genutzt wird (siehe das Hostname-Beispiel der vorherigen Anleitung); remove_keys ist nur die andere Richtung, Felder entfernen statt hinzufügen. Das ist ein vernünftiger Ort, alles Sensible zu schwärzen – eine E-Mail-Adresse, ein Session-Token, eine interne IP –, bevor es deine eigene Infrastruktur in Richtung eines Drittanbieter-Ziels verlässt, statt sich darauf zu verlassen, dass das Ziel das hinterher korrekt behandelt.

Beliebte Anleitungen