Üdv mindenkinek! Néhány hónappal ezelőtt elindítottuk új open-source projektünket — Grafana plugint a Kubernetes monitorozásához, amit a következő néven hívtunk: . A plugin forráskódja elérhető a . Ebben a cikkben szeretnénk megosztani veletek a történetet arról, hogyan készítettük el a plugint, milyen eszközöket használtunk és milyen buktatókkal találkoztunk a fejlesztés során. Kezdjük!
0. rész — bevezetés: hogyan jutottunk el idáig?
Az ötlet, hogy saját Grafana plugint készítsünk, teljesen véletlenül született meg. Cégünk már több mint 10 éve foglalkozik webprojektek monitorozásával, különböző bonyolultsági szinteken. Ez idő alatt jelentős tapasztalatot és érdekes esettanulmányokat halmoztunk fel, tapasztalatokat különböző monitorozó rendszerek használatával. És egy ponton felvetettük a kérdést: „Van-e varázsszerszám a Kubernetes monitorozására, amivel, ahogy mondani szokták, csak felrakod és megfeledkezel róla?”... A Kubernetes monitorozásának ipari szabványa természetesen régóta a Prometheus + Grafana kombináció. Különféle kész megoldások sokasága áll rendelkezésre ehhez a stackhez: prometheus-operator, a kubernetes-mixin dashboardok gyűjteménye, grafana-kubernetes-app.
A legérdekesebb lehetőség számunkra a grafana-kubernetes-app plugin volt, de ezt már több mint egy éve nem támogatják, és emellett nem működik az új node-exporter és kube-state-metrics verziókkal. Egy ponton úgy döntöttünk: „Miért ne készíthetnénk el saját megoldásunkat?”
Milyen ötleteket valósítottunk meg a saját pluginunkban:
- alkalmazás-térkép vizualizálása: kényelmes megjelenítés a klaszterben lévő alkalmazásokról, namespace-ek és deployments szerint csoportosítva...
- a „deployment — service (+ports)” típusú kapcsolatok vizualizálása.
- a klaszter alkalmazásainak eloszlásának vizualizálása a klaszter nodjai szerint.
- metrikák és információk gyűjtése több forrásból: Prometheus és k8s API szerver.
- monitorozás az infrastruktúra részének (processzoridő, memória, tároló alrendszer, hálózat használata) és az alkalmazások logikájának — pod-ok health-statusa, elérhető replikák száma, liveness/readyness próbák teljesítése — figyelemmel kísérésével.
1. rész: Mi az a „Grafana plugin”?
Műszaki szempontból a Grafana plugin egy Angular-vezérlő, amely a Grafana data könyvtárában található (/var/grafana/plugins/<your_plugin_name>/dist/module.js) és betölthető mint SystemJS-modul. Ezen a mappán belül egy plugin.json fájlnak is helyet kell kapnia, amely tartalmazza a bővítményed metaadatait: név, verzió, bővítmény típusa, linkek a repóhoz/weboldalhoz/engedélyhez, függőségek és így tovább.

module.ts

plugin.json
Ahogy a képernyőképen látható, a plugin.type = app értéket állítottuk be. Mivel a Grafana bővítményei háromféleképpen oszthatók meg:
panel: a legelterjedtebb bővítménytípus — egy panelt jelent, amely különböző metrikák vizualizálására szolgál, és különböző műszerfalak létrehozására használják.
datasource: egy bővítmény-kapcsoló valamilyen adatforráshoz (például Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
app: egy bővítmény, amely lehetővé teszi, hogy saját frontend alkalmazást építs Grafana-n belül, saját html-oldalakat hozz létre, és manuálisan hívj meg adatforrást, hogy különböző adatokat vizualizálj. Továbbá más típusú bővítmények (datasource, panel) és különböző műszerfalak is használhatók mint függőségek.

Példa egy bővítmény függőségeire, ahol a type = app.
A programozási nyelv lehet JavaScript vagy TypeScript (mi utóbbit választottuk). Választott példák hello-world bővítményekhez bármilyen típusban : ebben a repóban számos starter-pack található (még egy kísérleti React alapú bővítmény példát is találni lehet) előre telepített és konfigurált összeállítókkal.
2. rész: a helyi környezet előkészítése
A bővítmény fejlesztéséhez természetesen szükségünk van egy kubernetes klaszterre, amely teljes körűen rendelkezik az előre telepített eszközökkel: prometheus, node-exporter, kube-state-metrics, grafana. A környezetnek gyorsan, könnyen és zökkenőmentesen kell települnie, és a hot-reload biztosítása érdekében a Grafana data-mappáját közvetlenül a fejlesztő gépéről kell csatolni.
A legkényelmesebb megoldás a helyi munkára a kubernetes esetében . A következő lépésben telepítjük a Prometheus + Grafana csomagot a prometheus-operator segítségével. A folyamat részletes leírása megtalálható a prometheus-operator minikube-ra való telepítésében. A perzisztencia aktiválásához be kell állítani a parameter persistence: true értékre a charts/grafana/values.yaml fájlban, saját PV-t és PVC-t kell létrehozni, és azokat meg kell adni a persistence.existingClaim parameter-ben.
A minikube indító skript végső formája a következőképpen néz ki:
minikube start --kubernetes-version=v1.13.4 --memory=4096 --bootstrapper=kubeadm --extra-config=scheduler.address=0.0.0.0 --extra-config=controller-manager.address=0.0.0.0
minikube mount
/home/sergeisporyshev/Projects/Grafana:/var/grafana --gid=472 --uid=472 --9p-version=9p2000.L3. rész: közvetlenül a fejlesztés
Objektum modell
A plugin megvalósításának előkészítéseként úgy döntöttünk, hogy leírjuk azokat az alapvető Kubernetes entitásokat, amelyekkel dolgozni fogunk TypeScript-osztályok formájában: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Mindegyik osztály örökli a BaseModel közös osztályt, amely tartalmazza az konstruktort, destruktort, frissítő és láthatósági váltó módszereket. Minden osztályban le van írva a más entitásokkal való beágyazott kapcsolat, például a deployment típusú entitás pod-jainak listája.
import {Pod} from "./pod";
import {Service} from "./service";
import {BaseModel} from './traits/baseModel';
export class Deployment extends BaseModel{
pods: Array;
services: Array;
constructor(data: any){
super(data);
this.pods = [];
this.services = [];
}
}A getterek és setterek révén kényelmes és olvasható módon megjeleníthetjük vagy beállíthatjuk a szükséges entitásmérőszámokat. Például a formázott kimenet az allocatable CPU nod-ról:
get cpuAllocatableFormatted(){
let cpu = this.data.status.allocatable.cpu;
if(cpu.indexOf('m') > -1){
cpu = parseInt(cpu)/1000;
}
return cpu;
}Oldalak
A pluginunk összes oldalának listája kezdetben a pluing.json fájlunkon belül a függőségek szakaszában van leírva:

Minden oldal blokkban meg kell adnunk az OLDAL NEVÉT (ezután slug-ra lesz konvertálva, amelyen keresztül az oldal elérhető lesz); a lap működéséért felelős komponens nevét (a komponensek listája a module.ts fájlba van exportálva); a felhasználó szerepének megjelölését, akinek hozzáférése van ehhez az oldalhoz, valamint a navigáció beállításait az oldalsávhoz.
A lap működéséért felelős komponensben meg kell adnunk a templateUrl-t, átadva az html-fájl útvonalát a kinézethez. A kontrollerben, a dependency injection révén, hozzáférhetünk 2 fontos angular-szolgáltatáshoz:
- backendSrv — a Grafana api-szerverével való interakciót biztosító szolgáltatás;
- datasourceSrv — a Grafana-nál telepített összes datasource helyi interakcióját biztosító szolgáltatás (például a .getAll() módszer — visszaadja az összes telepített datasource listáját; .get() — visszaadja a konkrét datasource objektum példányát.



4. rész: datasource
Grafana szempontjából a datasource pontosan olyan plugint képvisel, mint a többi: van egy entry point-ja module.js, valamint egy plugin.json fájl metaadatokkal. App típusú plugin fejlesztésekor kölcsönhatásba léphetünk meglévő datasource-okkal (például prometheus-datasource), illetve saját magunk által létrehozottakkal is, amelyeket közvetlenül a plugin könyvtárában (dist/datasource/*) tárolhatunk vagy mint függőséget telepíthetünk. A mi esetünkben a datasource együtt érkezik a plugin kódjával. Ezenkívül kötelező a config.html sablon megléte, és a ConfigCtrl vezérlő, amelyek a datasource példányának konfigurálására és a Datasource vezérlő logikájának megvalósítására szolgálnak.
A KubeGraf pluginban, a felhasználói felület szempontjából a datasource egy kubernetes klaszter példányát jelenti, amely a következő funkciókat valósítja meg (a forráskód elérhető ):
- adatok beszerzése a k8s api-serveréből (namespace-ok, deployment-ek listájának lekérése…)
- kérések proxizálása a prometheus-datasource felé (amely minden egyes klaszter esetében a plugin beállításainál választható) és a válaszok formázása statikus oldalak és műszerfalak használatához.
- adatok frissítése a plugin statikus oldalaiban (meghatározott frissítési idővel).
- kérések kezelése a template lista grafana-dashboards formálásához (a .metriFindQuery() metódus).



- kapcsolat tesztelése a cél k8s klaszterrel.
testDatasource(){
let url = '/api/v1/namespaces';
let _url = this.url;
if(this.accessViaToken)
_url += '/__proxy';
_url += url;
return this.backendSrv.datasourceRequest({
url: _url,
method: "GET",
headers: {"Content-Type": 'application/json'}
})
.then(response => {
if (response.status === 200) {
return {status: "success", message: "A data source rendben van", title: "Siker"};
}else{
return {status: "error", message: "A data source nem rendben van", title: "Hiba"};
}
}, error => {
return {status: "error", message: "A data source nem rendben van", title: "Hiba"};
})
}Érdekes szempont, hogy szerintünk hogyan valósul meg az adatforrások hitelesítési és engedélyezési mechanizmusa. Általában a végső adatforráshoz való hozzáférés konfigurálásához a Grafana beépített komponensét, a datasourceHttpSettings-t használhatjuk. Ezzel a komponenssel beállíthatjuk a http-adatforráshoz való hozzáférést, megadva az URL-t és az alapvető hitelesítési/engedélyezési beállításokat: felhasználónév-jelszó, vagy client-cert/client-key. A bearer-token használatának beállításához (de facto szabvány a k8s-hez) kissé „kreatívnak” kellett lennünk.
E feladat megoldásához használhatjuk a Grafana beépített „Plugin Routes” mechanizmusát (további részletek a ). Az adatforrásunk beállításaiban deklarálhatunk egy szabályok halmazát, amelyeket a grafana proxy-szerver kezel. Például minden egyes végpont esetében lehetőség van fejléc vagy URL megadására, amelyek sablonozhatók, és az ezekhez szükséges adatok jsonData és secureJsonData mezőkből származhatnak (jelszavak vagy tokenek titkos tárolására). Példánkban az ilyen típusú kérések /__proxy/api/v1/namespaces át lesznek irányítva egy ilyen URL-re
/api/v1/namespaces segítségével, az Authorization: Bearer fejléc megadásával.


Természetesen a k8s API-szerverével való működéshez szükségünk van egy readonly hozzáféréssel rendelkező felhasználóra, amelynek létrehozásához szükséges manifeszt fájlokat szintén megtalálhatja a .
5. rész: kiadás

Miután megírta a saját Grafana pluginját, természetesen szeretné közzétenni nyílt forráskódúként. A Grafana plugin könyvtára elérhető a
oldalon. Ahhoz, hogy a pluginnak a hivatalos boltban elérhetőnek kell lennie, PR-t kell tennie a , hozzáadva a repo.json fájlhoz az alábbi formátumú tartalmat:

ahol a version a plugin verzióját, az url a repository linkjét, a commit pedig a commit hash-jét jelenti, amelyen az adott verzió elérhető.
A végén egy csodás képet fog látni, mint

Az adatok automatikusan a Readme.md, Changelog.md és a plugin.json fájlban található leírásból fognak származni.
6. rész: a következtetések helyett
A kiadás után sem hagytuk abba a pluginunk fejlesztését. Jelenleg is azon dolgozunk, hogy helyesen nyomon követhessük a klaszter csomópontjainak erőforrás-használatát, új funkciókat vezessünk be a felhasználói élmény javítása érdekében, valamint kezeljük a plugin telepítése után beérkezett rengeteg visszajelzést, melyet ügyfeleinktől és a GitHubon található issues-októl kaptunk (ha hagysz egy issue-t vagy pull requestet, nagyon örülnék 🙂 ).
Reméljük, hogy ez a cikk segít megérteni ezt a csodálatos eszközt, mint a Grafana, és lehet, hogy saját pluginodat is meg tudod írni.
Köszönjük!)
Forrás: habr.com
