Als Testapplikation nutzt unser Setup einen Nginx-Container. Dessen Konfiguration erzeugen wir unter "/root/docker/ nginx", wie zuvor beschrieben mit
»docker-compose.yml.
«
Genau genommen sollte auch hier eine ENV-Datei die Umgebung deklarieren, aber für unser einfaches Beispiel haben wir einfach alles direkt in das Compose-File geschrieben. Dazu gibt es einen Ordner "./config" mit einer sehr simplen Datei "site.conf", in der nur das Folgende steht:
server {
index index.html;
root /www;
}
Ebenfalls unter "/root/docker/nginx/" befindet sich das Verzeichnis "./www" mit einer ganzen Website oder zumindest einer Datei "index.html", die der Nginx-Server darstellen kann. Dazu lautet die passende Datei "Docker-compose.yml":
version: "3"
services:
nginx-example:
image: nginx:1.13-alpine
ports:
- "8002:80"
volumes:
- ./www:/www
- ./config/site.conf:/etc/nginx/conf.d/default.conf
Neben dem Verzeichnis für die Webserver-Daten blendet Docker die Konfigurationsdatei in die Umgebung ein. Das genügt für unser simples Beispiel.
Bei einem echten Setup würde der Administrator das komplette Verzeichnis "conf.d" mit allen Konfigurationsdateien anbinden:
logging:
driver: fluentd
options:
fluentd-address: localhost:24224
fluentd-async-connect: 'true'
fluentd-retry-wait: '1s'
fluentd-max-retries: '30'
tag: web.nginx
Den mitgegebenen Tag wird Fluentbit später für die Auswertung nutzen. Starten Sie nun per
»docker-compose up
«
den Nginx-Server, können Sie per "localhost:8002" auf dessen Homepage gehen.
Die Logausgaben des Nginx-Servers erscheinen in "Elasticsearch/Kibana", aber die interessanten Nginx-Loginformationen stecken, wie Bild 1 verdeutlicht, unqualifiziert im "Log"-Feld.
Theoretisch sollte es nun ausreichen, in der Konfiguration von Fluentd zwischen Input und Output einen passenden Filter einzubauen, der das Logfeld im Nginx-Format auseinandernimmt. Dazu würde in die Datei "fluent-bit.conf" folgender Block hinzukommen:
[FILTER]
Name parser
Match web.nginx
Key_Name log
Parser nginx
Reserve_data On
Im Klartext: Fluentd nimmt alle Loginformationen mit dem Tag "web.nginx" und schlüsselt das Feld "log" mit dem Parser "nginx" auf. Die Konfiguration des Parsers Nginx findet sich, unter vielen anderen, in der Datei "parsers.conf" aus dem Github-Repository von Fluentbit.
Nach dem gleichen Prinzip ließen sich dann die Loginformationen anderer Dienste wie Apache, Postgress, PHP-FPM oder MySQL taggen und mit dem passenden Parser zerlegen. In der Praxis funktioniert das Ganze aber leider nicht so einfach, wie es die Dokumentation von Fluentbit verspricht. Die Regular Expression, die der Nginx-Parser aus "parsers.conf" verwendet, passt leider gar nicht zu dem, was unser Nginx-Container in das "log"-Feld schreibt. Das bedeutet, Sie müssen die Regular Expression des Parsers modifizieren – eine Horrorvision vieler Administratoren.
Um den Schmerz bei der Arbeit mit Regular Expressions zu mindern, gibt es die Website [3]. Dort lassen sich Regular Expressions online erstellen und gleich ausprobieren. Mit Hilfe dieses Online-Tools (und sehr viel Geduld) modifizieren Sie die Regular Expression des Nginx-Filters so weit, dass sie für das vorliegende Beispiel passt.
Listing: parsers.conf
[PARSER] Name ng2 Format regex Regex ^(?<remote>[^ ]*) - - \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*) "(?<referencer>[^\"]*)" "(?<agent>[^\"]*)" Time_Format %d/%b/%Y:%H:%M:%S %z Time_Keep Off Time_Key log_time
Heraus kommt, wie im gleichnamigen Listing-Kasten ersichtlich, ein neuer Parser in "parsers.conf". Der ist zwar auch nicht perfekt (da er einfach zwei Datenfelder nach der Client-IP und zusätzliche Daten nach dem Agent ignoriert), funktioniert aber für unser Workshop-Beispiel.
Um die Logs noch besser voneinander zu trennen, lassen wir Fluentbit ferner die Daten in separate Indizes schreiben, sodass die Konfiguration in der Datei "fluent-bit.conf" am Ende so aussieht:
[SERVICE]
Flush 5
Daemon Off
Log_Level debug
Parsers_File parsers.conf
[INPUT]
Name forward
Tag *
Listen 0.0.0.0
Port 24224
Bis hierhin unverändert – aber die Datei "parsers.conf" enthält den oben erwähnten ng2-Eintrag:
[FILTER]
Name parser
Match web.nginx
Key_Name log
Parser ng2
Reserve_data On
Der Filter verweist auf den selbst geschriebenen Parser in der parsers.conf:
[OUTPUT]
Name es
Match container.*
Host <IP-Adresse des Hosts>
Port 9200
Index bit_docker.0
Type docker
Die Logs des EFK-Stacks selbst (getagt mit "container.elastic" und "container.kibana") landen im Index "bit_docker.0":
[OUTPUT]
Name es
Match web.nginx
Host <IP-Adresse des Hosts>
Port 9200
Index bit_nginx.0
Type docker
Die Logs des Webservers hingegen finden jetzt in einen eigenen Index namens "bit_nginx.0" Platz. Der neu gestartete EFK-Stack wertet im Anschluss die Loginformationen des Webservers detailliert aus (Bild 3).
Sie werden jedoch kaum darum herumkommen, sich mit angepassten und eigenen Regular Expressions auseinanderzusetzen. Während der Debug-Phase der eigenen Parser brauchen Sie dann gar nicht den kompletten EFK-Stack zu starten. Hier genügt ein einzelner Fluentbit-Container mit der Output-Option
[OUTPUT]
Name stdout
Match <mein.tag>
Dabei gibt Fluentbit die qualifizierten Logdaten im JSON-Format auf der Kommandozeile der Docker-Compose-Shell aus, sodass Sie direkt sehen, ob und wie Ihr Parser funktioniert.