Centralized logging in swarm
Contents
Bevezető
ElasticSearch
https://www.elastic.co/products/elasticsearch
Elasticsearch is an open-source, RESTful, distributed search and analytics engine built on Apache Lucene. Since the first version of Elasticsearch was released in 2010, it has quickly become the most popular search engine, and is commonly used for log analytics, full-text search, and operational intelligence use cases.
When coupled with Kibana, a visualization tool, Elasticsearch can be used to provide near-real time analytics using large volumes of log data. Elasticsearch is also popular because of its easy-to-use search APIs which allow you to easily add powerful search capabilities to your applications.
It scales horizontally to handle kajillions of events per second, while automatically managing how indices and queries are distributed across the cluster for oh-so smooth operations
- Log Analytics - Analyze un-structured and semi-structured logs generated by websites, mobile devices, servers, sensors, and more for a wide variety of applications such as digital marketing, application monitoring, fraud detection, ad tech, gaming, and IoT. Capture, pre-process, and load log data into Elasticsearch using Logstash, Amazon Kinesis Firehose, or Amazon CloudWatch Logs. You can then search, explore, and visualize the data using Kibana and the Elasticsearch query DSL to gain valuable insights about your users and applications.
- Full Text Search - Provide your customers with a rich search and navigation experience. Elasticsearch supports faceting, which allows your customers to narrow their search results by value ranges for fields like price, product characteristics, and brands; ability to create advanced search criteria filters; search-as-you-type suggesters; and near real-time index updates.
- Distributed Document Store - Power your application with an easy to use JSON document-oriented storage platform. Elasticsearch provides a simple REST API, fast performance, powerful search capabilities, so you can build highly performant applications that can store and retrieve billions of documents.
- Real-time Application Monitoring - Capture activity logs across your customer-facing applications and websites. Use Logstash to push these logs to your Elasticsearch cluster. Elasticsearch indexes the data and makes it available for analysis in near real-time (less than one second). You can then use Kibana to visualize the data and perform operational analyses like identifying outages and problems. With Elasticsearch’s geospatial analysis, you can identify the geographical region where the problem is occurring. Troubleshooting teams can then search the index and perform statistical aggregations to identify root cause and fix issues.
Logstash
Áttekintés
https://www.elastic.co/products/logstash
LogStash allows us to centralize data processing. It can be easily extended to custom data formats and offers a lot of plugins that can fulfill almost any need. Finally
Ezt az elastic cég csinálta, ugyan az aki az elasticPath-t.
LogSpout is a log router for Docker containers that runs inside Docker. It attaches to all containers on a host, then routes their logs wherever we want. It also has an extensible module system. It's a mostly stateless log appliance. It's not meant for managing log files or looking at history. It is just a tool to get your logs out to live somewhere else, where they belong.
Hogyan működik a Logstash
https://www.elastic.co/guide/en/logstash/6.4/pipeline.html
Logspout
Elasticsearch bemutatása
Az Elasticsearch adatbáziskezelő Elasticsearch node-okból épül fel. Mikor elindítunk egy node-ot, akkor az csatlakozni fog a konfigurációjában megadott cluster-hez. Ha a cluster még nem létezik, akkor létre fog hozni a node egy egy-node-os cluster-t. Egy környezetben (pl AWS) több Elasticsearch cluster-t is létrehozhatunk, lényeg, hogy a nevük különbözzön. Az alapértelmezett cluster név: elasticsearch
Akkor is Elasticsearch cluster-nek hívják, ha csak 1 node-ból áll a cluster. Tehát egy Elasticsearch adatbáziskezelőn mindig egy Elasticsearch cluster-t értünk.
Index
https://www.elastic.co/blog/what-is-an-elasticsearch-index
Az ElasticSearch-ben az Index megfelel egy adatbázisnak egy relációs adatbázis kezelőben.
- MySQL => Databases => Tables => Columns/Rows
- Elasticsearch => Indices => Types => Documents with Properties
Egy Elasticsearch cluster-ben tehát tetszőleges számú Index-et hozhatunk létre (adatbázist), amiben tetszőleges számú Type lehet (tábla). A type-okon belül Document-ek vannak (ezek a sorok), és a Document-nek vannak tulajdonságai, Property (ezek az oszlopok)
- Index -> Adatbázis
- Type -> Tábla
- Document -> Row
- Properties -> Column
Telepítés
docker network create --driver overlay elk
ElasticSearch
Az Elastichsearch docker image a https://www.docker.elastic.co/ oldaláról tölthető le
Itt van a telepítési leírás:
https://www.elastic.co/guide/en/elasticsearch/reference/6.4/docker.html
Volume plugin
Ahogy azt már sokszor említettem, a konténerek legfelső, írható rétegét, nem szabad írás intenzíven használni, mivel az ottani overlay2 fájlrendszer nagyon lassan tudja csak kezelni a változásokat, legrosszabb esetben minden image-et végig kell nézzen, ami a konténert alkotja, hogy megtaláljon egy fájlt. Minden írás intenzív műveletet volume-okon kell elvégezni, azok arra lettek kitalálva.
Az ElsaticSearch konténer két mappáját fogjuk a Netshare volume plugin-al felcsatolni az NFS megosztásra. Az egyik az adatbázis mappa, a másik a config mappa, hogy
Elsőként az ElasticSearch image-et fel fogjuk standalone docker konténerként telepíteni hogy kimásoljuk belőle a konfigurációs mappájának a tartalmát, amit az NFS elasticsearch/config mappájába fogunk másolni, hogy ezt majd felcsatoljuk a swarm service alá.
# docker run -d --name elasticsearch \ -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" \ docker.elastic.co/elasticsearch/elasticsearch:6.4.0 # docker cp -L elasticsearch:/usr/share/elasticsearch/config/ /home/adam/Projects/DockerCourse/persistentstore/elasticsearch/ # chmod 777 /home/adam/Projects/DockerCourse/persistentstore/elasticsearch/config # mkdir /home/adam/Projects/DockerCourse/persistentstore/elasticsearch/data # docker rm -f elasticsearch
Note
Az elasticsearch image elég nagy, 1 Giga körül van, így fontos, hogy legyen elég lemezterület az összes node-on. A base image CentOS 7.5
Telepítés
docker service create \ --detach=false \ --name elasticsearch \ --network elk \ --mount "type=volume,src=192.168.42.1/home/adam/Projects/DockerCourse/persistentstore/elasticsearch/config/\ ,dst=/usr/share/elasticsearch/config,volume-driver=nfs" \ --mount "type=volume,src=192.168.42.1/home/adam/Projects/DockerCourse/persistentstore/elasticsearch/data/\ ,dst=/usr/share/elasticsearch/data,volume-driver=nfs" \ -e "discovery.type=single-node" \ --reserve-memory 500m \ docker.elastic.co/elasticsearch/elasticsearch:6.4.0
# docker service ps elasticsearch ID NAME IMAGE NODE phgs0as5w612 elasticsearch.1 docker.elastic.co/elasticsearch/elasticsearch:6.4.0 mg2
Logstash
A LogStash image-et is az elastic oldaláról lehet letölteni:
https://www.elastic.co/guide/en/logstash/current/docker-config.html
Logstash konfigurációs fájl
https://www.elastic.co/guide/en/logstash/6.4/configuration.html
/home/adam/Projects/DockerCourse/persistentstore/logstash/logstash.conf
input {
syslog { port => 51415 }
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
}
# Remove in production
stdout {
codec => rubydebug
}
}
A logstash-t is a elk nevű overlay hálózatra fogjuk kapcsolni. Az overlay hálózatokon egyrészt a konténerek közvetlen elérik egymást, így nincs szükség az ingress hálózatra publikált portokra, másrészt a swarm névfeloldást végez. A szolgáltatás nevére indított DNS lekérdezés visszaadja az összes a szolgáltatáshoz tartozó konténer IP címét a közös overlay hálózaton. Fontos, hogy a lekérdezést olyan konténerből indítsuk, ami ugyan arra az overlay hálózatra csatlakozik mint a keresett szolgáltatás.
Az ElasticSearch a 9200-es porton hallgatózik, amit nem publikáltunk az ingress hálózatra. Viszont a logstash a közös elk overlay hálózaton fel tudja oldani az elasticsearch domain nevet, ami megegyezik a szolgáltatás nevével.
A logstash az 51415-ös porton fogja várni a beérkező logokat, amit majd aztán továbbít a megfelelő alakra hozva a elasticsearch:9200-es címre az ElasticSearch-nek.
Telepítés
docker service create --name logstash \ --detach=false \ --mount "type=volume,src=192.168.42.1/home/adam/Projects/DockerCourse/persistentstore/logstash/config/\ ,dst=/conf,volume-driver=nfs" \ --network elk \ --reserve-memory 100m \ -e "LOGSPOUT=ignore" \ docker.elastic.co/logstash/logstash:6.4.0 bin/logstash -f /conf/logstash.conf
A LOGSPOUT=ignore környezeti változóval azt mondjuk meg a logspout-nak, hogy erről a konténerről ne gyűjtse össze a logokat.
# docker service logs -f logstash ... [2018-09-12T20:01:26,403][INFO ][logstash.inputs.metrics ] Monitoring License OK [2018-09-12T20:01:27,999][INFO ][logstash.agent ] Successfully started Logstash API endpoint {:port=>9600}
Testing logstash
A logger nevű programmal, mely része a legtöbb Linux disztribúciónak logot írhatunk egy távoli server syslog-jába a lokális socket helyett. A logger-test konténert is a elk nevű overlay hálózatra fogjuk kötni, így közvetlen el fogja tudni érni a logstash-t a 51415-ös porton. Az overlay hálózaton használhatjuk a szolgáltatás nevét mint domain nevet, a logstash domain nevet a swarm fel fogja oldani a logstash konténer IP címére.
docker service create \ --name logger-test \ --network elk \ --restart-condition none \ debian \ logger -n logstash -P 51415 hello world
# docker service logs logstash .... { "severity" => 0, "@version" => "1", "tags" => [ [0] "_grokparsefailure_sysloginput" ], "severity_label" => "Emergency", "@timestamp" => 2018-09-12T20:24:29.085Z, "priority" => 0, "facility_label" => "kernel", "message" => "<13>1 2018-09-12T20:24:29.013823+00:00 a4f8651665ee root - - [timeQuality tzKnown=\"1\" isSynced=\"0\"] hello world", "host" => "10.0.0.2", "facility" => 0 }
# eval $(docker-machine env mg0) # docker service rm logger-test
Logspout
https://hub.docker.com/r/gliderlabs/logspout/
ogspout will gather logs from other containers that are started without the -t option and are configured with a logging driver that works with docker logs (journald and json-file).
For now it only captures stdout and stderr, but a module to collect container syslog is planned.
Telepítés
docker service create --name logspout \ --detach=false \ --network elk \ --mode global \ --mount "type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock" \ -e SYSLOG_FORMAT=rfc3164 \ gliderlabs/logspout:v3.2.5 syslog://logstash:51415
# docker service ls ID NAME MODE REPLICAS IMAGE e0smhp3tn8ox logspout global 4/4 gliderlabs/logspout:v3.2.5
A log végén meg kell jelenjen az alábbi sor, ami jelzi, hogy a logstash-ez kapcsolódik az 51415-ös porton.
# docker service logs logspout logspout.0.lh7yq14rapf7@mg2 | # ADAPTER ADDRESS CONTAINERS SOURCES OPTIONS logspout.0.lh7yq14rapf7@mg2 | # syslog logstash:51415 map[]
Note
Ha nincs elég memória szabadon a node-on, akkor a logspout nem fog tudni elindulni.
Tesztelés
A logspout minden egyes node-on ott fut, és bármelyik node-on is keletkezzen log az stdout-on, azt el fogja küldeni a logstash-nek az 51415-ös portra. Mivel mind a ketten az elk nevű overlay hálózatra kapcsolódnak, a logspout közvetlen eléri a logstash-t az bármelyik node-on is legyen. A közös overlay hálózatokon a service nevet domain névként használhatjuk, a swarm DNS szervere visszaadja az összes konténer IP címét, ami a service-hez tartozik. Mivel a logstash-böl csak egy példány fut, így az összes logspout konténer közvetlen el tudja neki küldeni az összegyűjtött logokat.
Úgy fogjuk tesztelni, hogy elsőként elkezdjük figyelni interaktív módban (-f) a logstash log-ját. Majd egy tetszőleges node-on (mindegy melyiken, a logspout minden node-on fut) elindítunk egy ubuntu image-ből álló konténert, ami egy sort fog írni az stdout-ra. Ennek azonnal meg kell jelennie a logstash logjában. Az ubuntu-nak nem is kell swarm service-ként futnia, a logspout mivel a lokális docker démonra csatlakozik, a standalone docker konténerek logját is be tudja gyűjteni.
Indítsuk el a logstash log-nézőt:
# docker service logs -f logstash
Indítsuk el az ubuntu-t standalone docker konténerként, ami az stdout-ra fog írni a konténeren belül. Ezt az logspout-nak észre kell venni, és el kell küldeni a logstash-nek, aki már be tudja tölteni a megfelelő alakban az ElasticSarch-be. Az ubuntu konténer ahogy kiírta az üzenetet az stdout-ra le fog állni, így kapásból törölhetjük is. Fontos, hogy -d kapcsolóval futtassuk az ubuntu konténert, interaktív módban a logspout nem gyűjti be a logokat.
# docker run -d --rm --name ubunto ubuntu echo "hello logspout" > /dev/stdout
A --rm hatására az ubuntu konténer azonnal törölve lesz, ahogy lefutott az echo.
Szinte azonnal meg kell jelenjen a "hello logspout" üzenet a logstash logjában, amit interaktív módban figyelünk:
logstash.1.ggjdb8navgso@mg1 | { logstash.1.ggjdb8navgso@mg1 | "@version" => "1", logstash.1.ggjdb8navgso@mg1 | "timestamp" => "2018-09-14T20:31:00Z", logstash.1.ggjdb8navgso@mg1 | "program" => "ubunto", logstash.1.ggjdb8navgso@mg1 | "severity" => 6, logstash.1.ggjdb8navgso@mg1 | "facility_label" => "user-level", logstash.1.ggjdb8navgso@mg1 | "pid" => "3291", logstash.1.ggjdb8navgso@mg1 | "priority" => 14, logstash.1.ggjdb8navgso@mg1 | "@timestamp" => 2018-09-14T20:31:00.000Z, logstash.1.ggjdb8navgso@mg1 | "facility" => 1, logstash.1.ggjdb8navgso@mg1 | "timestamp8601" => "2018-09-14T20:31:00Z", logstash.1.ggjdb8navgso@mg1 | "severity_label" => "Informational", logstash.1.ggjdb8navgso@mg1 | "message" => "hello logspout\n", logstash.1.ggjdb8navgso@mg1 | "host" => "10.0.0.5", logstash.1.ggjdb8navgso@mg1 | "logsource" => "836892e1d7fa" logstash.1.ggjdb8navgso@mg1 | }
Docker logger driver vs logspout
Kibana
https://www.elastic.co/products/kibana
https://www.elastic.co/guide/en/kibana/current/docker.html
Kibana is an analytics and visualization platform with intuitive interface sitting on top of ElasticSearch.
docker service create --name kibana \ --network elk \ -e ELASTICSEARCH_URL=http://elasticsearch:9200 \ --reserve-memory 50m \ --label com.df.notify=true \ --label com.df.distribute=true \ --label com.df.servicePath=/app/kibana,/bundles,/elasticsearch \ --label com.df.port=5601 \ docker.elastic.co/kibana/kibana:6.4.0 version: '2' services: kibana: image: docker.elastic.co/kibana/kibana:6.4.0 environment: SERVER_NAME: kibana.example.org ELASTICSEARCH_URL: http://elasticsearch.example.org docker run --name kibana docker.elastic.co/kibana/kibana:6.4.0