ELK Stack im Cluster-Betrieb
Published on 25/05/2017
5 min read
In category
devop
Mit dem ELK Stack bekommt man eine abgestimmte Umgebung um Log-Einträge per Logstash abzuholen, diese in Elasticsearch vorzuhalten und dann per Kibana anzuzeigen. Das Aufsetzen des ELK Stack wird mit den Docker Images von Elastic vereinfacht. Um diese jedoch im Cluster zu nutzen müssen ein paar Anpassungen durchgeführt werden, welche hier dargestellt werden.
Einrichtung
Elastic bietet auf GitHub mehrere Docker Images an:
- https://github.com/elastic/elasticsearch-docker
- https://github.com/elastic/logstash-docker
- https://github.com/elastic/kibana-docker
Mittels docker-compose kann eine Konfiguration aufgesetzt werden, um die gewünschte Cluster-Umgebung aufzusetzen. In diesem Beispiel wird vernachlässigt, dass die einzelnen Container auf unterschiedliche Hosts laufen sollten. Jedoch wird hierfür bei der Konfiguration schon entsprechend Beachtung geschenkt.
Die angestrebte Umgebung sieht wie folgt aus:
Die Grundgedanken sind:
- Ein Elasticsearch Client Node dient nur für die reine Koordination und stellt die benötigten Ports (hier: 9200 und 9300) bereit.
- Ein paar Elasticsearch Master Nodes, welche selbst keine Daten halten.
- Ein paar Elasticsearch Data Nodes für die reine Datenhaltung.
- Ein direkter Zugriff ist nur über den Client Node möglich.
- Kibana und Logstash kennen nur den Client Node und dessen Port.
Die docker-compose Konfiguration sieht wie folgt aus:
#
# docker-compose.yml
#
# Config file for running the following images
# - elasticsearch (master, loadbalancer and data node)
# - logstash
# - kibana
#
# To use elasticsearch in a cluster use the docker-compose scale logic:
# docker-compose scale elasticsearch=3
# Elasticsearch config use zen for instance discovering.
# Consider that a master and loadbalancer node is also configured. Kibana and
# Logstash instance should never act directly with a master node. For this reason
# is on the master node http.enabled deactivated.
#
#
# Hafid Haddouti <code@haddouti.com>
# 23.05.2017
#
version: '3'
services:
# Coordinating/Loadbalancing node
# master, data and ingest features are deactivated
# static port mapping for usage with external services like Kibana, Logstash
elasticsearch-coordinating:
build: elasticsearch/
container_name: elasticsearch-coordinating
volumes:
- ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
ports:
- "9200:9200"
- "9300:9300"
environment:
- "ES_JAVA_OPTS=-Xmx256m -Xms256m"
- "node.master=false"
- "node.data=false"
- "node.ingest=false"
- "discovery.type=zen"
- "discovery.zen.ping.unicast.hosts=elasticsearch-master"
- "discovery.zen.minimum_master_nodes=1"
networks:
- elk
# Master node
# Without static port mapping and http transport disabled
elasticsearch-master:
build: elasticsearch/
# container_name: elasticsearch-master
volumes:
- ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
ports:
- "9300"
environment:
- "ES_JAVA_OPTS=-Xmx256m -Xms256m"
- "node.master=true"
- "node.data=false"
- "node.ingest=false"
- "http.enabled=false"
# - "discovery.zen.minimum_master_nodes=2"
- "discovery.zen.ping.unicast.hosts=elasticsearch-master"
networks:
- elk
depends_on:
- elasticsearch-coordinating
# elasticsearch data service.
# Do not use a static container name, this will be generated during scaling
# also do not use static port mapping, instead let elasticsearch use random ports
elasticsearch:
build: elasticsearch/
# container_name: elasticsearch
volumes:
- ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
ports:
- "9300"
environment:
- "ES_JAVA_OPTS=-Xmx256m -Xms256m"
- "node.master=false"
- "node.ingest=true"
- "http.enabled=false"
- "discovery.type=zen"
- "discovery.zen.ping.unicast.hosts=elasticsearch-master"
# - "discovery.zen.minimum_master_nodes=2"
networks:
- elk
depends_on:
- elasticsearch-coordinating
logstash:
build: logstash/
container_name: logstash
volumes:
- ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
- ./logstash/pipeline:/usr/share/logstash/pipeline
ports:
- "5000:5000"
environment:
- "LS_JAVA_OPTS=-Xmx256m -Xms256m"
networks:
- elk
links:
- elasticsearch-coordinating
depends_on:
- elasticsearch-master
- elasticsearch-coordinating
kibana:
build: kibana/
container_name: kibana
volumes:
- ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml
ports:
- "5601:5601"
networks:
- elk
links:
- elasticsearch-coordinating
depends_on:
- elasticsearch-master
- elasticsearch-coordinating
networks:
elk:
driver: bridge
Zu beachten sind folgende Punkte:
- Elasticsearch bietet mit Zen ein Discovery Mechanismus an, um neue Nodes zu finden. Dabei müssen alle Hosts angegeben werden. Hier wurde es vereinfacht, da der Service-Name "elasticsearch-master" verwendet wurde.
- Container welche skaliert werden sollen, dürfen keinen festen container_name verwenden; da dieser eindeutig sein muss. Beim Start wird hierfür ein Name mit einer Nummer vergeben.
- Dabei Logstash kann mit einem Unterstrich „_“ im Hostnamen nicht umgehen (https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/363)
- In logstash.yml und logstash.conf wird der Hostname (elasticsearch-coordinating) aufgenommen.
- Logstash darf nicht mit dem Master kommunizieren; hierfür ist auch beim Master Node explizit der HTTP Transportweg deaktiviert; andernfalls wird bei der Ermittlung der vorhandenen Nodes auch der Master Node betrachtet.
- Zu beachten ist, dass für Elasticsearch der virtuelle Adressraum ausreichend groß gewählt wird, um ein möglichen OutOfMemory zu vermeiden: https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html
- Standardmäßig wird seit Version 5 Elasticsearch mit X-Pack bereitgestellt (https://www.elastic.co/guide/en/x-pack/5.4/xpack-introduction.html). X-Pack ist eine Erweiterung um Elasticsearch, bzw. auch Kibana, um Funktionen bezüglich Security, Alerting, Monitoring und Reporting bereitzustellen. Dadurch lässt sich standardmäßig schon viele Informationen sammeln und direkt im ELK-Stack bereitstellen. In diesem Beispiel wurde Security deaktiviert; da hier für Logstash Probleme mit der benötigten Rolle auftraten und gesondert gelöst werden muss.
- Damit die Container sich untereinander finden und Dienste/Ports aus anderen Container verwendet werden können, muss eine Verlinkung her. Der beim links angegebene Name dient als Hostname in dem entsprechenden Docker Container (hier: elasticsearch-coordinating).
Ein
docker-compse up -d > dc.log
sorgt dafür, dass die Docker Container gestartet werden - das sind neben den Client, Master und ein Data Node auch die Container für Kibana und Logstash.
http://localhost:9200/_cat/health
liefert ein gelben Status zurück, da wir nur einen Data Node verfügen.
Mittels
docker-compose scale elasticsearch-master=2
docker-compose scale elasticsearch=2
werden die Master und Data Nodes hochskaliert. Danach liefert ein Healtcheck auch den grünen Status zurück.
Fazit
Mit einfachen Mitteln lässt sich ein ELK Stack im Cluster-Betrieb aufsetzen. Die Skalierung der einzelnen Nodes - hier Master und Data - ist einfach realisierbar, wenn man die wichtigsten Punkte beachtet: Jegliche Kommunikation über einen Client Node und die Verlinkung zwischen den Container soll über symbolische Namen erfolgen.
Alle Dateien sind in Git zu finden: https://bitbucket.org/playsphere/monitoring.git
Hilfreiches
- Aufruf URL für Kibana: http://localhost:5601/
- Aufruf URL für Elasticsearch: http://localhost:9200/
- Um mittels einer Shell in ein Docker Container zu gelangen: docker exec -it $ID bash wobei $ID die ID z.B. von docker ps für den relevante Container.
Offen
- ELK-Stack mit X-Pack Security verwenden, hierfür muss das Problem mit der fehlenden Rolle/Privileg für Logstash gelöst werden.
- Einsatz von Docker swarm um die Skalierung zu vereinfachen.