Hei alle sammen! For noen mÄneder siden lanserte vi vÄrt nye Äpen kildekode-prosjekt i produksjon - Grafana-pluginen for overvÄking av kubernetes, som vi kalte . Kildekoden til plugin-modulen er tilgjengelig pÄ . Og i denne artikkelen Þnsker vi Ä dele med deg historien om hvordan vi laget plugin, hvilke verktÞy vi brukte og hvilke fallgruver vi mÞtte under utviklingsprosessen. La oss gÄ!
Del 0 - innledning: hvordan kom vi til dette punktet?
Ideen om Ä skrive vÄr egen plugin for Grafan kom til oss ganske ved en tilfeldighet. VÄrt firma har overvÄket nettprosjekter av ulike kompleksitetsnivÄer i mer enn 10 Är. I lÞpet av denne tiden har vi samlet en stor mengde kompetanse, interessante saker og erfaring med bruk av ulike overvÄkingssystemer. Og pÄ et tidspunkt spurte vi oss selv: "Finnes det et magisk verktÞy for Ä overvÄke Kubernetes, slik at, som de sier, "sett det og glem det"? Prometheus + Grafana kombinasjon. Og som ferdige lÞsninger for denne stabelen er det et stort sett med ulike typer verktÞy: prometheus-operator, et sett med kubernetes-mixin-dashboard, grafana-kubernetes-app.
Grafana-kubernetes-app-pluginen sÄ ut til Ä vÊre det mest interessante alternativet for oss, men det har ikke vÊrt stÞttet pÄ mer enn et Är og kan dessuten ikke fungere med nye versjoner av node-eksporter og kube-state-metrics. Og pÄ et tidspunkt bestemte vi oss: "Skal vi ikke ta vÄr egen avgjÞrelse?"
Hvilke ideer vi bestemte oss for Ä implementere i plugin-modulen vÄr:
- visualisering av "applikasjonskartet": praktisk presentasjon av applikasjoner i klyngen, gruppert etter navnerom, distribusjoner...;
- visualisering av tilkoblinger som "distribusjon - tjeneste (+porter)".
- visualisering av fordelingen av klyngeapplikasjoner pÄ tvers av klyngenoder.
- innsamling av metrikk og informasjon fra flere kilder: Prometheus og k8s api-server.
- overvÄking av bÄde infrastrukturdelen (bruk av CPU-tid, minne, diskdelsystem, nettverk) og applikasjonslogikk - helsestatuspoder, antall tilgjengelige replikaer, informasjon om bestÄtt liveness/readyness-tester.
Del 1: Hva er en "Grafana-plugin"?
Fra et teknisk synspunkt er plugin for Grafana en vinkelkontroller, som er lagret i Grafana-datakatalogen (/var/grafana/plugins/ /dist/module.js) og kan lastes inn som en SystemJS-modul. OgsÄ i denne katalogen bÞr det vÊre en plugin.json-fil som inneholder all metainformasjon om plugin-en din: navn, versjon, plugin-type, lenker til depotet/nettstedet/lisensen, avhengigheter og sÄ videre.

modul.ts

plugin.json
Som du kan se pÄ skjermbildet, spesifiserte vi plugin.type = app. Fordi plugins for Grafana kan vÊre av tre typer:
panel: den vanligste typen plugin - det er et panel for Ă„ visualisere alle beregninger, brukt til Ă„ bygge forskjellige dashboards.
datakilde: plugin-kobling til en datakilde (for eksempel Prometheus-datakilde, ClickHouse-datakilde, ElasticSearch-datakilde).
app: En plugin som lar deg bygge din egen frontend-applikasjon inne i Grafana, lage dine egne html-sider og manuelt fÄ tilgang til datakilden for Ä visualisere ulike data. OgsÄ plugins av andre typer (datakilde, panel) og ulike dashbord kan brukes som avhengigheter.

Eksempel pÄ plugin-avhengigheter med type=app.
Du kan bruke bÄde JavaScript og TypeScript som programmeringssprÄk (vi valgte det). Forberedelser for hello-world plugins av alle typer du kan : dette depotet inneholder et stort antall startpakker (det er til og med et eksperimentelt eksempel pÄ en plugin i React) med forhÄndsinstallerte og konfigurerte byggere.
Del 2: forberede lokalmiljĂžet
For Ä jobbe med plugin-en trenger vi naturligvis en kubernetes-klynge med alle forhÄndsinstallerte verktÞy: prometheus, node-exporter, kube-state-metrics, grafana. MiljÞet bÞr settes opp raskt, enkelt og naturlig, og for Ä sikre hot-reload, bÞr Grafana-datakatalogen monteres direkte fra utviklerens maskin.
Den mest praktiske mÄten, etter vÄr mening, Ä jobbe lokalt med kubernetes er . Det neste trinnet er Ä installere Prometheus + Grafana-kombinasjonen ved Ä bruke prometheus-operator. I Prosessen med Ä installere prometheus-operator pÄ minikube er beskrevet i detalj. For Ä aktivere utholdenhet mÄ du angi parameteren utholdenhet: sant i charts/grafana/values.yaml-filen, legg til din egen PV og PVC og spesifiser dem i persistence.existingClaim-parameteren
VÄrt siste minikube-lanseringsskript ser slik ut:
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.LDel 3: faktisk utvikling
Objektmodell
Som forberedelse til implementering av plugin bestemte vi oss for Ä beskrive alle de grunnleggende Kubernetes-enhetene som vi vil jobbe med i form av TypeScript-klasser: pod, deployment, daemonset, statefulset, jobb, cronjob, service, node, navneomrÄde. Hver av disse klassene arver fra den vanlige BaseModel-klassen, som beskriver konstruktÞren, destruktoren, metoder for oppdatering og bytte av synlighet. Hver av klassene beskriver nestede relasjoner med andre enheter, for eksempel en liste over pods for en enhet av typen distribusjon.
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 = [];
}
}Ved hjelp av gettere og settere kan vi vise eller angi enhetsberegningene vi trenger i en praktisk og lesbar form. For eksempel formatert utdata fra allokerbare CPU-noder:
get cpuAllocatableFormatted(){
let cpu = this.data.status.allocatable.cpu;
if(cpu.indexOf('m') > -1){
cpu = parseInt(cpu)/1000;
}
return cpu;
}sider
En liste over alle plugin-sidene vÄre er fÞrst beskrevet i vÄr pluing.json i avhengighetsdelen:

I blokken for hver side mÄ vi angi SIDENAVN (det vil da bli konvertert til en slug som denne siden vil vÊre tilgjengelig); navnet pÄ komponenten som er ansvarlig for driften av denne siden (listen over komponenter eksporteres til module.ts); som indikerer brukerrollen som arbeid med denne siden er tilgjengelig for og navigasjonsinnstillinger for sidefeltet.
I komponenten som er ansvarlig for driften av siden, mÄ vi sette templateUrl, og sende stien til html-filen med markup der. Inne i kontrolleren, gjennom avhengighetsinjeksjon, kan vi fÄ tilgang til opptil 2 viktige vinkeltjenester:
- backendSrv - en tjeneste som gir interaksjon med Grafana API-serveren;
- datasourceSrv - en tjeneste som gir lokal interaksjon med alle datakilder som er installert i din Grafana (for eksempel .getAll()-metoden - returnerer en liste over alle installerte datakilder; .get( ) - returnerer et forekomstobjekt av en bestemt datakilde.



Del 4: datakilde
Fra Grafanas synspunkt er datakilden nÞyaktig samme plugin som alle de andre: den har sitt eget inngangspunkt module.js, det er en fil med metainformasjon plugin.json. NÄr vi utvikler en plugin med type = app, kan vi samhandle med bÄde eksisterende datakilder (for eksempel prometheus-datasource) og vÄr egen, som vi kan lagre direkte i plugin-katalogen (dist/datasource/*) eller installere som en avhengighet. I vÄrt tilfelle kommer datakilden med plugin-koden. Det er ogsÄ nÞdvendig Ä ha en config.html-mal og en ConfigCtrl-kontroller, som vil bli brukt for konfigurasjonssiden for datakildeforekomsten og datakildekontrolleren, som implementerer driftslogikken til datakilden din.
I KubeGraf-plugin-modulen, fra brukergrensesnittets synspunkt, er datakilden en forekomst av en kubernetes-klynge som implementerer fĂžlgende funksjoner (kildekoden er tilgjengelig ):
- samler inn data fra k8s api-serveren (fÄr en liste over navneomrÄder, distribusjoner...)
- proxy-forespÞrsler til prometheus-datasource (som er valgt i plugin-innstillingene for hver spesifikke klynge) og formatering av svar for Ä bruke data bÄde pÄ statiske sider og i dashboards.
- oppdatering av data pÄ statiske plugin-sider (med en angitt oppdateringsfrekvens).
- behandle spĂžrringer for Ă„ generere et malark i grafana-dashboards (metriFindQuery()-metoden)



- forbindelsestest med den siste k8s-klyngen.
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"};
})
}Et eget interessant poeng, etter vÄr mening, er implementeringen av en autentiserings- og autorisasjonsmekanisme for datakilden. Vanligvis, ut av boksen, kan vi bruke den innebygde Grafana-komponenten datasourceHttpSettings for Ä konfigurere tilgang til den endelige datakilden. Ved Ä bruke denne komponenten kan vi konfigurere tilgang til http-datakilden ved Ä spesifisere url og grunnleggende autentisering/autorisasjonsinnstillinger: pÄloggingspassord eller klientsert/klientnÞkkel. For Ä implementere muligheten til Ä konfigurere tilgang ved hjelp av en bÊrer-token (de facto-standarden for k8s), mÄtte vi gjÞre en liten justering.
For Ä lÞse dette problemet kan du bruke den innebygde Grafana "Plugin Routes"-mekanismen (mer informasjon pÄ ). I innstillingene til datakilden vÄr kan vi deklarere et sett med rutingsregler som vil bli behandlet av grafana proxy-serveren. For hvert enkelt endepunkt er det for eksempel mulig Ä sette overskrifter eller nettadresser med mulighet for maling, hvor dataene kan hentes fra feltene jsonData og secureJsonData (for lagring av passord eller tokens i kryptert form). I vÄrt eksempel, spÞrringer som /__proxy/api/v1/navneomrÄder vil bli proksert til url-en til skjemaet
/api/v8/namespaces med Autorisasjon: BĂŠrer-overskrift.


For Ä jobbe med k8s api-serveren trenger vi naturligvis en bruker med skrivebeskyttet tilgang, manifester for Ä lage som du ogsÄ kan finne i .
Del 5: utgivelse

NÄr du har skrevet ditt eget Grafana-plugin, vil du naturligvis gjÞre det offentlig tilgjengelig. I Grafana er dette et bibliotek med plugins tilgjengelig her
For at plugin-en din skal vÊre tilgjengelig i den offisielle butikken, mÄ du lage en PR-inngang ved Ä legge til innhold som dette i repo.json-filen:

der versjon er versjonen av plugin-en din, url er en lenke til depotet, og commit er hashen til commit-en som en spesifikk versjon av plugin-en vil vĂŠre tilgjengelig for.
Og ved utgangen vil du se et fantastisk bilde som:

Dataene for den hentes automatisk fra Readme.md, Changelog.md og plugin.json-filen med plugin-beskrivelsen.
Del 6: i stedet for konklusjoner
Vi sluttet ikke Ä utvikle plugin-modulen vÄr etter utgivelsen. Og nÄ jobber vi med Ä overvÄke ressursbruken til klyngenoder pÄ riktig mÄte, introdusere nye funksjoner for Ä forbedre brukeropplevelsen, og ogsÄ hente inn en stor mengde tilbakemeldinger mottatt etter installasjon av plugin bÄde av vÄre kunder og fra folk pÄ GitHub (hvis du forlater problemet eller pull-forespÞrselen din, jeg blir veldig glad :)
Vi hÄper at denne artikkelen vil hjelpe deg Ä forstÄ et sÄ fantastisk verktÞy som Grafana og kanskje skrive din egen plugin.
Takk!)
Kilde: www.habr.com
