Changes

Metrics and Monitoring in swarm

38,748 bytes removed, 21:41, 19 September 2018
no edit summary
[[Docker|<< Back to Docker main]]
:[[File:ClipCapIt-180919-234053.PNG|300px]]
==Node exporter==
Ezt nem lenne muszáj konténerként telepíteni, futhat natívan is, de egyszerűbb ha konténerként fut, mert a swarm így automatikusan ki tudja rakni minden node-ra, nem nekünk kell. Ha konténerként fut, akkor a host OS szinte minden porcikáját fel kell mountolni a node-exporter konténernek, hiszen a le kell tudja kérdezni a host OS állapotát. Ez azért sem nagy biztonsági kockázat, mert ha swarm-ot futtatunk, akkor a hostok valamelyik virtualizációs környezetben fognak futni, és nagy valószínűséggel az egyetlen feladatuk a docker futtatása lesz.   Elsőként swarm-on kívül tegyük rá a mg0-ra, és nyissuk ki a host OS felé a 9100-es portot, hogy lássuk, hogy milyen metrikákat ad. A fentiekben létrehoztunk egy monitor nevű overlay hálózatot. Erre mind a Node Exporer mind a cAdviser és a Prometheus is közvetlen fog csatlakozni egy egy network interfésszel, ahol közvetlen meg tudják egymást szólítani, tehát egyáltalán nem szükséges a Node Exporter vagy a cAdviser egyik portját sem publikálni az ingres, load balanc-olt hálózatban. Azonban ha nem publikáljuk a portájt, nem tudunk a böngészőből belenézni. Ezért mielőtt swarm service-ként telepítenénk, elsőként standalon konténerként fel fogjuk rakni az mg0 node-ra, úgy hogy publikáljuk a 9100 portját, ahol a metrikákat szolgáltatja, majd a böngészővel meg fogjuk nyitni ezt a portot. <pre>docker run -d \-p 9100:9100 \--name node-exporter \--mount "type=bind,source=/proc,target=/host/proc" \--mount "type=bind,source=/sys,target=/host/sys" \--mount "type=bind,source=/,target=/rootfs" \prom/node-exporter:v0.16.0 \--collector.filesystem.ignored-mount-points \"^/(sys|proc|dev|host|etc)($|/)"</pre>  <pre># docker-machine ssh mg0 docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES7f81d5a9243c prom/node-exporter:v0.16.0 "/bin/node_exporter …" 18 seconds ago Up 18 seconds 0.0.0.0:9100->9100/tcp node-exporter</pre>  A KVM-es környezetünkben két virtuális hálózat található. A '''docker-machine''' hálózat, ami egy guest-only network. Ezt a docker-machine KVM driver hozta létre a swarm internal management kommunikációra. A másik hálózat a '''docker-network''' (eth0), amit mi hoztunk létre, ez egy publikus hálózat, ezen keresztül látnak ki a node-ok az Internetre, és mi is ezen hívjuk meg az ingress hálózaton elérhető, load-balance-olt swarm szolgáltatásokat. A '''docker-machine ip''' sajnos a guest-only IP címet adja vissza, nekünk viszont a másik kell:   # docker-machine ssh mg0 ifconfig | grep -A 1 eth0 | grep "inet addr" inet addr:'''<span style="color:red">192.168.123.36</span>''' Bcast:192.168.123.255 Mask:255.255.255.0  http://192.168.123.36:9100/metrics:[[File:ClipCapIt-180902-135755.PNG]] <pre># docker-machine ssh mg0 docker rm -f node-exporter</pre>  Service-ként így kell feltenni. Azért nem kell portot nyitni, mert a monitor nevű overlay hálózatra van kötve, ahova majd a Prometheus-t is rákötjük, így nincs arra szükség, hogy a host OS felé kinyissuk a 9100-as portot. <pre>docker service create \--name node-exporter \--mode global \--network monitor \--mount "type=bind,source=/proc,target=/host/proc" \--mount "type=bind,source=/sys,target=/host/sys" \--mount "type=bind,source=/,target=/rootfs" \prom/node-exporter:v0.16.0 \--collector.filesystem.ignored-mount-points \"^/(sys|proc|dev|host|etc)($|/)"</pre>  Létezik egy módosított változata is a node-exporter-nek, ami képes a swarm node nevét is belerakni a metrika címkéjébe, így nem csak egy IP címet látunk majd a Prometheus-ban/Grafana-ban, ahem egy beszédes node nevet, pl: mg0<pre>docker service create --detach=false \ --name node-exporter \ --mode global \ --network monitor \ --mount type=bind,source=/proc,target=/host/proc \ --mount type=bind,source=/sys,target=/host/sys \ --mount type=bind,source=/,target=/rootfs \ --mount type=bind,source=/etc/hostname,target=/etc/host_hostname \ -e HOST_HOSTNAME=/etc/host_hostname \ basi/node-exporter:latest \ --path.procfs /host/proc \ --path.sysfs /host/sys \ --collector.filesystem.ignored-mount-points "^/(sys|proc|dev|host|etc)($|/)" \ --collector.textfile.directory /etc/node-exporter/ </pre> A "'''mode globa'''l" miatt kerül rá az összes swarm résztvevőre.<pre># docker service ps node-exporter ID NAME IMAGE NODEwu1gprh06sgj node-exporter.y6pm0pw3l12d46lmb3qf4phg1 prom/node-exporter:v0.16.0 mg0 khoy23w1c48c node-exporter.7cxts15b77dvsbm9gygn7846j prom/node-exporter:v0.16.0 worker41bf9g1n3xheo node-exporter.zg7qx4aowtlh239lw29gvsbuf prom/node-exporter:v0.16.0 worker2y5d1l42a6p16 node-exporter.utxvbnfxu5x5sydnhd1uj7n5b prom/node-exporter:v0.16.0 worker1 ttx9wyggx4wt node-exporter.y1y1wnhz8kq70smuuet8exdhh prom/node-exporter:v0.16.0 worker0</pre> ==cAdvisor==Mi az a cAdvisor ... + architectura ábra. ... A cAdisor és a Node Exporter metrikái között van egy kis átfedés, mert a cAdivisor is szolgáltat pár OS specifikus metrikát.  A cAdivsor -t sem lenne muszáj konténerben futtatni, de így sokkal egyszerűbb. A lényeg, hogy tudja olvasni a host-on futó dockar démon állapotát, tehát a docker socket-et fel kell mountolni a cAdvisor konténernek.  A későbbiekben, mikor majd swarm service-ként telepítjük a '''cAdvisor'''-t nem lesz rá szükség hogy a publikáljuk a 8080-ás portját az ingress, load-balance-olt hálózatra, mivel a '''cAdvisor''' konténerek is a monitor nevű overlay hálózatra fognak kapcsolódni, így a Prometheus el fogja közvetlen érni őket. Azonban mi előbb meg akarjuk nézni böngészőből, hogy hogyan néznek ki a metrikák, amiket szolgáltat, ezért esőként standalone docker konténerként fel fogjuk telepíteni ezt is az mg0 node-ra, úgy hogy publikáljuk a 8080 portját. <pre>docker run -d --name cadvisor \-p 8080:8080 \--mount "type=bind,source=/,target=/rootfs" \--mount "type=bind,source=/var/run,target=/var/run" \--mount "type=bind,source=/sys,target=/sys" \--mount "type=bind,source=/var/lib/docker,target=/var/lib/docker" \google/cadvisor:v0.28.5</pre> Mivel a cAdviser konténert is az mg0 node-ra tettük, ugyan azon az IP-n érhető el mint az előző példában a Node Exporter. http://http://192.168.123.36:8080/metrics:[[File:ClipCapIt-180902-140813.PNG]]  http://192.168.123.36:8080:[[File:ClipCapIt-180821-174032.PNG]] :[[File:ClipCapIt-180821-174112.PNG]]  A grafikus felületnek sok értelme nincsen, ugyanis a cAdvisor-t kifejezetten cluster-ek monitorozására találták ki. A grafikus felület csak egy node lelki világát mutatja, és mivel minket az összes node érdekel, ezért a grafikus felület használhatatlan valójában. Ráadásul ha swarm-ban futtatnánk a 8080 porttal, akkor az ingress load balancer miatt sosem tudnánk, hogy melyik node webes felületére csatlakoztunk be, tehát swarm módban tényleg használhatatlan. Mivel a Prometheus a "közös" overlay hálózaton közvetlen el fogja érni a cAdvisor konténert, ezért itt az ingress hálózat nem fog bezavarni.   Ezért úgy fogjuk swarm service-ként kirakni a cAdivos-ort, hogy a 8080-as portját nem is nyitjuk ki a host felé, ugyanúgy rárakjuk a '''monitor''' nevű overlay hálózatra, ahol a Prometheus el fogja érni közvetlenül a http://10.0.0.X:8080/metrics linken.  <pre>docker service create --name cadvisor \--mode global \--network monitor \--mount "type=bind,source=/,target=/rootfs" \--mount "type=bind,source=/var/run,target=/var/run" \--mount "type=bind,source=/sys,target=/sys" \--mount "type=bind,source=/var/lib/docker,target=/var/lib/docker" \google/cadvisor:v0.28.5</pre>A "--mode global" miatt kerül ki az összes noder-ra, és ugyan úgy rákötöttük a '''monitor''' nevű overlay hálózatra. <pre># docker service ps cadvisor ID NAME IMAGE NODE sb6kszve3q9z cadvisor.7cxts15b77dvsbm9gygn7846j google/cadvisor:v0.28.5 worker4 4gi5aqnp790d cadvisor.y1y1wnhz8kq70smuuet8exdhh google/cadvisor:v0.28.5 worker0uxy7ybpdgp0u cadvisor.zg7qx4aowtlh239lw29gvsbuf google/cadvisor:v0.28.5 worker2dpddiisqmrtx cadvisor.utxvbnfxu5x5sydnhd1uj7n5b google/cadvisor:v0.28.5 worker15kalv9p21iav cadvisor.y6pm0pw3l12d46lmb3qf4phg1 google/cadvisor:v0.28.5 mg0 </pre> ==DNS lookup== A Prometheus-nak tudnia kell az összes Node-Exporter és cAdvisor konténer '''monitor''' hálózatbeli IP címét, hogy le tudja kérdezni tőlük a metrikákat. Az IP címeket nyilván nem drótozhatjuk be a Prometheus konfigurációjába, mivel node-ok dinamikusan létrejönnek és megszűnnek egy swarm cluster-ben. Szerencsére a swarm a '''tasks.<service név>''' dns lekérdezés hatására visszaadja a szolgáltatáshoz tartozó node-ok IP cím listáját azon az overlay hálózaton, ahol a lekérdezést végeztük (tehát egy olyan konténerből kell a lekérdezést végezni, ami ugyan arra az overlay hálózatra csatlakozik, mint a szolgáltatás konténerei. A Prometheus képes ilyen lekérdezéseket végrehajtani minden metrika begyűjtés előtt, hogy tudja, hogy aktuálisan melyik node-któl kell begyűjteni a metrikákat.   Ahhoz hogy ezt demonstrálni tudjuk, szükségünk van egy olyan konténerre, ami szintén a '''monitor''' nevű overlay hálózatra csatlakozik, és van benne dns util program, pl '''nslookup''' vagy '''dig'''. Fontos, hogy ezt a konténert swarm service-ként futtassuk, hogy rá tudjuk csatlakoztatni a '''monitor''' overlay hálózatra, ahol a DNS lekérdezést szeretnénk eszközölni. A swarm a localhost-on biztosít egy beépített DNS szervert a konténerek számára. A demonstráció céljára tökéletes a '''tutum/dnsutils''' image, ami ugyan ahogy lefutott le fog állni, és a swarm már is újra fogja indítani, ettől még minden egyes lefutáskor ki fogja nekünk írni a konténer log-ba a dns lekérdezés eredményét.  :[[File:ClipCapIt-180821-201934.PNG]]   A következő példában az összes node-exporter konténer IP címét fogjuk begyűjteni. <pre># docker service create --name util \--network monitor \--replicas 1 \tutum/dnsutils nslookup tasks.node-exporter</pre> <pre># docker service logs -f util ...util.1.zueyj5pydd0i@worker1 | Address: 10.0.0.17util.1.zueyj5pydd0i@worker1 | Address: 10.0.0.18util.1.zueyj5pydd0i@worker1 | Address: 10.0.0.15util.1.zueyj5pydd0i@worker1 | Address: 10.0.0.11util.1.zueyj5pydd0i@worker1 | Address: 10.0.0.16</pre>Amint megjelenik a log-ban a node-ok listája, el is távolíthatjuk a folyton újrainduló '''util''' nevű service-t. ==Prometheus== A Prometheus konténernek egyrészt csatlakoznia kell a '''monitor''' nevű overlay hálózatra, hogy le tudja kérdezni a '''node-exporter''' és a '''cAdvisor''' által begyűjtött metrikákat, másrészt publikálnia kell a 9090-ás portját az '''ingress''' (load-balance-olt) hálózaton. Fontos, hogy nem fogjuk megkötni, hogy melyik nodre-ra telepítse fel a swarm, csak azt, hogy egy példány jöjjön csak belőle létre. ===Prometheus konfiguráció=== Fontos, hogy a Prometheus dinamikusan frissítse a '''cAdvisor''' és a '''node-exporter''' node-ok listáját, ne legyen beégetve a config-ba, hiszen ha a swarm mérete változik (pl dinamikus skálázás miatt) akkor fontos, hogy az új node-okat a Prometheus automatikusan hozzáadja a lekérdezendő node-ok listájához, vagy ha csökken a cluster akkor a kieső node-okat már ne vegye figyelembe. A Prometheus képes a fent bemutatott DNS lekérdezéssel frissíteni az aktuális node listát ('''task.<service név>''', pl tasks.node-exporter), persze ehhez az kell, hogy ő is rajta legyen a '''monitor''' nevű overlay hálózaton, ahol a DNS lekérdezést eszközölni szeretné, ahogy ezt az előző példában láthattuk, csak a tutum/dnsutils helyett a Prometheus végzi majd a lekérdezést.  A Prometheus konfigurációs fájlja a /etc/pormetheus/prometheus.yml.  '''prometheus.yml'''<syntaxhighlight lang="C++">global: scrape_interval: 5s scrape_configs: - job_name: 'node' dns_sd_configs: - names: ['tasks.node-exporter'] type: A port: 9100  - job_name: 'cadvisor' dns_sd_configs: - names: ['tasks.cadvisor'] type: A port: 8080  - job_name: 'prometheus' static_configs: - targets: ['prometheus:9090']</syntaxhighlight>A konfiguráció elég beszédes. Összesen három darab metrika forrást (job-ot) definiálunk. A node-exporter és a cAdvisor konténerek végpontját a docker DNS-böl kérdezni le (dns_sd_configs). A lekérdezés A osztályú DNS rekordokat ad vissza (type:A). A harmadik metrika szolgáltató a Prometheus saját maga, aminek fixen megadtuk az elérhetőségét (static_config) a swarm szolgáltatás nevével.   ===Volume plugin használata===A Prometheus-nak a konfigurációs fájlját és az adatbázis mappáját a távoli NFS szerveren fogjuk tárolni, és a [[Docker_volume_orchestration#Netshare|"Docker volume orchestration/Netshare"]] fejezetben bemutatott '''Negshare''' volume plugin-el fogjuk ezeket a Prometheus konténerbe mount-olni.   A Prometheus konfigurációs fájlja itt van: ''/etc/prometheus/prometheus.yml''Az /'''etc/prometheus/''' mappában a yml fájlon kívül két további mappa is található. Nekünk az lenne a célunk, hogy a '''prometheus.yml''' fájl az NFS megosztásbol jöjjön. Sajnos volume-ként nem lehet egy fájlt mount-olni csak mappákat, csak a bind mount-al lehet követlen fájlokat mount-olni a konténerbe. Vagyis nem tehetjük meg, hogy csak a '''prometheus.yml''' fájlt cseréljük le, az NFS megosztást csak a teljes '''/etc/prometheus/''' mappába tudjuk felcsatolni ezzel fejbe vágva az ottani többi fájlt/mappát. Nem tudunk mást tenni, mint hogy a teljes '''/etc/prometheus''' mappát átmásoljuk az NFS megosztásunkra, ahol majd lecseréljük a prometheus.yml fájlt.  Ehhez elsőként telepítsük föl a Prometheus konténert standalone módban mount nélkül, hogy onnan ki tudjuk másolni a /etc/prometheus mappa tartalmát. Elsőként nézzük meg mi van a '''/etc/prometheus''' mappában, majd a mappa tartalmát másoljuk át az NFS meghajtóra. <pre>docker run -d --name prometheus -p 9090:9090 \prom/prometheus:v2.3.2</pre>A Prometheus image-ben bash nincs, de van sh: <pre># docker exec -it prometheus sh/prometheus $ ls -l /etc/prometheustotal 4lrwxrwxrwx 1 nobody nogroup 39 Jul 12 15:08 console_libraries -> /usr/share/prometheus/console_librarieslrwxrwxrwx 1 nobody nogroup 31 Jul 12 15:08 consoles -> /usr/share/prometheus/consoles/-rw-r--r-- 1 nobody nogroup 926 Jul 12 15:04 prometheus.yml</pre>Láthatjuk, hogy a prometheus.yml mellett még két simlink is található, ezeket is át kell másolni.   Másoljuk át a mappa tartalmát, majd töröljük le a standalone Prometheus konténert, hogy fel tudjuk service-ként telepíteni. <pre># docker cp -L prometheus:/etc/prometheus /home/adam/Projects/DockerCourse/persistentstore/prometheus/# chmod 777 -R /home/adam/Projects/DockerCourse/persistentstore/# mv /home/adam/Projects/DockerCourse/persistentstore/prometheus/prometheus/ /home/adam/Projects/DockerCourse/persistentstore/prometheus/config# docker rm -f prometheus</pre>   ===Prometheus szolgáltatás indítása===  <pre>docker service create \--detach=false \--name prometheus \--network monitor \-p 9090:9090 \--mount "type=volume,src=192.168.42.1/home/adam/Projects/DockerCourse/persistentstore/prometheus/config,dst=/etc/prometheus,volume-driver=nfs" \--mount "type=volume,src=192.168.42.1/home/adam/Projects/DockerCourse/persistentstore/prometheus/data,dst=/prometheus,volume-driver=nfs" \prom/prometheus:v2.3.2</pre>  Nézzük meg, hogy melyik node-ra került: <pre># docker service ps prometheus ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS11bkjfeobwuk prometheus.1 prom/prometheus:v2.3.2 mg0 Running Running 25 seconds ago </pre>  Innentől kezdve a Prometheus webes konzol elérhető bármelyik swarm node publikus IP címén a 9090-es porton az ingress hálózaton keresztül ('''docker-network''' hálózat, eth0 interfész). Kérdezzük le a worker0 IP címét. Sajnos a '''docker-machine ip''' parancs nem a publikus címet adja vissza, hanem a '''docker-machine''' hálózati címet, ami a swarm management kommunikációra szolgál a node-ok között.   # docker-machine ssh worker0 ifconfig | grep -A 1 eth0 | grep "inet addr" inet addr: '''<span style="color:red">192.168.123.141</span>''' Bcast:192.168.123.255 Mask:255.255.255.0  http://192.168.123.141:9090/graph:[[File:ClipCapIt-180903-212324.PNG]]  Végezetül nézzük meg a Status/Targets képernyőn, hogy mind a 8+1 konténerhez sikerült a kapcsolódnia (4 node-exporter, 4 cAdvisor, 1 Prometheus):[[File:ClipCapIt-180903-213141.PNG]] =Lekérdezések=https://prometheus.io/docs/prometheus/latest/querying/basics/#gotchas<br>A Prometheus-ban a lekérdezéseket PromQL nyelven kell írni. A lekérdezéseknek két legfontosabb eleme: * Instant vector: A szelektronak megfelelő idősorok egy-egy értékét adja vissza egy meghatározott időpillanatra. Pl ha a selector a '''machine_memory_bytes''', akkor az összes olyan idősort vissza fogja adni, ahol a metrika alapneve machine_memory_bytes, vagyis az összes címe variánsát. Fontos, hogy minden egyes idősorhoz csak egyetlen egy értéket fog vissza adni. Ha külön nem határozzuk meg, akkor ez a legutolsó lekérdezés eredménye lesz. Az instant vector lekérdezések jeleníthetők meg gráfokon.  * Range vektor: A szelektor mellé megadunk egy idő intervallumot is. A szelektornak megfelelő idősorhoz az összes értéket vissza fogja adni amit a megadott intervallumban rögzített. Az intervallum mindig a jelenben kezdődik és az intervallum hosszával megy vissza az időben. Pl: ha a selector '''machine_memory_bytes [5m]''' akkor az összes illeszkedő nevű idősor minden felvett értékét vissza fogja adni amit az elmúlt 5 percben rögzített.  ==Selector-ok== ===Instant vektor választó===Ha magunk akarunk lekérdezést írni, akkor ezt a legegyszerűbb a Prometheus webes felületén összerakni a '''Graph''' képernyőn. A képernyő tetején lévő kereső mezőbe (Expression) kezdjük el begépelni a keresett metrika nevét, ekkor fel fogja dobni az összes olyan metrikát, ami tartalmazza a beírt nevet. A legegyszerűbb selector, ha beírjunk egy metrika alap nevet, aminek vannak címke variánsai: '''machine_memory_bytes''' Az Execute megnyomása után a '''Console''' fülön megjelenik a találati lista. A baloldali oszlopban van a beírt metrika név összes címke variánsa, a jobboldali oszlopban pedig a legutoljára rögzített értékük. :[[File:ClipCapIt-180903-230918.PNG]]Láthatjuk, hogy összesen négy metrika felel meg a keresési kritériumnak, amit a négy cAdviser konténer szolgáltatott. Az utolsó lekérdezéskor mind a 4 node-on a memória használat 800 mega körül volt.   Ha átkapcsolunk a Graph fülre, akkor a Prometheus a Console fülön listázott metrikákhoz ki fog rajzolni egy gráfot, ahol az adott metrika értékeit láthatjuk egy órára visszamenően, tehát itt nem csak a legutolsó értéket láthatjuk, hanem az utolsó egy óra összes értékét. Mivel a cluster-en még semmilyen valódi szolgáltatás nem fut, ezért a gráf nem túl látványos: :[[File:ClipCapIt-180903-234741.PNG]]Mivel összesen 4 metrika találat volt az eredeti lekérdezésre, mind a négynek kirajzolja az 1 órás grafikonját (jelenleg a négy vonal teljesen egybe esik, nem a legjobb példa)  ===Range vektor választó===A range vektor lekérdezésben a metrika alapneve után oda kell írni az intervallumot kapcsos zárójelben, aminek az értékeire kíváncsiak vagyunk. Az eredmény a selector-ra illeszkedő összes címke variáns összes értéke a megadott intervallumban csoportosítva metrika nevek szerint. Pl nézzük meg a '''machine_memory_bytes''' selector-ra illeszkedő metrikákat az elmúlt 15 másodperce: :[[File:ClipCapIt-180904-001113.PNG]]Láthatjuk, hogy mind a 4 megtalált metrikához (a négy cAdviser konténerből) 3-3 érték tartozik, mivel 5 másodpercenként mintavételez a Prometheus a konfiguráció alapján. A jobboldali oszlopban láthatjuk a metrika értéke után @-al elválasztva az időbélyeget.   ==Fontos függvények és operátorok=====rate function===A rate függvény megmutatja range vektorokra az egy másodperce jutó változást: rate(<metrika név>[intervallum hossz]) Elsőnek nézzünk egy range vektort: prometheus_http_request_duration_seconds_count{handler="/query",instance="prometheus:9090",job="prometheus"}[10s] Mivel 5 másodpercre állítottuk a Prometheus adatbegyűjtését, ezért 10s-re visszamenve a jelenből, két minta lesz benne: 139 @1536269070.221 141 @1536269075.221 Láthat hogy a 10s ezelőtti begyűjtéskor a request-ek száma 139-volt, de szorgosan kattintgattam az ezt követő 5 másodpercben, ezért a következő begyűjtéskor már 141-volt. Vegyük ennek a range értékét, vagyis nézzük meg, hog 1 másodperce mekkora változás jutott: rate(prometheus_http_request_duration_seconds_count{handler="/query",instance="prometheus:9090",job="prometheus"}[10s]) Az eredmény 0.5 lesz, tehát a 10s hosszú intervallumban 0.5-öt nőt a számláló másodpercenként.  <br>Ha a '''range vektorunk''' selector-a nem csak egy metrikára illeszkedik, akkor a '''rate''' is több eredményt fog visszaadni, minden egyes range vektor találatra egyet.<br>Tegyük fel, hogy van két counter típusú metrikánk (az alap nevük megegyezik, csak a címkében különböznek) example_metric{type="Y"} example_metric{type="X"} Nézzük az alábbi range vektort: example_metric[10s]Ennek az eredménye a következő lesz, ha 5 másodpercenként mintavételezünk: example_metric{type="X"} 1 @1536433370.221 2 @1536433375.221  example_metric{type="Y"} 5 @1536433370.221 10 @1536433375.221 Ha erre alkalmazzuk a '''rate''' függvényt, két eredményt kapunk: rate(example_metric[10s]) {type="X"} 0.1 {type="Y"} 0.5 ===aggregation operators===Egy instant vektor összes találatára kijött metrika összegét mondja meg. Ezek a metrikák csak címkékben különbözhetnek egymástól, mivel a metrika alap nevét (a címke nélküli részt) kötelező tejesen megadni. Az instant vektor-os keresés találatai a keresésben nem megadott címkék értékeiben különbözhetnek csak egymástól.  Pl: ha vannak ilyen metrikáim: prometheus_http_request_duration_seconds_count{handler="...",instance="...",job="..."}Ha az instant vektor keresésekor csak az alapnevet adom meg (prometheus_http_request_duration_seconds_count) akkor az összes címke variánst meg fogom találni: prometheus_http_request_duration_seconds_count{handler="/query",instance="prometheus:9090",job="prometheus"} 1 prometheus_http_request_duration_seconds_count{handler="/graph",instance="prometheus:9090",job="prometheus"} 3 prometheus_http_request_duration_seconds_count{handler="/label/:name/values",instance="prometheus:9090",job="prometheus"} 4 prometheus_http_request_duration_seconds_count{handler="/metrics",instance="prometheus:9090",job="prometheus"} 10619 prometheus_http_request_duration_seconds_count{handler="/query",instance="prometheus:9090",job="prometheus"} 168 prometheus_http_request_duration_seconds_count{handler="/static/*filepath",instance="prometheus:9090",job="prometheus"} 8  De ha pontosítom a keresést a '''handler="/query"''' címével, akkor már csak két elemű lesz a találat: prometheus_http_request_duration_seconds_count{handler="/query",instance="prometheus:9090",job="prometheus"} 1 prometheus_http_request_duration_seconds_count{handler="/query",instance="prometheus:9090",job="prometheus"} 168  Nam most, az összes aggregation operator ezen instant vektor találatokkal csinál valamit, pl a sum(..) ezen találatok értékét adja össze: sum(prometheus_http_request_duration_seconds_count) 10841  Továbbiak: * sum (calculate sum over dimensions)* min (select minimum over dimensions)* max (select maximum over dimensions)* avg (calculate the average over dimensions)* count (count number of elements in the vector)* count_values (count number of elements with the same value)   ===Aggregation operation eredmény csoportosítása=== Ha a by vagy a without kulcssavakat az aggregation operátor lekérdezés mögé írunk, és megadunk ott egy címke listát, akkor az eredmény a címke lista lapján lesz csoportosítva. <aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]  '''by (label list)'''<br>Ha a by mögé megadunk egy címkét, akkor az aggregation operator elsőként csoportokat fog képezni azokból a mintákból, ahol a címke(ék) megegyeznek, és azokra fogja végrehajtani az aggregálást. Nézzük az alábbi nagyon egyszerű példát, ahol a metrika alapnév=example_metric: example_metric{job="A", type="X"} = 1 example_metric{job="A", type="Y"} = 2 example_metric{job="B", type="X"} = 4 example_metric{job="B", type="Y"} = 5 Ekkor a sum by nélküli eredménye: sum(example_metric) Element Value {} 12  De ha hozzáadjuk a by (job)-ot, akkor két választ kapunk, egyet az A sum-ra, egyet a B-sum-ra: sum(example_metric) by (job) Element Value {job="A"} 3 {job="B"} 9   '''without (label list)'''<br>A without-al pont az ellenkezőjét mondjuk meg, hogy mi szerint ne csoportosítson mielőtt össze adná a csoportok eredményét, tehát minden más szerint csoportosítani fog. A fenti példával ekvivalens eredményt kapunk, ha a '''by (job)''' helyett '''without (type)''' -ot írunk. sum(example_metric) without (type) Element Value {job="A"} 3 {job="B"} 9  <br>==Lekérdezés példák==  Átlag válaszidő az elmúlt 5 percben <br>A http_request_duration_seconds hisztogramnak van egy _sum és egy _count metrikája. Vegyük az összes _sum értéket az elmúlt 5 percben [5], majd vegyük ennek a <pre> rate(http_request_duration_seconds_sum[5m])/ rate(http_request_duration_seconds_count[5m])</pre> =Vizualizáció: Grafana=Ugyan a Prometheus-ban tudunk magunk lekérdezéseket írni, és bizonyos keretek között ezt a Prometheus meg is tudja jeleníteni, produkciós környezetben szükségünk van egy vizualizációs eszközre, ami a mi esetünkben a Grafana lesz. Grafana a piacvezető Time Series DB vizualizációs eszköz. Out of the box támogatja az elterjedt TSDB-ket: * Graphite* Elasticsearch* InfluxDB* OpenTSDB* KairosDB* Prometheus  ==Telepítés== ===Volume plugin használata===A konténerek írható rétegét nem szabad írás intenzíven használni, írás intenzív alkalmazásokhoz (mint amilyen a Granafa is) volume-okta kell használni. Ehhez a már ismert '''Netshare''' volume plugin-t fogjuk használni nfs protokollal. Ezen felül a grafana konfigurációs mappáját is át fogjuk helyezni az on-demand volume megosztásra.   A Grafan adatbázis a konténeren belül a '''/var/lib/grafana''' mappában található. Ezt szimplán mount-olni fogjuk az NFS megosztás '''grafana/data''' mappájába. A konfigurációs állomány a '''/etc/grafana''' mappában van. Ezt fogjuk mount-olni az NFS megosztás grafana/config mappájába, de előtte át kell oda másolni az '''/etc/grafana''' mappa tartalmát, ugyan úgy ahogy ezt a Prometheus telepítésénél is tettük. Elsőként feltelepítjük standalone docker konténerként, majd kimásoljuk belőle a konfigurációs mappát:  <pre>docker run --name grafana \grafana/grafana:5.2.4</pre><pre># docker cp -L grafana:/etc/grafana /home/adam/Projects/DockerCourse/persistentstore/grafana/config/# cd /home/adam/Projects/DockerCourse/persistentstore/grafana/config/grafana/provisioning/# mv grafana/ config/# chmod 777 -R config/</pre>  A használni kívánt datasource-okat (jelen esetben a Prometheus-t) vagy kézzel állítjuk be a Grafana webes konfigurációs felületén, vagy készítünk egy datasource yaml konfigurációs fájlt a '''/etc/grafana/provisioning/datasource''' mappába, így telepítéskor automatikusan létre fogja hozni a Prometheus adatkapcsolatot. grafana/provisioning/datasources/datasource.yaml<syntaxhighlight lang="C++">apiVersion: 1 datasources: - name: Prometheus type: prometheus access: proxy url: http://prometheus:9090</syntaxhighlight> A Grafana is a '''monitor''' nevű overlay hálózathoz fog csatlakozni, így közvetlenül el tudja érni a Promethues konténert. Mivel közös overlay hálózaton vannak, a Docker DNS fel tudja oldani a szolgáltatás nevét a konténer overlay hálózatbeli IP címére ha olyan rendszer indítja a névfeloldást, aki ugyan azon az overlay hálózaton van.    Ugyan így a '''grafana/provisioning/dashboards/''' mappába előre hozzáadhatunk dashboard-okat a Grafana-hoz, ami telepítés után azonnal rendelkezésre fog állni.  <br> ===Service létrehozása=== A Grafana-t ugyan úgy a monitor nevű overlay hálózathoz fogjuk csatlakoztatni. Két volume-ot fogunk felcsatolni a Netshare volume plugin segítségével, egyet a konfigurációnak, egyet pedig az adatbázisnak. Publikáljuk az '''ingress''' hálózatra a 3000-as portot. <pre>docker service create \--detach=false \--name grafana \--network monitor \--mount "type=volume,src=192.168.42.1/home/adam/Projects/DockerCourse/persistentstore/grafana/config/,dst=/etc/grafana,volume-driver=nfs" \--mount "type=volume,src=192.168.42.1/home/adam/Projects/DockerCourse/persistentstore/grafana/data/,dst=/var/lib/grafana,volume-driver=nfs" \-p 3000:3000 \grafana/grafana:5.2.4</pre> <pre># docker service lsID NAME MODE REPLICAS IMAGE PORTS959l8hlvh4u8 grafana replicated 1/1 grafana/grafana:5.2.4 *:3000->3000/tcpcbg79ex3db2g portainer replicated 1/1 portainer/portainer:latest *:9000->9000/tcpdzha5bvpjx67 node-exporter global 4/4 prom/node-exporter:v0.16.0 x035ni7e3qhi prometheus replicated 1/1 prom/prometheus:v2.3.2 *:9090->9090/tcpz60yg7cemg7p cadvisor global 4/4 google/cadvisor:v0.28.5 </pre> ==Login to Grafana== Mindegy is melyik node-ra került föl, az mg0 IP címével nyissuk meg az előbb publikált 3000 portot: <br> http://192.168.123.141:3000/login<br>A default user/password: '''admin/admin''' Miután megadtuk az új jelszót első belépéskor a settings képernyőn landolunk, ahol megjelenik az előre hozzáadott Prometheus data source. :[[File:ClipCapIt-180909-122943.PNG]]  ==Adding dashboards== ===Terhelés a node-okon===Elsőként generáljuk egy kis forgalmat a node-okon, ehhez a '''progrium/stress''' docker konténert fogjuk használni. <br>https://github.com/progrium/docker-stress<pre>docker service create \--detach=false \--mode global \--name loadgenerator \progrium/stress --cpu 2 --io 1 --vm 2 --vm-bytes 128M --timeout 30s</pre> A progrium/stress mindig csak 30s-ig fog futni, de ahogy leáll a swarm újra fogja indítani, tehát pár perc után töröljük: <pre># docker service rm loadgenerator</pre> ===CPU idle grafikon===Menjünk a bal oldali "+" jelre, majd "Dashboard" majd Graph (bal felső sarok). Data source-nak válasszuk ki a Prometheus-t, majd adjuk meg a következő lekérdezést: irate(node_cpu_seconds_total{mode="idle"}[5m]) :[[File:ClipCapIt-180910-231059.PNG]] Ezután a Time range fülön adjuk meg hogy 1 óra legyen a felbontás: :[[File:ClipCapIt-180910-231250.PNG]] Ekkor mind a 4 node-ra mutatni fogja, hogy a CPU hány százalékban idle: :[[File:ClipCapIt-180910-231334.PNG]]A jobb felső sarokban lévő save ikonnal mentsük el.   ===Node Exporter Server Metrics===https://grafana.com/dashboards/405 :[[File:ClipCapIt-180910-223918.PNG]]Importálhatunk komplett Dashboard-okat, ami előre van gyártva. A NodeExporter metrikákhoz pl több Dashboard is készült, ilyen pl a '''Node Exporter Server Metrics''', ahol az összes node-ot akár egyszerre is láthatjuk. Az a baj, hogy a Node listában nem csak a Node Exporter-ek vannak, hanem az összes hoszt, aki a '''monitor''' nevű overlay hálózatra csatlakozik. A node exporter-hez ebből a hosszú listából csak 4 IP tartozik  =Swarm stack= Az egész fentebb leírt architektúrát létrehozhatjuk swarm stack-ként egyetlen egy docker compose fájlal.  ===compose fájl=== '''docker-compose.yml'''<syntaxhighlight lang="C++">version: '3'services: cadvisor: image: google/cadvisor:v0.28.5 networks: - monitor volumes: - "/:/rootfs" - "/var/run:/var/run" - "/sys:/sys" - "/var/lib/docker:/var/lib/docker" deploy: mode: global restart_policy: condition: on-failure node-exporter: image: basi/node-exporter:v1.15.0 networks: - monitor volumes: - "/proc:/host/proc" - "/sys:/host/sys" - "/:/rootfs" - "/etc/hostname:/etc/host_hostname" command: - "--path.procfs=/host/proc" - "--path.sysfs=/host/sys" - "--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)" - "--collector.textfile.directory=/etc/node-exporter/" environment: - HOST_HOSTNAME=/etc/host_hostname deploy: mode: global restart_policy: condition: on-failure prometheus: image: prom/prometheus:v2.3.2 ports: - "9090:9090" networks: - monitor volumes: - "prometheus-conf:/etc/prometheus" - "prometheus-data:/prometheus" grafana: image: grafana/grafana:5.2.4 ports: - "3000:3000" networks: - monitor volumes: - "grafana-conf:/etc/grafana" - "grafana-data:/var/lib/grafana"  networks: monitor: driver: overlay volumes: prometheus-conf: driver: nfs driver_opts: share: 192.168.42.1:/home/adam/Projects/DockerCourse/persistentstore/prometheus/config prometheus-data: driver: nfs driver_opts: share: 192.168.42.1:/home/adam/Projects/DockerCourse/persistentstore/prometheus/data grafana-conf: driver: nfs driver_opts: share: 192.168.42.1:/home/adam/Projects/DockerCourse/persistentstore/grafana/config grafana-data: driver: nfs driver_opts: share: 192.168.42.1:/home/adam/Projects/DockerCourse/persistentstore/grafana/data</syntaxhighlight> Kiemelendők: * A '''Netshare''' NFS volume-okat csak a globális '''volumes''' szekcióban lehet definiálni, mert csak a globális volumes szekciónak van '''driver''' és '''driver_opts''' paramétere. A service definíción belüli '''volumes''' szekciónak nincs. * A Netshare 0.35-ös verziójában bevezették a '''share''' paraméter kezelését. Korábbi verziókat még nem lehetett swarm stack-ben (compose) használni. A globális '''volumes''' szekcióban a volume forrását elvileg nem kell megadni, az a swarm-ra van bízva, hogy hol hozza létre, ezért nincs neki src paramétere. Az egyetlen erre használható paraméter a '''driver_opts''' share paramétere, amit a korábbi verziók még nem tudtak kezelni. (Emlékezzünk vissza, hogy a swarm service definícióban ez nem okoz gondot, mert ott a forrást is meg tudtuk adni)* Mivel a globális '''networks''' szekcióban nem adtuk meg az external paramétert, a '''monitor''' nevű overlay hálózatot minden alkalommal létre fogja hozni a swarm stack telepítése előtt, és le is fogja törölni ha töröljük a stack-et.* A node-exporter command line paramétereibe kötőjelet kell használni, és nem kell dupla macskakörmöt használni a paraméter értékének megadásakor. A "&" jelet még egy "&" jellel kell escape-elni. ===Stack telepítése=== A stack-et az alábbi paranccsal hozhatjuk létre. docker stack deploy --compose-file <yaml fájl név> <stack név>  A megadott stack nevet minden létrehozott szolgáltatáshoz hozza fogja fűzni prefix-ként, ezzel jelezve, hogy azok egy swarm stack részei. Még a monitor nevű overlay hálózat neve elég is oda fogja rakni a stack nevét.   Legyen a stack neve monitor: <pre># docker stack deploy --compose-file docker-compose.yml monitorCreating network monitor_monitorCreating service monitor_prometheusCreating service monitor_cadvisorCreating service monitor_node-exporterCreating service monitor_grafana</pre>  Ezzel létrejött a monitor_monitor nevű overlay hálózatunk, ezen felül 4 swarm service, szintén a monitor prefix-el: <pre># docker network lsNETWORK ID NAME DRIVER SCOPE...nar4kl8o8tat monitor_monitor overlay swarm</pre><pre># docker stack lsNAME SERVICESmonitor 4</pre><pre># docker service lsID NAME MODE REPLICAS IMAGE PORTSfb3poq1m3my0 monitor_cadvisor global 4/4 google/cadvisor:v0.28.5 pidw51mgpc0e monitor_node-exporter global 4/4 basi/node-exporter:v1.15.0 pu4z76b6oijq monitor_grafana replicated 1/1 grafana/grafana:5.2.4 *:3000->3000/tcpterni4ylw5ca monitor_prometheus replicated 1/1 prom/prometheus:v2.3.2 *:9090->9090/tcp</pre>  Keressük meg az egyik node ingress hálózatbeli címét, hogy tesztelni tudjuk a Prometheus és Grafana konzolt: # docker-machine ssh worker0 ifconfig | grep -A 1 eth0 | grep "inet addr" inet addr: '''<span style="color:red">192.168.123.252</span>''' Bcast:192.168.123.255 Mask:255.255.255.0  Most lépjünk be a Prometheus-ba és a Grafana-ba. Mivel mind a kettő az NFS megosztásból szedi a beállításait és az adatbázisát is, már semmilyen beállításra nincs szükség, ezeket már korábban mind elvégeztük. * Grafana: http://192.168.123.252:3000* Prometheus: http://192.168.123.252:9090