Das Bereitstellen von Anwendungen ist eine zentrale Administrationsaufgabe und Fehler hierbei fallen Mitarbeitern wie Kunden unmittelbar auf. Eine wichtige ... (mehr)

Komposition mit Docker-compose

Das Tool Docker-compose bezieht seine Anweisungen aus einem YAML-File, das den zu startenden Service bestehend aus einem oder mehreren Containern und deren Abhängigkeit beschreibt. Hier setzt sich der Dienst aus drei Containern zusammen.

Docker-compose.yml
version: '3'

legt die Version der docker-compose-Syntax fest. Mit

services:
      elasticsearch:
           image: ${ELASTICSEARCH_IMAGE}
           restart: always

erhält der erste Container Elasticsearch und nutzt als Quell-Image die URL, die in der ENV-Datei angegeben wurde. Mit

environment:
      - 'node.name=elastic'
      - 'discovery.type=single-node'
      - 'bootstrap.memory_lock=true'
      - 'ES_JAVA_OPTS=-Xms256m -Xmx256m'

geben Sie über die Definition des Environments innerhalb des Containers die Basiskonfiguration vor, vor allem das RAM-Limit für die Java Virtual Machine. Im Gegenzug bedarf es keiner Konfigurationsdatei für Elasticsearch.

ports:
- 9200:9200

zeigt, dass unsere Konfiguration ohne eine "Network"-Deklaration auskommt. Die Container arbeiten mit der IP-Adresse des Hostsystems und blenden ihre Applikations-Ports darüber. Sobald der Elasticsearch-Container läuft, können Sie darauf über eine Shell auf dem Host per »curl localhost:9200« zugreifen.

volumes:
      - ./elasticsearch:/usr/share/elasticsearch/data

verhindert, dass der Container bei jedem Start seine Daten vergisst, denn wir binden das Host-Unterverzeichnis "./elasticsearch" (absolut also "/root/docker/elk/elasticsearch") im Container unter "/usr/share/elasticsearch/data" ein. Um Zugriffsprobleme zu vermeiden, sollte das Unterverzeichnis offene Berechtigungen (777) haben.

logging:
      driver: fluentd
      options:
           fluentd-address: localhost:24224
           fluentd-async-connect: 'true'
           fluentd-retry-wait: '1s'
           fluentd-max-retries: '30'
           tag: ${LOG_OPT_TAG_PREFIX}.elastic

Hier kommt nun die Konfiguration des Logtreibers. Elasticsearch selbst wird seine Logs an den Fluentbit-Dienst senden. Der Tag wird gemäß der Vorgabe aus der ENV-Datei dann "container.elastic" lauten.

 Die Retry- und Wait-Angaben sind nötig, da der Fluentbit-Container selbst erst nach dem Elasticsearch-Container startet. Im nächsten Schritt folgt der Kibana-Container:

kibana:
      image: ${KIBANA_IMAGE}
      restart: always
      ports:
           - 5601:5601
      depends_on:
           - elasticsearch
Bild 2: Die Webseite "regex101.com" hilft beim Ausprobieren und Anpassen von Regular Expressions.

Das "depends_on"-Statement sorgt dafür, dass der Kibana-Container Zugriff auf die Ports von Elasticsearch bekommt und erst nach dem Elasticsearch-Container startet.

logging:
      driver: fluentd
      options:
            fluentd-address: localhost:24224
            fluentd-async-connect: 'true'
            fluentd-retry-wait: '1s'
            fluentd-max-retries: '30'
           tag: ${LOG_OPT_TAG_PREFIX}.kibana

Auch hier sendet Kibana seine Logs mit dem Tag "container.kibana" direkt an Fluentbit. Zum Schluss startet Fluentbit selbst:

fluentbit:
      image: ${FLUENTBIT_IMAGE}
      ports:
            - 24224:24224
      depends_on:
            - elasticsearch
     volumes:
            - ./fluentbit:/fluent-bit/etc

Das Volume-Overlay sorgt dafür, dass Fluentbit die auf dem Host gesicherte Dienst-Konfiguration verwendet:

logging:
      driver: "json-file"
      options:
            max-size: "1G"
            max-file: "2"

Da wir Fluentbit im Vordergrund laufen lassen, sind alle Ausgaben ohnehin auf der Docker-Compose-Shell sichtbar. Daher sind die Logs nicht wichtig. Im produktiven Umfeld sollte aber auch Fluentbit als Background-Daemon laufen und seine Logs an sich selbst senden.

Fluentbit konfigurieren

Bei der Konfiguration des Fluentbit-Containers gilt es, ein paar Hindernisse zu überwinden. Unter "/fluent-bit/etc" muss neben der eigentlichen "fluent-bit.conf" noch die Konfiguration der Parser stehen. Daher müssen Sie aus dem Repository unter "https://github.com/fluent/fluentbit/tree/master/conf" die Datei "parsers. conf" kopieren und im Verzeichnis "./fluentbit" ablegen. In die eigentliche "fluent-bit.conf" kommt zunächst folgender Inhalt:

[SERVICE]
      Flush 5
      Daemon Off
      Log_Level debug
      Parsers_File parsers.conf

Hiermit wird Fluentbit alle fünf Sekunden die gesammelten Logdaten weiterleiten und im Vordergrund laufen, sodass die Logausgaben des Diensts zu sehen sind. Wichtig hierbei: Fluentbit ist sehr empfindlich, was die Einzüge (Whitespaces) innerhalb seiner Konfigurationsdatei betrifft (wie bei YAML oder Python).

Falsche Einzüge oder ein Durcheinander aus Tabs und Whitespaces führen dazu, dass der Dienst die Konfigurationsdatei nicht liest und abbricht. Die Input-Anweisung öffnet nun Port 24224 und nimmt alle hier abgelieferten Logdaten entgegen:

      [INPUT]
      Name forward
      Listen 127.0.0.1
     Port 24224

Danach bestimmen Sie mit

      [OUTPUT]
      Name es
      Match *
      Host <IP-Adresse des Hosts>
      Port 9200
      Index fluentbit
      Type docker

dass Fluentbit zunächst einfach alle Loginformationen direkt als Typ "docker" an Elasticsearch shippen soll. Wie sich herausstellt, hat der Fluentbit-Container dabei ein entscheidendes Problem: Eigentlich sollte er den Kontakt zu Elasticsearch via "127.0.0.1:9200" aufnehmen können (Host localhost, Port 9200) - genau so, wie das der Kibana-Container macht. In der Praxis funktioniert das jedoch nicht und der Fluentbit-Container berichtet "127.0.0.1:9200 connection refused". Steht in der Konfiguration als "Host" die externe IP-Adresse des Hosts, auf dem die Container arbeiten, funktioniert der Stack. Also müssen Sie die IP-Adresse Ihres Docker-Hosts in die Konfiguration eintragen. Das gilt natürlich auch, wenn ein bestehendes EK-System anstelle der lokalen Container zum Einsatz kommt.

Mit »docker-compose up« starten Sie jetzt den EFK-Stack mit seinen drei Containern. Der erste Anlauf dauert etwas länger, da Docker erst die Images aus dem Internet herunterladen muss. Sobald alle drei Container laufen, lässt sich Kibana im Browser via "localhost:5601" aufrufen. Dort müssen Sie zunächst einen "fluentbit*"-Index erzeugen und können dann die Logeinträge einsehen. Die erste Hürde ist genommen.

Bild 3: Filtert der passende Parser mit der richtigen Regular Expression das "log"-Feld, qualifiziert Fluentbit die Logfelder der Nginx-Ausgabe.

Hier zeigt sich nun das eigentliche Problem: Fluentbit qualifiziert die Ausgaben als Docker-Logformat. Das heißt, es qualifiziert nur die Docker-typischen Felder wie "container_name" und "con­tainer_id".

Die Logausgaben eines Diensts, der innerhalb des Containers arbeitet, stecken unqualifiziert in einem großen Feld namens "log". Aber genau das ist es, was Sie als Admin aufgeschlüsselt in qualifizierter Form sehen möchten. Und genau das muss Fluentbit nun im nächsten Schritt lernen.

comments powered by Disqus
Einmal pro Woche aktuelle News, kostenlose Artikel und nützliche ADMIN-Tipps.
Ich habe die Datenschutzerklärung gelesen und bin einverstanden.

Konfigurationsmanagement

Ich konfiguriere meine Server

  • von Hand
  • mit eigenen Skripts
  • mit Puppet
  • mit Ansible
  • mit Saltstack
  • mit Chef
  • mit CFengine
  • mit dem Nix-System
  • mit Containern
  • mit anderer Konfigurationsmanagement-Software

Ausgabe /2023