Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

Hi almal! 'n Paar maande gelede het ons ons nuwe oopbronprojek in produksie bekendgestel - Grafana-inprop vir die monitering van kubernetes, wat ons genoem het DevOpsProdigy KubeGraf. Inprop-bronkode is beskikbaar by openbare bewaarplek op GitHub. En in hierdie artikel wil ons die storie met jou deel van hoe ons die inprop geskep het, watter gereedskap ons gebruik het en watter slaggate ons in die ontwikkelingsproses teëgekom het. Kom ons gaan!

Deel 0 - inleidend: hoe het ons by hierdie punt gekom?

Die idee om ons eie inprop vir Grafan te skryf, is heel toevallig gebore. Ons maatskappy monitor webprojekte van verskillende vlakke van kompleksiteit vir meer as 10 jaar. Gedurende hierdie tyd het ons baie kundigheid, interessante gevalle en ervaring opgedoen in die gebruik van verskeie moniteringstelsels. En op 'n stadium het ons onsself afgevra: "Is daar 'n towerinstrument om Kubernetes te monitor, sodat, soos hulle sê, "stel dit en vergeet dit"?" En as gereedgemaakte oplossings vir hierdie stapel, is daar 'n groot stel verskillende soorte gereedskap: prometheus-operateur, 'n stel kubernetes-mixin-dashboards, grafana-kubernetes-app.

Die grafana-kubernetes-app-inprop was die interessantste opsie vir ons, maar dit word nie meer as 'n jaar ondersteun nie en weet boonop nie hoe om met nuwe weergawes van node-exporter en kube-state- te werk nie. metrieke. En op 'n stadium het ons besluit: "Moet ons nie ons eie besluit neem nie?"

Watter idees het ons besluit om in ons inprop te implementeer:

  • visualisering van die "toepassingskaart": gerieflike aanbieding van toepassings in 'n groepering, gegroepeer volgens naamruimtes, ontplooiings ...;
  • visualisering van skakels soos "ontplooiing - diens (+poorte)".
  • visualisering van die verspreiding van klustertoepassings deur cluster nodusse.
  • versameling van statistieke en inligting uit verskeie bronne: Prometheus en k8s api-bediener.
  • monitering van beide die infrastruktuurdeel (die gebruik van verwerkertyd, geheue, skyfsubstelsel, netwerk) en die toepassingslogika - die gesondheidstatus van peule, die aantal beskikbare replikas, inligting oor die verloop van lewendheid/gereedheid-probes.

Deel 1: Wat is 'n "inprop vir Grafana"?

Vanuit 'n tegniese oogpunt is 'n inprop vir Grafana 'n hoekbeheerder wat in Grafana se datagids gestoor word (/var/grafana/plugins/ /dist/module.js) en kan as 'n SystemJS-module gelaai word. Ook in hierdie gids behoort daar 'n plugin.json-lêer te wees wat al die meta-inligting oor jou inprop bevat: naam, weergawe, tipe inprop, skakels na die bewaarplek / webwerf / lisensie, afhanklikhede, ensovoorts.

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls
module.ts

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls
plugin.json

Soos u in die skermkiekie kan sien, het ons plugin.type = app gespesifiseer. Vir plugins vir Grafana kan van drie tipes wees:

paneel: die mees algemene tipe inproppe - is 'n paneel vir die visualisering van enige maatstawwe, wat gebruik word om verskeie dashboards te bou.
data bron: inpropverbinding na enige databron (byvoorbeeld Prometheus-databron, ClickHouse-databron, ElasticSearch-databron).
artikels: 'n Inprop wat jou toelaat om jou eie voorkanttoepassing binne Grafana te bou, jou eie HTML-bladsye te skep, en handmatig toegang tot die databron te verkry om verskeie data weer te gee. Inproppe van ander tipes (databron, paneel) en verskeie dashboards kan ook as afhanklikhede gebruik word.

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls
Voorbeeld inpropafhanklikhede met tipe = app.

As 'n programmeertaal kan jy beide JavaScript en TypeScript gebruik (ons het dit gekies). U kan sjablone skep vir hello-wêreld-inproppe van enige tipe vind deur skakel: hierdie bewaarplek bevat 'n groot aantal beginpakkette (daar is selfs 'n eksperimentele voorbeeld van 'n React-inprop) met vooraf geïnstalleerde en gekonfigureerde bouers.

Deel 2: voorbereiding van die plaaslike omgewing

Om aan die inprop te werk, benodig ons natuurlik 'n kubernetes-kluster met al die vooraf geïnstalleerde gereedskap: prometheus, node-uitvoerder, kube-state-metrics, grafana. Die omgewing moet vinnig, maklik en natuurlik opgestel word, en om te verseker dat die Grafana-datagids direk vanaf die ontwikkelaar se masjien gelaai word, moet die Grafana-datagids gemonteer word.

Die gerieflikste, na ons mening, manier om plaaslik met kubernetes te werk, is minikube. Die volgende stap is om die Prometheus + Grafana-bundel te installeer deur die prometheus-operateur te gebruik. IN Hierdie artikel die proses om prometheus-operator op minikube te installeer, word in detail beskryf. Om volharding moontlik te maak, moet jy die parameter stel volharding: waar in die charts/grafana/values.yaml lêer, voeg jou eie PV en PVC by en spesifiseer hulle in die persistence.existingClaim parameter

Die finale minikube-opstartskrif lyk soos volg:

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

Deel 3: direkte ontwikkeling

Voorwerp Model

As 'n voorbereiding vir die implementering van die inprop, het ons besluit om al die basiese Kubernetes-entiteite waarmee ons sal werk, te beskryf in die vorm van TypeScript-klasse: pod, ontplooiing, daemonset, statefulset, job, cronjob, diens, node, naamruimte. Elkeen van hierdie klasse erf van die algemene BaseModel-klas, wat die konstruktor, vernietiger, metodes vir opdatering en omskakeling van sigbaarheid beskryf. Elkeen van die klasse beskryf geneste verhoudings met ander entiteite, byvoorbeeld 'n lys peule vir 'n entiteit van ontplooiingstipe.

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

Met die hulp van getters en opstellers kan ons die entiteitsmaatstawwe wat ons benodig in 'n gerieflike en leesbare vorm vertoon of stel. Byvoorbeeld, die geformateerde uitset van toekenbare cpu knik:

get cpuAllocatableFormatted(){
   let cpu = this.data.status.allocatable.cpu;
   if(cpu.indexOf('m') > -1){
       cpu = parseInt(cpu)/1000;
   }
   return cpu;
}

bladsye

Die lys van alle bladsye van ons inprop word aanvanklik beskryf in ons pluing.json in die afdeling afhanklikhede:

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

In die blok vir elke bladsy moet ons die BLADSY NAAM spesifiseer (dit sal dan omskep word in 'n slak waardeur hierdie bladsy beskikbaar sal wees); die naam van die komponent wat verantwoordelik is vir die werking van hierdie bladsy (die lys van komponente word na module.ts uitgevoer); spesifiseer die gebruikerrol waarvoor werk met hierdie bladsy beskikbaar is en navigasie-instellings vir die sybalk.

In die komponent wat vir die bladsy verantwoordelik is, moet ons die templateUrl stel deur die pad na die html-lêer met die opmaak daar deur te gee. Binne die beheerder kan ons deur afhanklikheidsinspuiting toegang tot 2 belangrike hoekdienste kry:

  • backendSrv - 'n diens wat interaksie met die grafana api-bediener bied;
  • datasourceSrv - 'n diens wat plaaslike interaksie verskaf met alle databronne wat in jou Grafana geïnstalleer is (byvoorbeeld, die .getAll() metode - gee 'n lys van alle geïnstalleerde databronne terug; .get( ) - gee 'n instansieobjek van 'n spesifieke databron terug.

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

Deel 4: databron

Uit die oogpunt van Grafana is databron presies dieselfde inprop as al die ander: dit het sy eie module.js-intreepunt, daar is 'n plugin.json-lêer met meta-inligting. Wanneer ons 'n inprop met tipe = app ontwikkel, kan ons met beide bestaande databronne (byvoorbeeld prometheus-datasource) en ons eie interaksie hê, wat ons direk in die inpropgids (dist/datasource/*) kan stoor of as 'n afhanklikheid kan installeer . In ons geval kom die databron met die inpropkode. Dit is ook nodig om 'n config.html-sjabloon en 'n ConfigCtrl-beheerder te hê wat gebruik sal word vir die databroninstansie-konfigurasiebladsy en 'n Databronbeheerder wat jou databron se logika implementeer.

In die KubeGraf-inprop, in terme van gebruikerskoppelvlak, is databron 'n voorbeeld van 'n kubernetes-kluster wat die volgende kenmerke implementeer (bronkode is beskikbaar по ссылке):

  • haal data van k8s api-bediener af (kry 'n lys van naamruimtes, ontplooiings ...)
  • volmagversoeke na prometheus-databron (wat gekies word in die inpropinstellings vir elke spesifieke groepering) en formatering van antwoorde om data in beide statiese bladsye en in kontroleskerms te gebruik.
  • opdatering van data op statiese bladsye van die inprop (met 'n vasgestelde verversingsfrekwensie tyd).
  • verwerking van navrae om 'n sjabloonblad in grafana-dashboards te vorm (metode .metriFindQuery())

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

  • verbindingstoets met die finale k8s-kluster.
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"};
       })
}

'n Aparte interessante punt, na ons mening, is die implementering van die verifikasie- en magtigingsmeganisme vir die databron. As 'n reël, buite die boks, om toegang tot die finale databron op te stel, kan ons die ingeboude Grafana-komponent gebruik - datasourceHttpSettings. Deur hierdie komponent te gebruik, kan ons toegang tot die http-databron opstel deur die url en basiese verifikasie/magtiging-instellings te spesifiseer: login-wagwoord, of client-cert/client-key. Om die vermoë om toegang te konfigureer met behulp van 'n draer-token (die de facto-standaard vir k8's) te implementeer, moes ek 'n bietjie "bedrog" doen.

Om hierdie probleem op te los, kan jy die ingeboude Grafana "Plugin Routes" meganisme gebruik (meer oor amptelike dokumentasie bladsy). In die instellings van ons databron kan ons 'n stel roetereëls verklaar wat deur die grafana-instaanbediener verwerk sal word. Byvoorbeeld, vir elke individuele eindpunt is daar die moontlikheid om opskrifte of url op te stel met die moontlikheid van sjabloon, waarvan die data uit die jsonData- en secureJsonData-velde geneem kan word (vir die stoor van wagwoorde of tekens in geënkripteerde vorm). In ons voorbeeld, navrae soos /__proxy/api/v1/naamruimtes sal gevolmagtig word na die url van die vorm
/api/v8/naamruimtes met kopskrif Magtiging: Draer .

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

Natuurlik, om met die k8s api-bediener te werk, benodig ons 'n gebruiker met leesalleentoegang, die manifeste vir die skep wat u ook kan vind in plugin bronkode.

Deel 5: vrystelling

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

Sodra jy jou eie Grafana-inprop geskryf het, sal jy dit natuurlik publiek beskikbaar wil stel. In Grafana is dit 'n plugin-biblioteek wat by die skakel beskikbaar is grafana.com/grafana/plugins

Om u inprop in die amptelike winkel beskikbaar te maak, moet u 'n PR instel hierdie bewaarplek, en voeg die volgende inhoud by die repo.json-lêer:

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

waar weergawe die weergawe van jou inprop is, url 'n skakel na die bewaarplek is, en commit is die hash van die commit wat die spesifieke inpropweergawe beskikbaar sal maak.

En by die uitset sal jy 'n wonderlike prentjie van die vorm sien:

Inpropontwikkeling vir Grafana: die geskiedenis van gevulde keëls

Die data daarvoor sal outomaties van jou Readme.md, Changelog.md en die plugin.json-lêer met die inpropbeskrywing beroof word.

Deel 6: in plaas van gevolgtrekkings

Ons het nie opgehou om ons inprop te ontwikkel na die vrystelling nie. En nou werk ons ​​aan die korrekte monitering van die gebruik van hulpbronne van die cluster nodusse, die bekendstelling van nuwe funksies om UX te verbeter, en ons haal ook 'n groot hoeveelheid terugvoer in wat ontvang is na die installering van die inprop, beide deur ons kliënte en van ishshui op github (as jy jou kwessie of trekversoek los, sal ek baie gelukkig wees 🙂).

Ons hoop dat hierdie artikel u sal help om so 'n wonderlike hulpmiddel soos Grafana te verstaan ​​en miskien u eie inprop te skryf.

Dankie!)

Bron: will.com

Voeg 'n opmerking