Përshëndetje të gjithëve! Disa muaj më parë ne lançuam në prodhim projektin tonë të ri open-source — plugin-in Grafana për monitorimin e Kubernetes, të cilin e quajtëm . Kodi burimor i plugin-it është në dispozicion në . Në këtë artikull ne duam të ndajmë me ju historinë e mënyrës se si e krijuam plugin-in, cilat mjete përdorëm dhe me cilat vështirësi u përballëm gjatë zhvillimit. Le të fillojmë!
Pjesa 0 — hyrje: si e arritëm deri këtu?
Ideja për të shkruar plugin-in tonë për Grafanën lindi krejt rastësisht. Kompania jonë merret me monitorimin e projekteve web për më shumë se 10 vjet. Gjatë kësaj kohe ne kemi fituar një bagazh të madh ekspertize, rastesh interesante, dhe përvojash në përdorimin e sistemeve të ndryshme të monitorimit. Ndërsa një moment ne na erdhi në mendje pyetja: "A ekziston ndonjë mjet magjik për monitorimin e Kubernetes-it, që, siç thuhet, 'e vendos dhe harro'"? Standardi industrial për monitorimin e k8s, natyrisht, është bashkimi Prometheus + Grafana. Dhe për zgjidhjet e gatshme për këtë stack ekziston një grup i madh mjetesh të ndryshme: prometheus-operator, grup dashboard-esh kubernetes-mixin, aplikacioni grafana-kubernetes.
Opsioni më interesant për ne dukej të ishte plugin-i grafana-kubernetes-app, por ai nuk është mbështetur për më shumë se një vit dhe, përveç kësaj, nuk punon me versionet e reja të node-exporter dhe kube-state-metrics. Ndërsa një moment vendosëm: "A nuk do ta bënim ne zgjidhjen tonë?"
Cilat ide vendosëm të realizojmë në plugin-in tonë:
- vizualizimi i 'hartës së aplikacionit': përfaqësim i përshtatshëm i aplikacioneve në kluster, të grupuara sipas namespace-ve, deployment-eve…;
- vizualizimi i lidhjeve të tipit 'deployment — shërbim (+ports)'.
- vizualizimi i shpërndarjes së aplikacioneve të klusterit sipas nod-eve të klusterit.
- mbledhja e metrikave dhe informacionit nga disa burime: Prometheus dhe serveri i API të k8s.
- monitorimi i pjesës infrastrukturore (përdorimi i kohës së procesorit, memories, sistemit disk, rrjetit), si dhe logjikës së aplikacioneve — statusi i shëndetit të pod-eve, numri i replikave të disponueshme, informacion mbi kalimin e testeve të liveness/readyness.
Pjesa 1: Çfarë është 'plugin për Grafana'?
Nga këndvështrimi teknik, një plugin për Grafana është një kontrollues angular që ruhet në direktorinë data të Grafanës (/var/grafana/plugins/<your_plugin_name>/dist/module.js) dhe mund të ngarkohet si një modul SystemJS. Gjithashtu, në këtë direktor duhet të jetë një skedar plugin.json, që përmban të gjitha metainformacionet për plugin-in tuaj: emri, versioni, tipi i plugin-it, lidhjet me depot/sitë/licencë, varësitë dhe kështu me radhë.

module.ts

plugin.json
Siç shihet në foto, ne kemi caktuar plugin.type = app. Sepse plugin-et për Grafana mund të jenë të tre llojeve:
panel: tipi më i zakonshëm i plugin-eve — përfaqëson një panel për vizualizimin e disa metrikave, përdoret për ndërtimin e disa dashboard-eve të ndryshme.
datasource: plugin-connector në një burim të dhënash (për shembull, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
app: plugin që ju lejon të ndërtoni aplikacionin tuaj të frontend-it brenda Grafana, të krijoni faqet tuaja html dhe të bëni kërkesa manuale në datasource për vizualizimin e disa të dhënave të ndryshme. Gjithashtu, si varësi mund të përdoren plugin-e të lloje të tjera (datasource, panel) dhe dashboard-e të ndryshme.

Shembulli i varësive të plugin-it me type = app.
Si gjuhë programimi mund të përdoret si JavaScript, ashtu edhe TypeScript (ne e kemi zgjedhur atë). Skellet për plugin-e hello-world të çdo lloji mund të : në këtë depo paraqitet një numër i madh starter-pack’ash (madje ka edhe një shembull eksperimental plugin-i në React) me ndërtues të parainstaluar dhe të konfiguruar.
Pjesa 2: përgatitja e mjedisit lokal
Për të punuar në plugin, natyrisht, na nevojitet një grup kubernetes me të gjitha mjete të parainstaluara: prometheus, node-exporter, kube-state-metrics, grafana. Mjedisi duhet të konfigurohet shpejt, lehtësisht dhe pa probleme, dhe për të siguruar hot-reload, директoria e të dhënave të Grafana duhet të montohet përmes kompjuterit të zhvilluesit.
Më i rehatshmi, sipas mendimit tonë, është . Hapi tjetër është të instalohet lidhja Prometheus + Grafana me anë të prometheus-operator. Në përshkruhet në detaje procesi i instalimit të prometheus-operator në minikube. Për të aktivizuar persistencën, duhet të vendosni parametrin persistence: true në skedarin charts/grafana/values.yaml, shtoni PV dhe PVC tuaj të vetëdijshëm dhe tregoni ato në parametrin persistence.existingClaim
Skema përfundimtare e nisjes së minikube duket kështu:
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.LPjesa 3: zhvillimi i drejtpërdrejtë
Modeli i Objektit
Si përgatitje për implementimin e plugin-it, ne vendosëm të përshkruajmë të gjitha entitetet bazë të Kubernetes me të cilat do të punojmë në formën e klasave TypeScript: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Secila nga këto klasa trashëgon nga klasa e përbashkët BaseModel, e cila përshkruan konstruktorin, destruktorin dhe metodat për përditësimin dhe ndryshimin e dukshmërisë. Në secilën nga klasat përshkruhen marrëdhëniet e ngulitura me entitete të tjera, për shembull, lista e pod-eve për entitetin e tipit 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 = [];
}
}Me anë të getter’ave dhe setter’ave, ne mund të nxjerrim ose vendosim metrikat e nevojshme të entiteteve në një format të përshtatshëm dhe të lexueshëm. Për shembull, output-i i formatizuar i allocatable cpu të nodës:
get cpuAllocatableFormatted(){
let cpu = this.data.status.allocatable.cpu;
if(cpu.indexOf('m') > -1){
cpu = parseInt(cpu)/1000;
}
return cpu;
}Faqet
Lista e të gjitha faqeve të plugin-it tonë përshkruhet fillimisht në pluing.json në seksionin e varësive:

Në bllokun për secilën faqe, ne duhet të specifikojmë EMRIN E FAQES (ky do të konvertohet më pas në slug, me të cilin do të jetë e accesueshme kjo faqe); emrin e komponentit, i cili është përgjegjës për funksionimin e kësaj faqe (lista e komponentëve eksporton në module.ts); përcaktimin e rolit të përdoruesit, për të cilin është e aksesuar puna me këtë faqe dhe konfigurimet e navigimit për panelin anësor.
Në komponentin që është përgjegjës për funksionimin e faqes, ne duhet të vendosim templateUrl, duke kaluar aty rrugën deri në skedarin html me markup. Brenda kontrolluesit, përmes injeksionit të varësive, ne mund të kemi qasje në 2 shërbime të rëndësishme të angular:
- backendSrv — shërbimi që siguron ndërveprimin me serverin api të Grafana;
- datasourceSrv — shërbimi që siguron ndërveprimin lokal me të gjitha datasource-t që janë instaluar në Grafana tuaj (për shembull, metoda .getAll() — kthen një listë të të gjitha datasource-ve të instaluara; .get() — kthen objektin-instancën e një datasource-i të caktuar.



Pjesa 4: datasource
Sipas Grafana, një burim të dhënash është i njëjtë si çdo plugin tjetër: ai ka hyrjen e tij module.js, ka një skedë me metainformata plugin.json. Kur zhvillojmë një plugin me tipin = app, mund të interaktojmë me burime ekzistuese të dhënash (p.sh. prometheus-datasource) si dhe me të tuat, të cilat mund t'i mbajmë direkt në direktorinë e plugin-it (dist/datasource/*) ose t'i installojmë si varësi. Në rastin tonë, burimi i të dhënave vjen së bashku me kodin e plugin-it. Gjithashtu, është e domosdoshme që të kemi një model config.html dhe kontrolluesin ConfigCtrl, të cilat do të përdoren për faqen e konfigurimit të instancës së burimit të të dhënave dhe kontrolluesin e Burimit të të Dhënave, në të cilin implementohet logjika e funksionimit të burimit të dhënave.
Në plugin-in KubeGraf, nga pikëpamja e ndërfaqes së përdoruesit, burimi i të dhënave përfaqëson një instancë të klasterit kubernetes, në të cilin janë implementuar funksionalitetet e mëposhtme (kodin burimor e ka në dispozicion ):
- marrja e të dhënave nga api-server i k8s (marrja e listës së namespace-ve, deploymenteve…)
- proksimi i kërkesave për burimin e të dhënave prometheus (i zgjedhur në konfigurimet e plugin-it për çdo klaster specifik) dhe formatimi i përgjigjeve për përdorimin e të dhënave si në faqet statike ashtu edhe në panelët e kontrollit.
- përditësimi i të dhënave në faqet statike të plugin-it (me një kohë të caktuar refresh rate).
- përpunimi i kërkesave për formimin e listës së templates në grafana-dashboards (metoda .metriFindQuery())



- testimi i lidhjes me klasterin përfundimtar k8s.
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: "Burimi i të dhënave është OK", title: "Sukses"};
}else{
return {status: "error", message: "Burimi i të dhënave nuk është OK", title: "Gabim"};
}
}, error => {
return {status: "error", message: "Burimi i të dhënave nuk është OK", title: "Gabim"};
})
}Një moment interesant, sipas mendimit tonë, është implementimi i mekanizmit të autentifikimit dhe autorizimit për datasource. Zakonisht, nga kutia, për konfigurimin e aksesit në burimin e fundit të të dhënave, mund të përdorim komponentin e integruar të Grafana — datasourceHttpSettings. Me këtë komponent mund të konfigurojmë qasjen në burimin e të dhënave http, duke specifikuar url dhe parametrat bazë të autentifikimit/ autorizimit: emri i përdoruesit - fjalëkalimi, ose client-cert/client-key. Për të realizuar mundësinë e konfigurimit të qasjes me tokenin bearer (standard de facto për k8s), duhej të bëhej pak "kimistrie".
Për zgjidhjen e kësaj çështjeje mund të përdorim mekanizmin e integruar të Grafana "Plugin Routes" (më shumë në ). Në cilësimet e datasource-it tonë mund të shpallim një grup rregullash rruge, të cilat do të përpunohen nga serveri proxy i grafana. Për shembull, për çdo endpoint të veçantë ekziston mundësia e vendosjes së kokave ose url me mundësinë e templating, të dhënat për të cilat mund të merren nga fushat jsonData dhe secureJsonData (për ruajtjen e fjalëkalimeve ose tokeneve në formë të shkruar). Në shembullin tonë, kërkesat si /__proxy/api/v1/namespaces do të proksohen në url si
/api/v1/namespaces me vendosjen e kokës Authorization: Bearer.


Natyrisht, për të punuar me serverin api të k8s, na nevojitet një përdorues me akses vetëm për lexim, manifestet për krijimin e të cilit mund t'i gjeni gjithashtu në .
Pjesa 5: lansohet

Pasi të shkruani plugin-in tuaj për Grafana, natyrisht do të dëshironit ta publikoni atë në mënyrë të hapur. Në Grafana ka një bibliotekë plugins që është e aksesueshme në lidhjen
Për ta bërë plugin-in tuaj të aksesueshëm në dyqanin zyrtar, duhet të bëni PR në , duke shtuar në skedarin repo.json përmbajtjen si kjo:

ku version — është versioni i plugin-it tuaj, url — lidhja për depo, dhe commit — hash i commit-it, me të cilin do të jetë e aksesueshme versioni specifike e plugin-it.
Dhe në fund do të shihni një pamje të mrekullueshme si kjo:

Të dhënat për të do të dihen automatikisht nga Readme.md, Changelog.md dhe skedari plugin.json që përshkruan plugin-in.
Pjesa 6: në vend të përfundimeve
Ne e kemi ndaluar zhvillimin e plugin-it tonë pas lançimit. Aktualisht po punojmë për monitorimin e saktë të përdorimit të burimeve të nyjave të klasterit, implementimin e veçorive të reja për të përmirësuar përvojën e përdoruesit, si dhe po shqyrtojmë një sasi të madhe të reagimeve që kemi marrë pas instalimeve të plugin-it nga klientët tanë, si dhe nga çështjet e raportuara në GitHub (nëse lini një çështje ose një kërkesë tërheqjeje, do të isha shumë i lumtur 🙂 ).
Shpresojmë që ky artikull t'ju ndihmojë të kuptoni një mjet kaq të mrekullueshëm si Grafana dhe, ndoshta, të shkruani plugin-in tuaj të vet.
Faleminderit!)
Burimi: habr.com
