Sziasztok! Néhány hónappal ezelőtt elindítottuk az új nyílt forráskódú projektünket a termelésben - a kubernetes figyelésére szolgáló Grafana bővítményt, amelyet elhívtunk. . A beépülő modul forráskódja a következő címen érhető el . Ebben a cikkben pedig szeretnénk megosztani veletek a bővítmény létrehozásának történetét, milyen eszközöket használtunk, és milyen buktatókkal találkoztunk a fejlesztési folyamat során. Gyerünk!
0. rész - bevezető: hogyan jutottunk el idáig?
Egészen véletlenül támadt bennünk az ötlet, hogy írjunk saját bővítményt a Grafan számára. Cégünk több mint 10 éve figyeli a különböző bonyolultságú webprojekteket. Ezalatt az idő alatt nagy mennyiségű szakértelmet, érdekes eseteket, tapasztalatokat halmoztunk fel a különböző monitoring rendszerek használatában. És egy ponton feltettük magunknak a kérdést: „Van valami varázseszköz a Kubernetes figyelésére, hogy – ahogy mondani szokás – „állítsd be és felejtsd el”?”. A k8-ak figyelésének iparági szabványa természetesen régóta a Prometheus + Grafana kombináció. És kész megoldásként ehhez a veremhez számos különféle eszköz található: prometheus-operator, kubernetes-mixin irányítópultok, grafana-kubernetes-app.
Számunkra a grafana-kubernetes-app plugin tűnt a legérdekesebb lehetőségnek, de már több mint egy éve nem támogatott, ráadásul nem működik a node-exporter és a kube-state-metrics új verzióival. És valamikor úgy döntöttünk: „Nem kellene magunk döntenünk?”
Milyen ötleteket határoztunk meg a bővítményünkben:
- az „alkalmazástérkép” megjelenítése: az alkalmazások kényelmes bemutatása a fürtben, névterek, telepítések szerint csoportosítva...;
- kapcsolatok megjelenítése, mint például a „telepítés - szolgáltatás (+portok)”.
- a fürt alkalmazások fürtcsomópontok közötti eloszlásának megjelenítése.
- metrikák és információk gyűjteménye több forrásból: Prometheus és k8s api szerver.
- mind az infrastrukturális rész (CPU-idő, memória, lemez-alrendszer, hálózat) és alkalmazáslogika monitorozása - állapotjelző pod-ok, elérhető replikák száma, életképességi/készenléti tesztek teljesítésével kapcsolatos információk.
1. rész: Mi az a „Grafana plugin”?
Technikai szempontból a Grafana beépülő modulja egy szögvezérlő, amely a Grafana adatkönyvtárában (/var/grafana/plugins/ /dist/module.js), és SystemJS modulként tölthető be. Szintén ebben a könyvtárban kell lennie egy plugin.json fájlnak, amely tartalmazza a beépülő modul összes metainformációját: név, verzió, beépülő modul típusa, hivatkozások a tárhelyre/webhelyre/licencre, függőségek és így tovább.

modul.ts

plugin.json
Amint a képernyőképen látható, a plugin.type = app-ot adtuk meg. Mivel a Grafana beépülő moduljai háromféleek lehetnek:
panel: a legelterjedtebb beépülő modul - ez egy panel bármilyen mérőszám megjelenítésére, amelyet különféle irányítópultok készítésére használnak.
adatforrás: plugin csatlakozó valamilyen adatforráshoz (például Prometheus-adatforrás, ClickHouse-adatforrás, ElasticSearch-adatforrás).
app: Beépülő modul, amely lehetővé teszi saját frontend alkalmazás létrehozását a Grafana belsejében, saját html-oldalak létrehozását, valamint az adatforrás kézi elérését különféle adatok megjelenítéséhez. Ezenkívül más típusú bővítmények (adatforrás, panel) és különféle irányítópultok is használhatók függőségekként.

Példa beépülő modul-függőségekre a type=app paraméterrel.
Programozási nyelvként használhatja a JavaScriptet és a TypeScriptet is (ezt választottuk). Előkészületek bármilyen típusú hello-world bővítményhez : ez a tároló nagyszámú kezdőcsomagot tartalmaz (még a Reactban van egy kísérleti példa is egy bővítményre) előre telepített és konfigurált építőkkel.
2. rész: a helyi környezet előkészítése
A bővítményen való munkához természetesen szükségünk van egy kubernetes-fürtre az összes előre telepített eszközzel: prometheus, node-exporter, kube-state-metrics, grafana. A környezetet gyorsan, egyszerűen és természetesen kell beállítani, és a hot-reload biztosításához a Grafana adatkönyvtárat közvetlenül a fejlesztő gépéről kell felcsatolni.
Véleményünk szerint a legkényelmesebb módja a kubernetes helyi együttműködésének . A következő lépés a Prometheus + Grafana kombináció telepítése a prometheus-operator segítségével. BAN BEN A prometheus-operator minikube-ra történő telepítésének folyamata részletesen le van írva. A perzisztencia engedélyezéséhez be kell állítani a paramétert kitartás: igaz a charts/grafana/values.yaml fájlban adja hozzá saját PV-jét és PVC-jét, és adja meg őket a persistence.existingClaim paraméterben
A végső minikube indító szkriptünk így 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: tényleges fejlesztés
Objektummodell
A beépülő modul megvalósításának előkészítéseként úgy döntöttünk, hogy TypeScript osztályok formájában leírjuk az összes alapvető Kubernetes entitást, amellyel dolgozni fogunk: pod, telepítés, démonset, állapotkészlet, feladat, cronjob, szolgáltatás, csomópont, névtér. Ezen osztályok mindegyike a közös BaseModel osztályból örökli, amely leírja a konstruktort, a destruktort, a láthatóság frissítésének és váltásának metódusait. Az egyes osztályok beágyazott kapcsolatokat írnak le más entitásokkal, például egy telepítési típusú entitás pod-listáját.
import {Pod} from "./pod";
import {Service} from "./service";
import {BaseModel} from './traits/baseModel';
export class Deployment extends BaseModel{
pods: Array<Pod>;
services: Array<Service>;
constructor(data: any){
super(data);
this.pods = [];
this.services = [];
}
}A getterek és setterek segítségével kényelmes és olvasható formában tudjuk megjeleníteni vagy beállítani a számunkra szükséges entitásmérőket. Például az allokálható CPU-csomópontok formázott kimenete:
get cpuAllocatableFormatted(){
let cpu = this.data.status.allocatable.cpu;
if(cpu.indexOf('m') > -1){
cpu = parseInt(cpu)/1000;
}
return cpu;
}Oldalak
Az összes beépülő modulunk listája először a pluing.json fájlban található a függőségek szakaszban:

Az egyes oldalak blokkjában meg kell jelölnünk az OLDAL NEVÉT (ezt ezután egy slug-vá alakítjuk, amely által ez az oldal elérhető lesz); az oldal működéséért felelős komponens neve (az összetevők listája a module.ts-be kerül exportálásra); jelzi a felhasználói szerepkört, amelyhez ez az oldal elérhető, és az oldalsáv navigációs beállításait.
Az oldal működéséért felelős komponensben be kell állítanunk a templateUrl-t, átadva ott a html fájl elérési útját jelöléssel. A vezérlőn belül a függőségi befecskendezéssel akár 2 fontos szögszolgáltatást is elérhetünk:
- backendSrv - olyan szolgáltatás, amely interakciót biztosít a Grafana API-kiszolgálóval;
- datasourceSrv – egy szolgáltatás, amely helyi interakciót biztosít a Grafana-ba telepített összes adatforrással (például a .getAll() metódus) – visszaadja az összes telepített adatforrás listáját; .get( ) - egy adott adatforrás példányobjektumát adja vissza.



4. rész: adatforrás
A Grafana szemszögéből az adatforrás pontosan ugyanaz a plugin, mint az összes többi: saját belépési pontja module.js, van egy fájl metainformációkkal plugin.json. A type = app bővítmény fejlesztésekor a meglévő adatforrásokkal (például prometheus-datasource) és a sajátunkkal is interakcióba léphetünk, amit közvetlenül a plugin könyvtárában (dist/datasource/*) tárolhatunk, vagy függőségként telepíthetünk. Esetünkben az adatforrás a beépülő modul kódjával érkezik. Szükséges továbbá egy config.html sablon és egy ConfigCtrl vezérlő, amely az adatforrás-példány konfigurációs oldalához lesz használva, valamint az adatforrás logikáját megvalósító Datasource vezérlő.
A KubeGraf beépülő modulban a felhasználói felület szempontjából az adatforrás egy kubernetes-fürt példánya, amely a következő képességeket valósítja meg (forráskód elérhető ):
- adatok gyűjtése a k8s api-szerverről (névterek, telepítések listájának lekérése...)
- proxy kérések a prometheus-datasource-hoz (amely az egyes fürtök beépülő modul-beállításaiban van kiválasztva), és a válaszok formázása az adatok statikus oldalakon és irányítópultokon történő használatához.
- adatok frissítése statikus bővítményoldalakon (beállított frissítési gyakorisággal).
- lekérdezések feldolgozása sablonlap létrehozásához grafana-dashboardokban (metriFindQuery() metódus)



- kapcsolati teszt a végső 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: "Data source is OK", title: "Success"};
}else{
return {status: "error", message: "Data source is not OK", title: "Error"};
}
}, error => {
return {status: "error", message: "Data source is not OK", title: "Error"};
})
}Külön érdekesség véleményünk szerint az adatforrás hitelesítési és engedélyezési mechanizmusának megvalósítása. Általában a beépített Grafana komponens datasourceHttpSettings segítségével konfigurálhatjuk a végső adatforráshoz való hozzáférést. Ezzel az összetevővel konfigurálhatjuk a hozzáférést a http adatforráshoz az url és az alapvető hitelesítési/engedélyezési beállítások megadásával: login-password vagy client-cert/client-key. Annak érdekében, hogy megvalósíthassuk a hozzáférést egy vivőjogkivonat (a k8s de facto szabványa) használatával konfigurálhatjuk, egy kis módosítást kellett végrehajtanunk.
A probléma megoldásához használhatja a Grafana beépített „Plugin Routes” mechanizmusát (további részletek: ). Adatforrásunk beállításaiban deklarálhatunk egy útválasztási szabálykészletet, amelyet a grafana proxyszerver dolgoz fel. Például minden egyes végponthoz lehetőség van sablonozási lehetőséggel fejlécek vagy url-ek beállítására, amelyekhez a jsonData és a secureJsonData mezőkből lehet adatokat venni (jelszavak vagy tokenek titkosított formában tárolásához). Példánkban az olyan lekérdezések, mint a /__proxy/api/v1/namespaces az űrlap url-jéhez kerül proxyként
/api/v8/namespaces az Authorization: Bearer fejléccel.


Természetesen a k8s api szerverrel való együttműködéshez csak olvasási hozzáféréssel rendelkező felhasználóra van szükségünk, amelynek létrehozásához szintén megtalálható a .
5. rész: kiadás

Miután megírta saját Grafana beépülő modulját, természetesen nyilvánosan elérhetővé kell tennie azt. A Grafanában ez az itt elérhető bővítmények könyvtára
Ahhoz, hogy a bővítmény elérhető legyen a hivatalos áruházban, PR-t kell készítenie ehhez hasonló tartalom hozzáadásával a repo.json fájlhoz:

ahol a verzió a beépülő modul verziója, az url a tárolóra mutató hivatkozás, a commit pedig annak a véglegesítésnek a hash-je, amelyhez a beépülő modul egy adott verziója elérhető lesz.
És a kimeneten egy csodálatos képet fog látni, például:

A hozzá tartozó adatokat a rendszer automatikusan lekéri a Readme.md, Changelog.md és a plugin.json fájlból a beépülő modul leírásával.
6. rész: következtetések helyett
A kiadás után sem hagytuk abba a bővítmény fejlesztését. Most pedig azon dolgozunk, hogy megfelelően figyeljük a fürtcsomópontok erőforrás-felhasználását, új funkciókat vezetünk be az UX javítása érdekében, és nagy mennyiségű visszajelzést is begyűjtünk a bővítmény telepítése után, mind az ügyfeleinktől, mind a GitHubon élőktől (ha kilép kérdésed vagy kérésed, nagyon boldog leszek :)
Reméljük, hogy ez a cikk segít megérteni egy ilyen csodálatos eszközt, mint a Grafana, és talán megírja saját bővítményét.
Kösz!)
Forrás: will.com
