Fluent an Elasticsearch

Fluent an Elasticsearch

Im 2. Teil soll nun der FluentD seine Daten im ELK speichern.

Dazu gibt es ein fertiges Plugin Fluent Plugin Elasticsearch🖹. Es muss "nur" in das Docker Image eingebunden werden. Dazu dient am besten ein eigenes Image, hier das entsprechende Dockerfile:

 1FROM fluent/fluentd:edge-debian
 2
 3USER root
 4
 5RUN ln -snf /usr/share/zoneinfo/CET /etc/localtime && echo 'CET' >/etc/timezone
 6
 7RUN mkdir /log && chown fluent /log
 8
 9# below RUN includes plugin as examples elasticsearch is not required
10# you may customize including plugins as you wish
11RUN buildDeps="sudo make gcc g++ libc-dev libmariadb-dev"\
12 && apt-get update \
13 && apt-get install -y --no-install-recommends libmariadb3 $buildDeps \
14 && gem uninstall -I elasticsearch \
15 && gem install elasticsearch -v 7.17.0 \
16 && gem install mysql2 --no-document \
17 && gem install fluent-plugin-sql --no-document \
18 && gem install fluent-plugin-elasticsearch \
19 && gem sources --clear-all \
20 && SUDO_FORCE_REMOVE=yes \
21    apt-get purge -y --auto-remove \
22                  -o APT::AutoRemove::RecommendsImportant=false \
23                  $buildDeps \
24 && rm -rf /var/lib/apt/lists/* \
25 && rm -rf /tmp/* /var/tmp/* /usr/lib/ruby/gems/*/cache/*.gem
26
27COPY fluentd.conf /fluentd/etc/fluent.conf
28USER fluent

Das Ding bindet auch gleich ein MySQL Plugin in FluentD ein, weil wir das für Teil 3 benötigen.

Für den Raspberry PI bedarf es eines anderen Source-Images:

1FROM fluent/fluentd:edge-debian-armhf

Der Rest ist gleich.

Der etwas abenteuerliche und längliche RUN Befehl macht mehrere Dinge:

  • installiert Pakete zum Bau der FluentD Plugins, die kommen teilweise als C Sourcen und müssen compiliert werden
  • installiert die mariadb Libs und auch die Develop-Header dazu
  • installiert dann mit gem die Ruby Plugins für FluentD, dabei wird eben z.B. beim mysql2 Plugin compiliert
  • löscht die Pakete wieder, die nur zum Bau nötig waren
  • löscht Caches und sowas

Zuletzt wird die Fluentd.conf ins Image kopiert. Ja, das könnte man auch als Volume mounten.

Sehen wir uns das fluentd.conf für diesen Teil an:

 1# fluentd/conf/fluent.conf
 2
 3<source>
 4  @type forward
 5  port 24224
 6</source>
 7
 8<match *.**>
 9    @type relabel
10    @label @FILES
11</match>
12
13<label @FILES>
14	<match *.**>
15	  @type copy
16	  time_format "%Y-%m-%d %H:%M:%S"
17	
18	  <store>
19			  @type file
20			  path /log/${tag[0]}/log_%Y-%m-%d
21			  append true
22			  <buffer tag,time>
23					timekey 1d
24					flush_mode immediate
25			  </buffer>
26			  <format>
27					@type stdout
28			  </format>
29	  </store> 	  
30	  
31	  <store>
32			  @type elasticsearch
33			  host 192.168.1.2
34			  port 9200
35			  logstash_format true
36			  logstash_prefix fluentd
37			  logstash_dateformat %Y%m
38			  include_timestamp true 
39			  include_tag_key true
40			  tag_key @log_name
41			  index_name fluentd
42			  type_name fluentd
43			  flush_interval 5s
44	  </store>
45	  
46	</match>
47</label>

Das sind gleich viele Dinge. Deshalb der Reihe nach:

Es wird als 1. eine "Source" definiert. Hier vom Type "forward", was bedeutet, dass Port 24224 Logs im Fluent Format empfangen kann. Z.B. aus Docker ( ☛ Stetig locken die Logs)

Der "Match *.**" soll einfach mal alles matchen, da alles ohnehin später verteilt wird. Als Type dient "relabel" und ein "label" Objekt, damit man ggf. doch verschiedene Matches haben kann, die zusätzliche Dinge tun sollen.

Das Label Objekt ist jetzt der spannende Teil:

Durch den "Copy" Type lassen sich mehrere Ziele definieren. In dem Fall Dateien und Elasticsearch!

Die Dateien werden nach ihrem Tag auf Verzeichnisse verteilt, so könnte jede Log-Kategorie eigene Dateien haben.

Den Type "elasticsearch" sehen wir uns genauer an:

host 192.168.1.2
port 9200
# definiert den Elasticsearch Server und Port

logstash_format true
# schreibt die Daten so, wie "logstash" das machen würde - vereinfacht ein paar Optionen 

logstash_prefix fluentd
logstash_dateformat %Y%m
# damit landen die Daten jeweil in einem eigenen Index von EL, "fluentd-YYYYMM" in dem Fall, also Jahr YYYY und Monat MM

include_timestamp true 
include_tag_key true
# packt den Timestamp vom Log und auch den Tag mit ins EL

tag_key @log_name
# definiert den Key Namen für eben jenes Tag "@log_name", könnte auch einfach "tag" sein

index_name fluentd
type_name fluentd
# die braucht es im logstash Modus eigentlich nicht und stehen hier nur, falls jemand den auf "false" setzen will, was wir im späteren Teil machen werden

flush_interval 5s
# wie lange fluentd die Daten erstmal im Speicher hält bevor sie an EL gehen

Bauen des Images:

1DOCKER_BUILDKIT=1 docker build -t myfluentd:latest --rm -f Dockerfile .

Bevor jemand fragt, hier noch das Docker Compose um Fluent zu starten:

 1version: '3.9'
 2
 3services:
 4  fluentd:
 5   hostname: fluentd
 6   image: myfluentd:latest
 7   ports:
 8     - 24224:24224
 9   volumes:
10      - type: volume
11        source: fluentd
12        target: /log
13   deploy:
14      placement:
15         max_replicas_per_node: 1
16         constraints:
17           - node.labels.fluentd == here
18      mode: replicated
19      replicas: 1
20      restart_policy:
21         condition: any
22         delay: 2s
23         max_attempts: 3
24         window: 120s
25      update_config:
26         parallelism: 1
27         delay: 10s
28         order: stop-first
29
30
31volumes:
32 fluentd:
33   driver_opts:
34      type: "nfs"
35      o: "addr=192.168.1.151,nolock,soft,rw,nfsvers=4"
36      device: ":/docker/fluentd" 

siehe auch