So installierst du Elasticsearch, Fluentd und Kibana (EFK) Logging Stack auf Ubuntu 22.04

Die Log-Überwachung und -Analyse ist ein wesentlicher Bestandteil der Server- oder Container-Infrastruktur und ist nützlich, wenn es um komplexe Anwendungen geht. Eine der beliebtesten Logging-Lösungen ist der Elasticsearch, Fluentd und Kibana (EFK) Stack. Bevor wir uns dem Tutorial zuwenden, wollen wir die Komponenten des Stacks kennenlernen.

Elasticsearch ist eine verteilte und skalierbare Echtzeit-Suchmaschine, die eine Volltextsuche und Analysen ermöglicht. Sie wird zum Indizieren und Durchsuchen großer Datenmengen verwendet. In der Regel wird sie zusammen mit Kibana eingesetzt, einem leistungsstarken Dashboard zur Datenvisualisierung für Elasticsearch. Mit Kibana kannst du die Elasticsearch-Logdaten untersuchen und Dashboards und Abfragen erstellen, um Einblicke in deine Anwendung zu erhalten. Fluentd sammelt und transformiert die Logdaten und sendet sie an das Elasticsearch-Backend.

In diesem Lernprogramm werden wir den EFK-Stack mit Docker auf einem Ubuntu 22.04-Rechner installieren und die Container-Logs an Kibana senden, nachdem wir sie mit Fluentd gefiltert und umgewandelt haben.

Voraussetzungen

  • Ein Server mit Ubuntu 22.04 und mindestens 6 GB RAM.
  • Ein Nicht-Root-Benutzer mit sudo-Rechten.
  • Die Unkomplizierte Firewall (UFW) ist aktiviert und läuft.
  • Ein Fully Qualified Domain Name (FQDN), der auf den Server zeigt, z.B. kibana.example.com.
  • Alles ist auf dem neuesten Stand.
    $ sudo apt update && sudo apt upgrade
    

Schritt 1 – Firewall konfigurieren

Bevor du die Pakete installierst, musst du zunächst die Firewall so konfigurieren, dass HTTP- und HTTPS-Verbindungen zugelassen werden.

Überprüfe den Status der Firewall.

$ sudo ufw status

Du solltest etwas wie das Folgende sehen.

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)

Erlaube HTTP- und HTTPs-Ports.

$ sudo ufw allow http
$ sudo ufw allow https

Überprüfe den Status zur Bestätigung noch einmal.

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443                        ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)

Schritt 2 – Installiere Docker und Docker Compose

Füge den offiziellen GPG-Schlüssel von Docker hinzu.

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg

Führe den folgenden Befehl aus, um das Docker-Repository hinzuzufügen.

$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Aktualisiere das System, um das Docker Repository einzubinden.

$ sudo apt update

Installiere Docker und das Docker Compose Plugin.

$ sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

In diesem Lehrgang wird das Docker Compose v2 Plugin anstelle des älteren Legacy Binary verwendet. Daher hat sich der Befehl zum Ausführen des Plugins von docker-compose auf docker composegeändert, was sich hier widerspiegelt.

Docker läuft mit erhöhten Rechten, daher musst du sudo häufig verwenden, um Befehle auszuführen. Die bessere Option ist, dein Linux-Benutzerkonto zur Benutzergruppe docker hinzuzufügen.

$ sudo usermod -aG docker ${USER}

Die Variable ${USER} nimmt das aktuell eingeloggte Systemkonto auf. Wenn du nicht mit dem Benutzer eingeloggt bist, dem du Privilegien geben willst, ersetze ${USER} durch den Benutzernamen.

Um die neue Gruppenmitgliedschaft zu beantragen, melde dich vom Server ab und wieder an oder verwende den folgenden Befehl. Du wirst aufgefordert, das Passwort des Benutzers einzugeben.

$ su - ${USER}

Schritt 3 – Docker Compose-Datei erstellen

Erstelle zunächst das Verzeichnis für das EFK-Projekt.

$ mkdir ~/efk

Wechsle in das Verzeichnis.

$ cd ~/efk

Erstelle und öffne die Datei docker-compose.yml zum Bearbeiten.

$ nano docker-compose.yml

Füge den folgenden Code in die Datei ein.

services:
  # Deploy using the custom image automatically be created during the build process.
  fluentd:
    build: ./fluentd
    volumes:
      - ./fluentd/conf:/fluentd/etc
    links: # Sends incoming logs to the elasticsearch container.
      - elasticsearch
    depends_on:
      - elasticsearch
    ports: # Exposes the port 24224 on both TCP and UDP protocol for log aggregation
      - 24224:24224
      - 24224:24224/udp

  elasticsearch:
    image: elasticsearch:8.7.1
    expose:
      - 9200
    environment:
      - discovery.type=single-node # Runs as a single-node
      - xpack.security.enabled=false
    volumes: # Stores elasticsearch data locally on the esdata Docker volume
      - esdata:/usr/share/elasticsearch/data

  kibana:
    image: kibana:8.7.1
    links: # Links kibana service to the elasticsearch container
      - elasticsearch
    depends_on:
      - elasticsearch
    ports:
      - 5601:5601
    environment: # Defined host configuration
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200

# Define the Docker volume named esdata for the Elasticsearch container.
volumes:
  esdata:

Speichere die Datei, indem du Strg + X drückst und Y eingibst, wenn du dazu aufgefordert wirst. Wir haben drei Dienste konfiguriert, jeweils einen für Fluentd, Elasticsearch und Kibana.

Für Fluentd werden wir einen Container bauen, anstatt ein fertiges Image. Die Build-Dateien für Fluentd werden im nächsten Schritt eingerichtet. Wir haben ein Verzeichnis für die Build-Dateien und ein Volume für die Konfigurationsdateien eingerichtet und den Port 24224 sowohl auf dem TCP- als auch auf dem UDP-Protokoll für die Log-Aggregation freigegeben.

Der nächste Dienst ist Elasticsearch und wir verwenden die neueste Version, die zum Zeitpunkt der Erstellung dieses Tutorials verfügbar war. Wir haben ihn über Port 9200 zugänglich gemacht und ein paar Umgebungsvariablen eingerichtet, damit wir ihn als Single-Node-Cluster betreiben können. Dies wird normalerweise nicht empfohlen, aber die Aktivierung der Sicherheitsfunktionen ist nicht Gegenstand dieses Lehrgangs. Außerdem haben wir ein lokales Volume für die Elasticsearch-Daten eingerichtet.

Schließlich konfigurieren wir Kibana und stellen es über Port 5601 bereit, über den wir auf das Dashboard zugreifen werden. Außerdem richten wir eine Variable ein, um den Elasticsearch-Host zu konfigurieren, auf den er zugreifen soll.

Schritt 4 – Fluentd Build-Dateien einrichten

Erstelle Fluentd und das Konfigurationsverzeichnis.

$ mkdir fluentd/conf -p

Führe den Befehl tree aus, um die Verzeichnisstruktur zu überprüfen.

$ tree

Sie sollte wie die folgende aussehen.

Tree command output

Wechsle in das Fluentd-Verzeichnis.

$ cd fluentd

Erstelle und öffne die Dockerfile zur Bearbeitung.

$ nano Dockerfile

Füge den folgenden Code darin ein. Dieser Code zieht das Fluentd Debian Docker Image und installiert das Fluentd Plugin für Elasticsearch.

# fluentd/Dockerfile
FROM fluent/fluentd:v1.16-debian-1
USER root
RUN ["gem", "install", "fluent-plugin-elasticsearch", "--no-document", "--version", "5.3.0"]
USER fluent

Speichere die Datei, indem du Strg + X drückst und Y eingibst, wenn du dazu aufgefordert wirst.

Wechsle in das Konfigurationsverzeichnis.

$ cd conf

Erstelle und öffne die Datei fluentd.conf zum Bearbeiten.

$ nano fluentd.conf

Füge den folgenden Code in die Datei ein.

# bind fluentd on IP 0.0.0.0
# port 24224
<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>

# sendlog to the elasticsearch
# the host must match to the elasticsearch
# container service
<match *.**>
  @type copy
  <store>
    @type elasticsearch_dynamic
    hosts elasticsearch:9200
    logstash_format true
    logstash_prefix fluentd
    logstash_dateformat %Y%m%d
    include_tag_key true
    tag_key @log_name
    include_timestamp true
    flush_interval 30s
  </store>
  <store>
    @type stdout
  </store>
</match>

Speichere die Datei, indem du Strg + X drückst und Y eingibst, wenn du dazu aufgefordert wirst.

Die obige Quellrichtlinie verwendet das Plugin forward, das Fluentd in einen TCP-Endpunkt verwandelt, um TCP-Pakete zu akzeptieren.

Die Match-Direktive sucht nach Ereignissen mit übereinstimmenden Tags, was in diesem Fall bedeutet, dass sie mit allen Ereignissen übereinstimmt. Zur Speicherung verwenden wir das Plugin elasticsearch_dynamic, mit dem Konfigurationswerte dynamisch angegeben werden können. Das Feld hosts gibt den Hostnamen für die Elasticsearch-Anwendung an, der der Dienstname in der Docker Compose-Datei ist. Das Feld logstash_format ist auf true gesetzt, was bedeutet, dass Fluentd das konventionelle Namensformat logstash-%Y.%m.%dlogstash-%Y.%m.%d verwendet. Der Präfixname zum Schreiben der Ereignisse wird auf fluend gesetzt. include_tag_key wird auf true gesetzt, wodurch das Fluentd-Tag im JSON-Format hinzugefügt wird. tag_key ist der Feldname, der für das Tag extrahiert werden soll. Wenn du die Variable include_timestamp auf true setzt, wird dem Protokoll ein Zeitstempelfeld hinzugefügt. Die Variable flush_interval legt das Intervall zwischen den Datenflushs fest. Wir verwenden das Plugin stdout auch, um Ereignisse/Protokolle auf der Standardausgabe auszugeben.

Schritt 5 – Ausführen der Docker-Container

Wechsle zurück in das EFK-Verzeichnis.

$ cd ~/efk

Starte die Container mit dem folgenden Befehl.

$ docker compose up -d

Überprüfe den Status der laufenden Container.

$ docker ps
b3780c311154   efk-fluentd           "tini -- /bin/entryp…"   9 seconds ago   Up 8 seconds   5140/tcp, 0.0.0.0:24224->24224/tcp, 0.0.0.0:24224->24224/udp, :::24224->24224/tcp, :::24224->24224/udp   efk-fluentd-1
5a48f0a9ade1   kibana:8.7.1          "/bin/tini -- /usr/l…"   9 seconds ago   Up 7 seconds   0.0.0.0:5601->5601/tcp, :::5601->5601/tcp                                                                efk-kibana-1
dab3a0ab0312   elasticsearch:8.7.1   "/bin/tini -- /usr/l…"   9 seconds ago   Up 8 seconds   9200/tcp, 9300/tcp                                                                                       efk-elasticsearch-1

Du kannst dafür auch den folgenden Befehl verwenden.

$ docker compose ps
NAME                  IMAGE                 COMMAND                  SERVICE             CREATED             STATUS              PORTS
efk-elasticsearch-1   elasticsearch:8.7.1   "/bin/tini -- /usr/l…"   elasticsearch       37 seconds ago      Up 36 seconds       9200/tcp, 9300/tcp
efk-fluentd-1         efk-fluentd           "tini -- /bin/entryp…"   fluentd             37 seconds ago      Up 36 seconds       5140/tcp, 0.0.0.0:24224->24224/tcp, 0.0.0.0:24224->24224/udp, :::24224->24224/tcp, :::24224->24224/udp
efk-kibana-1          kibana:8.7.1          "/bin/tini -- /usr/l…"   kibana              37 seconds ago      Up 36 seconds       0.0.0.0:5601->5601/tcp, :::5601->5601/tcp

Führe die folgenden Befehle aus, um die Logs des EFK-Build-Prozesses zu überprüfen.

$ docker logs efk-fluentd-1
$ docker logs efk-kibana-1
$ docker logs efk-elasticsearch-1

Überprüfe den Elasticsearch-Container. Er wird die detaillierten Einstellungen des Containers ausgeben.

$ docker inspect efk-elasticsearch-1

Du kannst die IP-Adresse sehen, die dem Container zugewiesen wurde.

[
    {
        "Id": "dab3a0ab03120d3a7192045e1ea84fdd0f8fdb7819cc6d6780e05109d61e0b66",
        "Created": "2023-05-04T09:58:00.256169904Z",
        "Path": "/bin/tini",
        "Args": [
            "--",
            "/usr/local/bin/docker-entrypoint.sh",
            "eswrapper"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 23619,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2023-05-04T09:58:00.563700803Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:59075530be34d3a06866f894ae9735f6d739a7a751ad45efb86dec3c9bd16836",
        "ResolvConfPath": "/var/lib/docker/containers/dab3a0ab03120d3a7192045e1ea84fdd0f8fdb7819cc6d6780e05109d61e0b66/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/dab3a0ab03120d3a7192045e1ea84fdd0f8fdb7819cc6d6780e05109d61e0b66/hostname",
        "HostsPath": "/var/lib/docker/containers/dab3a0ab03120d3a7192045e1ea84fdd0f8fdb7819cc6d6780e05109d61e0b66/hosts",
        "LogPath": "/var/lib/docker/containers/dab3a0ab03120d3a7192045e1ea84fdd0f8fdb7819cc6d6780e05109d61e0b66/dab3a0ab03120d3a7192045e1ea84fdd0f8fdb7819cc6d6780e05109d61e0b66-json.log",
        "Name": "/efk-elasticsearch-1",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "docker-default",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "efk_default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "ConsoleSize": [
                0,
                0
            ],
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "private",
            "Dns": null,
            "DnsOptions": null,
            "DnsSearch": null,
            "ExtraHosts": [],
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": null,
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": null,
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": null,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "Mounts": [
                {
                    "Type": "volume",
                    "Source": "efk_esdata",
                    "Target": "/usr/share/elasticsearch/data",
                    "VolumeOptions": {}
                }
            ],
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/ee03648cf34e03601848b1769569b4d3bb7192db118102ca050215ba87060bbf-init/diff:/var/lib/docker/overlay2/51d6cfcb59e473a3f163e68984a1ba1325a2c816ed7925c4dffdefcf2e104d11/diff:/var/lib/docker/overlay2/b9c096454bda31f1cb2ea33f108be8b29b2e94827ebe94cc17563eb596b7cab1/diff:/var/lib/docker/overlay2/effe604c5b015ba02cf3b7a238bd3ff5dad7970a72e689ef5275fcf03fd0bcd1/diff:/var/lib/docker/overlay2/72fbf23251467ea2f6af8d9458c7fdd8fa3ef716eeafd9319ceff59d07d96788/diff:/var/lib/docker/overlay2/02094ec9e4ebb04371f782744a3a46852a00bf6fd7e8820d466a3576aeb9d5fc/diff:/var/lib/docker/overlay2/ce364cdd636b67e10c879aa152360d965d08fe456663ed8fbe78c3bd37bde6c7/diff:/var/lib/docker/overlay2/33bf44b475ea5ea249845b7eed75ded47dd9dc7877b9231fa4195b4753071945/diff:/var/lib/docker/overlay2/4f19bd8089599ef879075012c710ec464d8e0446fc0a0813850657dddd23a5dc/diff:/var/lib/docker/overlay2/a39a61b12d8565c6d5b33c17a04d47c8bd47609a787e0548fbac0d47d00eecc8/diff:/var/lib/docker/overlay2/cbd9d77eb9ed6b600511f9a676aab511d2aa2b3dbd18d5403559699558546996/diff",
                "MergedDir": "/var/lib/docker/overlay2/ee03648cf34e03601848b1769569b4d3bb7192db118102ca050215ba87060bbf/merged",
                "UpperDir": "/var/lib/docker/overlay2/ee03648cf34e03601848b1769569b4d3bb7192db118102ca050215ba87060bbf/diff",
                "WorkDir": "/var/lib/docker/overlay2/ee03648cf34e03601848b1769569b4d3bb7192db118102ca050215ba87060bbf/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [
            {
                "Type": "volume",
                "Name": "efk_esdata",
                "Source": "/var/lib/docker/volumes/efk_esdata/_data",
                "Destination": "/usr/share/elasticsearch/data",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ],
        "Config": {
            "Hostname": "dab3a0ab0312",
            "Domainname": "",
            "User": "elasticsearch:root",
            "AttachStdin": false,
            "AttachStdout": true,
            "AttachStderr": true,
            "ExposedPorts": {
                "9200": {},
                "9200/tcp": {},
                "9300/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "xpack.security.enabled=false",
                "discovery.type=single-node",
                "PATH=/usr/share/elasticsearch/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "ELASTIC_CONTAINER=true"
            ],
            "Cmd": [
                "eswrapper"
            ],
            "Image": "elasticsearch:8.7.1",
            "Volumes": null,
            "WorkingDir": "/usr/share/elasticsearch",
            "Entrypoint": [
                "/bin/tini",
                "--",
                "/usr/local/bin/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "com.docker.compose.config-hash": "51c818791aa87ea7eccc389578c76ec4d596265eba8baefb8833bf5df13777e3",
                "com.docker.compose.container-number": "1",
                "com.docker.compose.depends_on": "",
                "com.docker.compose.image": "sha256:59075530be34d3a06866f894ae9735f6d739a7a751ad45efb86dec3c9bd16836",
                "com.docker.compose.oneoff": "False",
                "com.docker.compose.project": "efk",
                "com.docker.compose.project.config_files": "/home/navjot/efk/docker-compose.yml",
                "com.docker.compose.project.working_dir": "/home/navjot/efk",
                "com.docker.compose.service": "elasticsearch",
                "com.docker.compose.version": "2.17.3",
                "org.label-schema.build-date": "2023-04-27T04:33:42.127815583Z",
                "org.label-schema.license": "Elastic-License-2.0",
                "org.label-schema.name": "Elasticsearch",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.url": "https://www.elastic.co/products/elasticsearch",
                "org.label-schema.usage": "https://www.elastic.co/guide/en/elasticsearch/reference/index.html",
                "org.label-schema.vcs-ref": "f229ed3f893a515d590d0f39b05f68913e2d9b53",
                "org.label-schema.vcs-url": "https://github.com/elastic/elasticsearch",
                "org.label-schema.vendor": "Elastic",
                "org.label-schema.version": "8.7.1",
                "org.opencontainers.image.created": "2023-04-27T04:33:42.127815583Z",
                "org.opencontainers.image.documentation": "https://www.elastic.co/guide/en/elasticsearch/reference/index.html",
                "org.opencontainers.image.licenses": "Elastic-License-2.0",
                "org.opencontainers.image.ref.name": "ubuntu",
                "org.opencontainers.image.revision": "f229ed3f893a515d590d0f39b05f68913e2d9b53",
                "org.opencontainers.image.source": "https://github.com/elastic/elasticsearch",
                "org.opencontainers.image.title": "Elasticsearch",
                "org.opencontainers.image.url": "https://www.elastic.co/products/elasticsearch",
                "org.opencontainers.image.vendor": "Elastic",
                "org.opencontainers.image.version": "8.7.1"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "bf47cd7764585766349085d35100611e086cf233fc9fc655c6eb9e086f1cd59a",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "9200/tcp": null,
                "9300/tcp": null
            },
            "SandboxKey": "/var/run/docker/netns/bf47cd776458",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "",
            "Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "",
            "IPPrefixLen": 0,
            "IPv6Gateway": "",
            "MacAddress": "",
            "Networks": {
                "efk_default": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": [
                        "efk-elasticsearch-1",
                        "elasticsearch",
                        "dab3a0ab0312"
                    ],
                    "NetworkID": "1bc8ac0185982b84a24a201852f2cddc0432a3ffff1a2bd4008074875f696cac",
                    "EndpointID": "e1c67199e679f350d1da47f0b1e208ec6a7767eb57d60f773ba08b88a6962dcf",
                    "Gateway": "172.23.0.1",
                    "IPAddress": "172.23.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:17:00:02",
                    "DriverOpts": null
                }
            }
        }
    }
]

Wie du sehen kannst, hat der Container 172.23.0.2 als IP-Adresse erhalten. Führe den folgenden Befehl aus, um zu überprüfen, ob Elasticsearch richtig funktioniert.

$ curl 172.23.0.2:9200
{
  "name" : "dab3a0ab0312",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "gldMFBtQSxS5sL93rBAdzA",
  "version" : {
    "number" : "8.7.1",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "f229ed3f893a515d590d0f39b05f68913e2d9b53",
    "build_date" : "2023-04-27T04:33:42.127815583Z",
    "build_snapshot" : false,
    "lucene_version" : "9.5.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}

Schritt 6 – Kibana konfigurieren

Jetzt, wo der EFK-Stack eingesetzt wird, ist es an der Zeit, Kibana zu konfigurieren. Öffne die URL http://<yourserverIP>:5601 im Browser.

Kibana Willkommensseite

Klicke auf die Schaltfläche Eigenständig erkunden, um zum Kibana-Dashboard zu gelangen.

Kibana Dashboard

Klicke auf den Link Stack Management, um die Kibana-Datenansicht einzurichten. Wähle die Option Kibana >> Datenansichten in der linken Seitenleiste, um die Seite mit den Datenansichten zu öffnen.

Kibana Datenansicht Seite

Klicke auf die Schaltfläche Datenansicht erstellen, um fortzufahren.

Kibana Datenansicht erstellen

Gib den Namen der Datenansicht und das Indexmuster als fluentd-* ein. Stelle sicher, dass das Feld Zeitstempel auf @timestamp eingestellt ist. Das Feld Quelle wird automatisch aktualisiert. Klicke auf die Schaltfläche Datenansicht in Kibana speichern, um die Erstellung der Datenansicht abzuschließen.

Klicke als Nächstes auf das obere Menü (Ellipse) und klicke auf die Option Entdecken, um die Überwachung der Logs anzuzeigen.

Kibana Menü entdecken

Du erhältst die folgende Seite, die bestätigt, dass dein Setup perfekt funktioniert. Die Logs stammen alle von Elasticsearch und werden von der Fluentd-Log-Aggregation ausgeliefert.

Kibana Fluentd Monitoring Logs

Schritt 7 – Nginx installieren

Ubuntu 22.04 wird mit einer älteren Version von Nginx ausgeliefert. Du musst das offizielle Nginx-Repository herunterladen, um die neueste Version zu installieren.

Importiere den Signierschlüssel von Nginx.

$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

Füge das Repository für die stabile Version von Nginx hinzu.

$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg arch=amd64] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list

Aktualisiere die System-Repositories.

$ sudo apt update

Installiere Nginx.

$ sudo apt install nginx

Überprüfe die Installation.

$ nginx -v
nginx version: nginx/1.24.0

Starte den Nginx-Server.

$ sudo systemctl start nginx

Schritt 8 – SSL installieren

Der erste Schritt ist die Installation des Let’s Encrypt SSL-Zertifikats. Wir müssen Certbot installieren, um das SSL-Zertifikat zu erstellen. Du kannst Certbot entweder über das Ubuntu-Repository installieren oder die neueste Version mit dem Snapd-Tool herunterladen. Wir werden die Snapd-Version verwenden.

Bei Ubuntu 22.04 ist Snapd standardmäßig installiert. Führe die folgenden Befehle aus, um sicherzustellen, dass deine Version von Snapd auf dem neuesten Stand ist.

$ sudo snap install core && sudo snap refresh core

Installiere Certbot.

$ sudo snap install --classic certbot

Verwende den folgenden Befehl, um sicherzustellen, dass der Certbot-Befehl ausgeführt werden kann, indem du einen symbolischen Link zum Verzeichnis /usr/bin erstellst.

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

Erstelle das SSL-Zertifikat für die Domain kibana.example.com.

$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m name@example.com -d kibana.example.com

Mit dem obigen Befehl wird ein Zertifikat in das Verzeichnis /etc/letsencrypt/live/kibana.example.com auf deinem Server heruntergeladen.

Erstelle ein Diffie-Hellman-Gruppenzertifikat.

$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096

Überprüfe den Certbot-Erneuerungsplanerdienst.

$ sudo systemctl list-timers

Du findest snap.certbot.renew.service als einen der Dienste, die für die Ausführung vorgesehen sind.

NEXT                        LEFT          LAST                        PASSED         UNIT                     ACTIVATES
------------------------------------------------------------------------------------------------------------------------------------
Mon 2023-05-06 13:37:57 UTC 3h 45min left Mon 2023-05-01 07:20:42 UTC 2h 31min ago   ua-timer.timer           ua-timer.service
Mon 2023-05-06 14:39:29 UTC 4h 47min left Sat 2023-02-04 16:04:18 UTC 2 months ago   motd-news.timer          motd-news.service
Mon 2023-05-06 15:53:00 UTC 6h left       n/a                         n/a            snap.certbot.renew.timer snap.certbot.renew.service

Führe einen Probelauf des Prozesses durch, um zu prüfen, ob die SSL-Erneuerung einwandfrei funktioniert.

$ sudo certbot renew --dry-run

Wenn du keine Fehler siehst, bist du bereit. Dein Zertifikat wird automatisch erneuert.

Schritt 9 – Nginx konfigurieren

Erstelle und öffne die Nginx-Konfigurationsdatei für Kibana.

$ sudo nano /etc/nginx/conf.d/kibana.conf

Füge den folgenden Code in die Datei ein. Ersetze die IP-Adresse durch die private IP-Adresse deines Elasticsearch-Servers.

server {
        listen 80; listen [::]:80;
        server_name kibana.example.com;
        return 301 https://$host$request_uri;
}

server {
        server_name kibana.example.com;
        charset utf-8;

        listen 443 ssl http2;
        listen [::]:443 ssl http2;

        access_log /var/log/nginx/kibana.access.log;
        error_log /var/log/nginx/kibana.error.log;

        ssl_certificate /etc/letsencrypt/live/kibana.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/kibana.example.com/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/kibana.example.com/chain.pem;
        ssl_session_timeout 1d;
        ssl_session_cache shared:MozSSL:10m;
        ssl_session_tickets off;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

		resolver 8.8.8.8;

        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;

        location / {
                proxy_pass http://localhost:5601;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
        }
}

Speichere die Datei, indem du Strg + X drückst und Y eingibst, wenn du dazu aufgefordert wirst.

Öffne die Datei /etc/nginx/nginx.conf zum Bearbeiten.

$ sudo nano /etc/nginx/nginx.conf

Füge die folgende Zeile vor der Zeile include /etc/nginx/conf.d/*.conf; ein.

server_names_hash_bucket_size  64;

Speichere die Datei, indem du Strg + X drückst und Y eingibst, wenn du dazu aufgefordert wirst.

Überprüfe die Konfiguration.

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Starte den Nginx-Dienst neu.

$ sudo systemctl restart nginx

Es ist noch ein weiterer Schritt erforderlich. Öffne die Docker compose Datei zum Bearbeiten.

$ nano ~/docker-compose.yml

Füge die Zeile SERVER_PUBLICBASEURL=https://kibana.example.com unter dem Abschnitt environment für den Kibana-Dienst wie folgt ein.

    environment: # Defined host configuration
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - SERVER_PUBLICBASEURL=https://kibana.example.com

Speichere die Datei, indem du Strg + X drückst und Y eingibst, wenn du dazu aufgefordert wirst, sobald du fertig bist.

Stoppe und entferne die Container.

$ docker compose down --remove-orphans

Starte die Container erneut mit der aktualisierten Konfiguration.

$ docker compose up -d

Dein Kibana-Dashboard sollte über die URL https://kibana.example.com von jedem beliebigen Ort aus zugänglich sein.

Schritt 10 – Ausführen eines Docker-Containers mit Fluentd Log Driver

Jetzt lassen wir einen Docker-Container mit dem Fluentd Log-Treiber laufen, der automatisch Logs an den Stack sendet. Wir testen mit dem Nginx-Container.

Ziehe das Nginx-Image aus der Docker Hub Registry. Wir verwenden die Version alpine, weil sie die kleinste Version des Images ist.

$ docker pull nginx:alpine

Führe den folgenden Befehl aus, um den Nginx-Container zu erstellen und zu starten. Wir haben den Log-Treiber auf Fluentd und den Port auf 8080 gesetzt, weil der Standard-Port 80 bereits vom Nginx-Server im Proxy-Modus verwendet wird.

$ docker run --name nginx-fluentd-test -d --log-driver=fluentd -p 8080:80 nginx:alpine

Überprüfe den Status des Containers.

$ docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS                                                                                                    NAMES
038c43e4e1a3   nginx:alpine          "/docker-entrypoint.…"   12 seconds ago   Up 11 seconds   0.0.0.0:8080->80/tcp, :::8080->80/tcp                                                                    nginx-fluentd-test
a94ca706bd0c   efk-fluentd           "tini -- /bin/entryp…"   8 hours ago      Up 8 hours      5140/tcp, 0.0.0.0:24224->24224/tcp, 0.0.0.0:24224->24224/udp, :::24224->24224/tcp, :::24224->24224/udp   efk-fluentd-1
0cf04a446425   kibana:8.7.1          "/bin/tini -- /usr/l…"   8 hours ago      Up 8 hours      0.0.0.0:5601->5601/tcp, :::5601->5601/tcp                                                                efk-kibana-1
7c7ad8f9b123   elasticsearch:8.7.1   "/bin/tini -- /usr/l…"   8 hours ago      Up 8 hours      9200/tcp, 9300/tcp                                                                                       efk-elasticsearch-1

Führe den folgenden Befehl aus, um auf den Nginx-Container zuzugreifen und Zugriffsprotokolle zu erstellen.

$ curl localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Alternativ kannst du die URL http://<yourserverIP>:8080 in deinem Browser öffnen und du erhältst die folgende Seite.

Nginx Homepage

Öffne das Kibana Dashboard und klicke auf den Link Entdecken in der linken Seitenleiste. Klicke auf das +-Zeichen im oberen Menü, um das Popup-Fenster Filter hinzufügen aufzurufen.

Kibana Add Filter Popup

Wähle das Feld container_name aus dem Dropdown, is als Operator und gib den Containernamen ( nginx-fluentd-test) als Feldwert ein.

Kibana Container select Abfrage

Klicke auf die Schaltfläche Filter hinzufügen, um die Daten aus dem Nginx-Container zu visualisieren.

Nginx Container Fluentd Log

Fazit

Damit ist unser Tutorial zur Installation von Elasticsearch, Fluentd und Kibana (EFK) auf einem Ubuntu 22.04 Rechner abgeschlossen. Wenn du Fragen hast, schreibe sie unten in die Kommentare.

Das könnte dich auch interessieren …