Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Përshëndetje të gjithëve! Disa muaj më parë, lançuam projektin tonë të ri me burim të hapur, një plugin Grafana për monitorimin e Kubernetes, në prodhim. DevOpsProdigy KubeGrafKodi burimor i plugin-it është i disponueshëm në depo publike në GitHubNë këtë artikull, dëshirojmë të ndajmë me ju historinë se si e krijuam plugin-in, mjetet që përdorëm dhe grackat që hasëm gjatë zhvillimit. Le të fillojmë!

Pjesa 0 - Hyrje: Si arritëm deri këtu?

Ideja për të shkruar plugin-in tonë për Grafana na erdhi krejt rastësisht. Kompania jonë ka monitoruar projekte web me kompleksitet të ndryshëm për më shumë se 10 vjet. Gjatë kësaj kohe, kemi grumbulluar një mori ekspertize, studime rastesh interesante dhe përvojë duke përdorur sisteme të ndryshme monitorimi. Në një moment, pyetëm veten: "A ekziston ndonjë mjet magjik për monitorimin e Kubernetes që, siç thonë, mund ta 'vendosësh dhe ta harrosh'"? Natyrisht, kombinimi Prometheus + Grafana ka qenë prej kohësh standardi i industrisë për monitorimin e K8S. Ekziston një gamë e gjerë mjetesh të gatshme për këtë grumbull, duke përfshirë prometheus-operator, suitën e panelit kubernetes-mixin dhe grafana-kubernetes-app.

Shtojca grafana-kubernetes-app na dukej opsioni më interesant, por nuk është mbështetur për më shumë se një vit dhe, për më tepër, nuk funksionon me versionet e reja të node-exporter dhe kube-state-metrics. Në një moment, vendosëm, "Pse të mos krijojmë zgjidhjen tonë?"

Çfarë idesh vendosëm të zbatojmë në plugin-in tonë?

  • Vizualizimi i hartës së aplikacioneve: një përfaqësim i përshtatshëm i aplikacioneve në një klaster, të grupuara sipas hapësirave të emrave, vendosjeve, etj.;
  • vizualizimi i lidhjeve të tipit "zbatim - shërbim (+porte)".
  • vizualizimi i shpërndarjes së aplikacioneve të klasterit nëpër nyjet e klasterit.
  • Mbledhja e metrikave dhe informacionit nga burime të shumta: Prometheus dhe serveri API k8s.
  • Monitorimi si i infrastrukturës (përdorimi i kohës së CPU-së, memories, nënsistemit të diskut, rrjetit) ashtu edhe i logjikës së aplikacionit - gjendja shëndetësore e pod-eve, numri i replikave të disponueshme dhe informacioni në lidhje me progresin e testeve të gatishmërisë/aktivitetit.

Pjesa 1: Çfarë është një plugin Grafana?

Nga një këndvështrim teknik, një plugin për Grafana është një kontrollues këndor që ruhet në drejtorinë e të dhënave të Grafana (/var/grafana/plugins/ /dist/module.js) dhe mund të ngarkohet si një modul SystemJS. Kjo drejtori duhet të përmbajë gjithashtu një skedar plugin.json, i cili përmban të gjitha meta të dhënat rreth plugin-it tuaj: emrin, versionin, llojin e plugin-it, lidhjet e depos/faqes së internetit/licencës, varësitë e kështu me radhë.

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha
module.ts

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha
plugin.json

Siç mund ta shihni në pamjen e ekranit, ne specifikuam plugin.type = app. Kjo ndodh sepse ekzistojnë tre lloje plugin-esh për Grafana:

panel: lloji më i zakonshëm i plugin-it - është një panel për vizualizimin e metrikave të caktuara dhe përdoret për të ndërtuar panele të ndryshme.
burim të dhënash: një lidhës plugin për çdo burim të dhënash (për shembull, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
appNjë plugin që ju lejon të ndërtoni aplikacionin tuaj frontend brenda Grafana, të krijoni faqet tuaja HTML dhe të qaseni manualisht në burimin e të dhënave për të vizualizuar të dhëna të ndryshme. Lloje të tjera plugin-esh (burimi i të dhënave, paneli) dhe panele të ndryshme mund të përdoren gjithashtu si varësi.

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha
Shembull i varësive të plugin-eve me tipin = app.

Mund të përdorni JavaScript ose TypeScript si gjuhë programimi (ne zgjodhëm TypeScript). Mund të krijoni shabllone për çdo lloj plugin-i hello-world. gjej me anë të lidhjesKy depo përmban një numër të madh paketash fillestare (ekziston edhe një shembull eksperimental i një plugin-i React) me ndërtues të parainstaluar dhe të konfiguruar.

Pjesa 2: Përgatitja e Mjedisit Lokal

Për të punuar me plugin-in, natyrisht do të na duhet një klaster Kubernetes me të gjitha mjetet e parainstaluara: prometheus, node-exporter, kube-state-metrics dhe grafana. Mjedisi duhet të jetë i shpejtë, i lehtë dhe pa probleme për t'u konfiguruar, dhe për të siguruar ringarkimin e shpejtë, direktoria e të dhënave Grafana duhet të montohet direkt nga makina e zhvilluesit.

Sipas mendimit tonë, mënyra më e përshtatshme për të punuar lokalisht me Kubernetes është minikubeHapi tjetër është instalimi i paketës Prometheus + Grafana duke përdorur prometheus-operator. Ky artikull Procesi i instalimit të operatorit prometheus në minikube përshkruhet në detaje. Për të aktivizuar persistencën, duhet të vendosni parametrin këmbëngulje: e vërtetë Në skedarin charts/grafana/values.yaml, shtoni PV dhe PVC tuaj dhe specifikojini ato në parametrin persistence.existingClaim

Skripti ynë përfundimtar i lançimit të 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.L

Pjesa 3: Zhvillimi i drejtpërdrejtë

Modeli i objektit

Në përgatitje për zbatimin e plugin-it, vendosëm të përcaktojmë të gjitha entitetet bazë të Kubernetes me të cilat do të punojmë si klasa TypeScript: pod, deployment, daemonset, statefulset, job, cronjob, service, node dhe namespace. Secila prej këtyre klasave trashëgon nga një klasë e përbashkët BaseModel, e cila përcakton një konstruktor, një destruktor dhe metoda për përditësimin dhe çaktivizimin e dukshmërisë. Çdo klasë përcakton gjithashtu marrëdhënie të ndërthurura me entitete të tjera, të tilla si një listë pod-esh për një entitet vendosjeje.

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 = [];
   }
}

Duke përdorur marrës dhe përcaktues, ne mund të shfaqim ose vendosim metrikat e dëshiruara të entitetit në një format të përshtatshëm dhe të lexueshëm. Për shembull, rezultati i formatuar i nyjeve të alokueshme të CPU-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 tonë në seksionin e varësive:

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Në bllokun për secilën faqe, duhet të specifikojmë EMRIN E FAQES (ky më pas do të shndërrohet në një slug me anë të të cilit kjo faqe do të jetë e arritshme); emrin e komponentit përgjegjës për funksionimin e kësaj faqeje (lista e komponentëve eksportohet në module.ts); një tregues të rolit të përdoruesit për të cilin është e disponueshme puna me këtë faqe dhe cilësimet e navigimit për shiritin anësor.

Në komponentin përgjegjës për funksionimin e faqes, duhet të caktojmë templateUrl, duke i kaluar asaj rrugën për në skedarin HTML që përmban shënimin. Brenda kontrolluesit, përmes injektimit të varësisë, mund të hyjmë në dy shërbime të rëndësishme të Angular:

  • backendSrv është një shërbim që ofron ndërveprim me serverin Grafana API;
  • datasourceSrv është një shërbim që ofron ndërveprim lokal me të gjitha burimet e të dhënave të instaluara në Grafana-n tuaj (për shembull, metoda .getAll() kthen një listë të të gjitha burimeve të të dhënave të instaluara; .get( ) — kthen një objekt instance të një burimi të dhënash specifik.

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Pjesa 4: Burimi i të dhënave

Nga perspektiva e Grafanës, një burim të dhënash është një plugin njësoj si çdo tjetër: ai ka pikën e vet të hyrjes, module.js, dhe një skedar plugin.json me meta të dhëna. Kur zhvillojmë një plugin me llojin = app, ne mund të bashkëveprojmë me burimet ekzistuese të të dhënave (për shembull, prometheus-datasource) ose me tonat, të cilat mund t'i ruajmë direkt në direktorinë e plugin-it (dist/datasource/*) ose t'i instalojmë si një varësi. Në rastin tonë, burimi i të dhënave është i paketuar me kodin e plugin-it. Gjithashtu kërkohen një shabllon config.html dhe një kontrollues ConfigCtrl, i cili do të përdoret për faqen e konfigurimit të instancës së burimit të të dhënave dhe kontrolluesin Datasource, i cili zbaton logjikën për burimin tuaj të të dhënave.

Në shtojcën KubeGraf, nga një perspektivë e ndërfaqes së përdoruesit, një burim të dhënash është një instancë e një klasteri Kubernetes që zbaton aftësitë e mëposhtme (kodi burimor i disponueshëm) по ссылке):

  • marrja e të dhënave nga serveri k8s api (marrja e një liste të hapësirave të emrave, vendosjeve, etj.)
  • Kërkesat me proksi te prometheus-datasource (i cili zgjidhet në cilësimet e plugin-it për secilin klaster specifik) dhe formatimi i përgjigjeve për përdorimin e të dhënave si në faqet statike ashtu edhe në panelet e kontrollit.
  • përditësimi i të dhënave në faqet statike të shtojcës (me një shpejtësi të caktuar rifreskimi).
  • Përpunimi i pyetjeve për të gjeneruar një fletë shablloni në grafana-dashboards (method .metriFindQuery())

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

  • testi 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: "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"};
       })
}

Një aspekt veçanërisht interesant, sipas mendimit tonë, është zbatimi i mekanizmit të vërtetimit dhe autorizimit për burimin e të dhënave. Zakonisht, menjëherë pas përdorimit, ne mund të përdorim komponentin e integruar datasourceHttpSettings të Grafana-s për të konfiguruar aksesin në burimin përfundimtar të të dhënave. Me këtë komponent, ne mund të konfigurojmë aksesin në burimin e të dhënave HTTP duke specifikuar URL-në dhe cilësimet bazë të vërtetimit/autorizimit: hyrje/fjalëkalim, ose certifikatë-klienti/çelës-klienti. Zbatimi i aftësisë për të konfiguruar aksesin duke përdorur një token bartës (standardi de facto për k8s) kërkoi disa përmirësime.

Për të zgjidhur këtë problem, mund të përdorni mekanizmin e integruar "Plugin Routes" të Grafanës (më shumë detaje mbi faqja zyrtare e dokumentacionit). Në cilësimet e burimit të të dhënave tona, ne mund të deklarojmë një grup rregullash rrugëzimi që do të përpunohen nga serveri proxy grafana. Për shembull, për secilën pikë fundore individuale, ekziston opsioni për të vendosur tituj ose URL me mbështetje shablloni, të dhënat për të cilat mund të merren nga fushat jsonData dhe secureJsonData (për ruajtjen e fjalëkalimeve ose tokenëve në formë të enkriptuar). Në shembullin tonë, kërkesat e formularit /__proxy/api/v1/hapësirat e emrave do të përfaqësohet te URL-të e tipit të mëposhtëm
/api/v1/namespaces me të vendosur kokën Authorization: Bearer.

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Natyrisht, për të punuar me serverin k8s api, na duhet një përdorues me akses vetëm për lexim, manifestet për krijimin e të cilave mund t'i gjeni edhe në kodi burimor i plugin-it.

Pjesa 5: Publikimi

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Pasi të keni shkruar plugin-in tuaj Grafana, natyrisht do të dëshironi ta bëni atë me burim të hapur. Në Grafana, kjo është një bibliotekë plugin-esh, e disponueshme në grafana.com/grafana/plugins

Që shtojca juaj të jetë e disponueshme në dyqanin zyrtar, duhet të bëni një PR në këtë depo, duke shtuar përmbajtje si kjo në skedarin repo.json:

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

ku version është versioni i plugin-it tuaj, url është lidhja me depon dhe commit është hash-i i commit-it që do ta bëjë të disponueshëm versionin specifik të plugin-it.

Dhe në dalje do të shihni një pamje të mrekullueshme si kjo:

Zhvillimi i një shtojce për Grafana: një histori e goditjeve të mëdha

Të dhënat për të do të merren automatikisht nga Readme.md, Changelog.md dhe skedari plugin.json me përshkrimin e plugin-it.

Pjesa 6: Në vend të përfundimeve

Ne nuk kemi ndaluar së zhvilluari shtojcën tonë që nga publikimi i saj. Aktualisht po punojmë për monitorimin e duhur të përdorimit të burimeve të nyjeve të klasterit, zbatimin e veçorive të reja për të përmirësuar përvojën e përdoruesit dhe renditjen e sasisë së madhe të reagimeve që kemi marrë si nga klientët tanë ashtu edhe nga përdoruesit në GitHub pas instalimit të shtojcës (nëse lini një problem ose kërkesë për tërheqje, do të isha shumë i lumtur :)).

Shpresojmë që ky artikull do t'ju ndihmojë të kuptoni një mjet kaq të mrekullueshëm si Grafana dhe, ndoshta, të shkruani shtojcën tuaj.

Faleminderit!)

Burimi: www.habr.com

Bleni një host të besueshëm për faqet me mbrojtje DDoS, serverë VPS VDS 🔥 Bleni hosting të besueshëm të faqeve të internetit me mbrojtje DDoS, servera VPS VDS | ProHoster