Pozdrav svima! Prije nekoliko mjeseci pokrenuli smo naš novi open-source projekt u produkciji — Grafana dodatak za praćenje kubernetes-a, koji smo nazvali . Izvorni kod dodatka dostupan je u . U ovom članku želimo podijeliti s vama priču o tome kako smo razvijali dodatak, koje smo alate koristili i s kakvim se izazovima suočili tijekom razvoja. Krenimo!
Dio 0 — uvod: kako smo do ovog došli?
Ideja da napišemo vlastiti dodatak za Grafanu pojavila se sasvim slučajno. Naša tvrtka već više od 10 godina bavi se praćenjem web-projekata različite složenosti. Tijekom tog vremena stekli smo veliko iskustvo, zanimljive slučajeve i iskustvo korištenja raznih sustava za praćenje. U nekom trenutku postavili smo si pitanje: "Postoji li čarobni alat za praćenje Kubernetes-a, koji se može 'postaviti i zaboraviti'?" Prometni standard za praćenje k8s, naravno, odavno je kombinacija Prometheus + Grafana. Za ovaj stakl postoji veliki broj različitih alata: prometheus-operator, set nadzornih ploča kubernetes-mixin, grafana-kubernetes-app.
Najinteresantnija opcija za nas činilo se da je dodatak grafana-kubernetes-app, no on se ne podržava više od godinu dana i, uz to, ne može raditi s novim verzijama node-exportera i kube-state-metrics-a. U nekom trenutku odlučili smo: "Zašto ne bismo napravili vlastito rješenje?"
Koje smo ideje odlučili realizirati u vlastitom dodatku:
- vizualizacija 'karta aplikacije': prikladno prikazivanje aplikacija u klasteru, grupiranih prema namespace-ima, deployment-ima…;
- vizualizacija odnosa tipa 'deployment — service (+ports)'.
- vizualizacija raspodjele aplikacija klastera po nodovima klastera.
- prikupljanje metrika i informacija iz više izvora: Prometheus i k8s api server.
- praćenje infrastrukturnog dijela (korištenje procesorskog vremena, memorije, diskovnog sustava, mreže), kao i logike aplikacija — health-status pod-ova, broj dostupnih replika, informacije o prolasku liveness/readyness probiranja.
Dio 1: Što je 'dodatak za Grafana'?
S tehničke točke gledišta, dodatak za Grafanu je angular-kontroler, koji se pohranjuje u data-direktoriju Grafane (/var/grafana/plugins/<your_plugin_name>/dist/module.js) i može biti učitan kao SystemJS modul. Također, u ovoj direktoj mora se nalaziti datoteka plugin.json koja sadrži sve metapodatke o vašem pluginu: naziv, verzija, tip plugina, linkovi na repozitorij/web stranicu/licencu, ovisnosti i tako dalje.

module.ts

plugin.json
Kao što je prikazano na snimci, postavili smo plugin.type = app. Budući da mogu postojati tri vrste plugina za Grafanu:
panel: najčešći tip plugina — predstavlja panel za vizualizaciju raznih metrika, koristi se za izradu različitih nadzornih ploča.
datasource: plugin-konektor za neki izvor podataka (na primjer, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
app: plugin koji vam omogućuje da izradite vlastitu frontend aplikaciju unutar Grafane, stvarate vlastite HTML stranice i ručno se obraćate datasource-u za vizualizaciju raznih podataka. Također, kao ovisnosti mogu se koristiti pluginovi drugih tipova (datasource, panel) i različite nadzorne ploče.

Primjer ovisnosti plugina s type = app.
Kao programski jezik možete koristiti i JavaScript i TypeScript (mi smo odabrali njega). Predloške za hello-world pluginove bilo koje vrste možete : u ovom repozitoriju nalazi se veliki broj starter-packova (čak postoji i eksperimentalni primjer plugina na Reactu) s unaprijed instaliranim i konfiguriranim alatima.
Dio 2: priprema lokalnog okruženja
Za rad na pluginu, naravno, trebat će nam Kubernetes klaster sa svim unaprijed instaliranim alatima: prometheus, node-exporter, kube-state-metrics, grafana. Okruženje bi se trebalo postaviti brzo, lako i neformalno, a za osiguranje hot-reload data-direktorij Grafane trebao bi se montirati direktno s računala programera.
Najprikladniji način lokalnog rada s Kubernetesom je . Sljedeći korak je instalirati vezu Prometheus + Grafana putem prometheus-operatora. U detaljno je opisan proces instalacije prometheus-operatora na minikube. Za uključivanje trajnosti potrebno je postaviti parametar persistence: true u datoteci charts/grafana/values.yaml, dodati svoj vlastiti PV i PVC i navesti ih u parametru persistence.existingClaim
Konačni skript za pokretanje minikubea izgleda ovako:
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.LDio 3: razvoj
Objektni model
Kao pripremu za implementaciju dodatka odlučili smo opisati sve osnovne entitete Kubernetes-a s kojima ćemo raditi u obliku TypeScript klasa: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Svaka od ovih klasa nasljeđuje zajedničku klasu BaseModel, koja opisuje konstruktor, destruktor, metode za ažuriranje i prebacivanje vidljivosti. U svakoj od klasa su opisane ugniježdene veze s drugim entitetima, na primjer, popis podova unutar entiteta tipa deployment.
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 = [];
}
}Pomoću getter-a i setter-a možemo prikazivati ili postavljati potrebne nam metrike entiteta na prikladan i čitljiv način. Primjer formatiranog izlaza allocatable cpu nod-e:
get cpuAllocatableFormatted(){
let cpu = this.data.status.allocatable.cpu;
if(cpu.indexOf('m') > -1){
cpu = parseInt(cpu)/1000;
}
return cpu;
}Stranice
Popis svih stranica našeg dodatka prvotno se opisuje u našem pluing.json u odjeljku sa zavisnostima:

U bloku za svaku stranicu moramo navesti NAZIV STRANICE (koji će potom biti konvertiran u slug pod kojim će stranica biti dostupna); naziv komponente koja je odgovorna za rad s ovom stranicom (popis komponenti izvozi se u module.ts); označavanje uloge korisnika kojoj je dostupno raditi s ovom stranicom i postavke navigacije za bočnu traku.
U komponenti koja je odgovorna za rad sa stranicom moramo postaviti templateUrl, prenoseći tamo putanju do html datoteke s markupom. Unutar kontrolera, putem dependency injection-a, možemo dobiti pristup do 2 važna angular servisa:
- backendSrv — servis koji omogućava interakciju s api-serverom Grafane;
- datasourceSrv — servis koji omogućava lokalnu interakciju sa svim izvorima podataka instaliranim u vašoj Grafani (na primjer, metoda .getAll() — vraća popis svih instaliranih izvora podataka; .get() — vraća objekt-instanicu konkretnog izvora podataka.



Dio 4: izvor podataka
Prema Grafana, datasource je plugin poput svih ostalih: ima svoju ulaznu točku module.js i datoteku s metainformacijama plugin.json. Kada razvijamo plugin tipa app, možemo se povezati s postojećim datasourceima (na primjer, prometheus-datasource) ili s vlastitim koji možemo pohraniti izravno u direktorij plugina (dist/datasource/*) ili instalirati kao ovisnost. U našem slučaju, datasource dolazi zajedno s kodom plugina. Također je obavezno imati predložak config.html i kontroler ConfigCtrl, koji će se koristiti za stranicu konfiguracije instance datasourcea i kontrolera Datasource, u kojem se implementira logika rada vašeg datasourcea.
U pluginu KubeGraf, iz perspektive korisničkog sučelja, datasource predstavlja instancu kubernetes-klastera, koja ima sljedeće mogućnosti (izvorni kod je dostupan ):
- prikupljanje podataka iz api-servera k8s (dohvaćanje popisa namespacea, deploymenta…)
- proksiranje zahtjeva u prometheus-datasource (koji se odabire u postavkama plugina za svaki konkretni klaster) i formatiranje odgovora za upotrebu podataka kako na statičnim stranicama, tako i na nadzornim pločama.
- ažuriranje podataka na statičnim stranicama plugina (s postavljenim vremenom osvježavanja).
- obrada zahtjeva za generiranje popisa predložaka u grafana-dashboards (metoda .metriFindQuery())



- testiranje veze s konačnim k8s-klasterom.
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: "Izvor podataka je u redu", title: "Uspjeh"};
}else{
return {status: "error", message: "Izvor podataka nije u redu", title: "Greška"};
}
}, error => {
return {status: "error", message: "Izvor podataka nije u redu", title: "Greška"};
})
}Jedan zanimljiv aspekt, prema našem mišljenju, je implementacija mehanizma autentifikacije i autorizacije za datasource. Obično, iz kutije za konfiguraciju pristupa krajnjem izvoru podataka možemo koristiti ugrađenu komponentu Grafana — datasourceHttpSettings. Pomoću ove komponente možemo konfigurirati pristup http-izvoru podataka, navodeći URL i osnovne postavke autentifikacije/oznake: korisničko ime lozinka, ili client-cert/client-key. Kako bismo omogućili konfiguraciju pristupa putem bearer-tokena (de facto standard za k8s), trebalo je malo „zakuhati“.
Za rješavanje ovog zadatka može se koristiti ugrađeni mehanizam Grafana „Plugin Routes“ (više na ). U postavkama našeg datasource-a možemo deklarirati skup pravila usmjeravanja koja će obraditi proxy poslužitelj grafana. Na primjer, za svaki pojedini endpoint postoji mogućnost postavljanja zaglavlja ili URL-a s mogućnošću templatinga, a podaci za koje se mogu uzeti iz polja jsonData i secureJsonData (za pohranu lozinki ili tokena u šifriranom obliku). U našem primjeru, zahtjevi poput /__proxy/api/v1/namespaces bit će proksirani na URL poput
/api/v1/namespaces s postavljenim zaglavljem Authorization: Bearer.


Naravno, za rad s api-poslužiteljem k8s potreban nam je korisnik s readonly pristupima, a manifesti za njegovo kreiranje također se mogu pronaći u .
Dio 5: izdanje

Nakon što napišete vlastiti plugin za Grafanu, naravno, poželjet ćete ga objaviti kao otvoreni izvor. U Grafani postoji biblioteka pluginova koja je dostupna na linku
Kako bi vaš plugin bio dostupan u službenoj trgovini, potrebno je napraviti PR u , dodajući u datoteku repo.json sadržaj oblika:

gdje je version — verzija vašeg plugina, url — link na repozitorij, a commit — hash commit-a koji će omogućiti specifičnu verziju plugina.
I na izlazu ćete vidjeti prekrasnu sliku oblika:

Podaci za nju će se automatski izvući iz vašeg Readme.md, Changelog.md i datoteke plugin.json s opisom plugina.
Dio 6: umjesto zaključaka
Nismo prekinuli razvoj našeg dodatka nakon objave. Trenutno radimo na pravilnom praćenju upotrebe resursa nodova klastera, implementaciji novih funkcionalnosti za poboljšanje korisničkog iskustva, kao i na rješavanju velikog broja povratnih informacija koje smo dobili nakon instalacije dodatka od naših klijenata, kao i iz prijava na GitHubu (ako ostavite svoj issue ili pull request, bit ću vrlo sretan 🙂 ).
Nadamo se da će vam ovaj članak pomoći da se upoznate s ovim prekrasnim alatom kao što je Grafana i možda napisati vlastiti dodatak.
Hvala!)
Izvor: habr.com
