Utveckling av plugin för Grafana: en historia av samlade erfarenheter

Hej alla! För nĂ„gra mĂ„nader sedan lanserade vi vĂ„rt nya open-source projekt i produktion — en Grafana-plugin för övervakning av Kubernetes, som vi har döpt till DevOpsProdigy KubeGraf. KĂ€llkoden för pluginet finns tillgĂ€nglig i ett offentligt arkiv pĂ„ GitHub. I den hĂ€r artikeln vill vi dela med er historien om hur vi skapade pluginet, vilka verktyg vi anvĂ€nde och vilka hinder vi stötte pĂ„ under utvecklingen. LĂ„t oss börja!

Del 0 — introduktion: hur kom vi dit?

Idén att skriva vÄr egen plugin för Grafana föddes av en slump. VÄrt företag har arbetat med övervakning av webbprojekt i olika komplexitetsnivÄer i över 10 Är. Under denna tid har vi samlat pÄ oss mycket expertis, intressanta fallstudier och erfarenheter av att anvÀnda olika övervakningssystem. Vid nÄgot tillfÀlle stÀllde vi oss frÄgan: "Finns det ett magiskt verktyg för att övervaka Kubernetes, sÄ att man kan 'installera och glömma'"?.. Standardlösningen för att övervaka k8s Àr naturligtvis sedan lÀnge en kombination av Prometheus + Grafana. Och det finns en mÀngd olika verktyg som erbjuder fÀrdiga lösningar för denna teknikstack: prometheus-operator, en uppsÀttning dashboards frÄn kubernetes-mixin, grafana-kubernetes-app.

Det mest intressanta alternativet för oss verkade vara pluginet grafana-kubernetes-app, men det har inte underhÄllits pÄ över ett Är och dessutom fungerar det inte med de nya versionerna av node-exporter och kube-state-metrics. Vid nÄgot tillfÀlle beslutade vi: "Varför inte göra vÄr egen lösning?"

Vilka idéer beslutade vi oss för att genomföra i vÄrt plugin:

  • visualisering av "applikationskartan": en anvĂ€ndarvĂ€nlig representation av applikationer i klustret, grupperade efter namespaces, deployments
;
  • visualisering av relationer som "deployment — service (+ports)".
  • visualisering av distributionen av klustrets applikationer över noderna i klustret.
  • insamling av metrik och information frĂ„n flera kĂ€llor: Prometheus och k8s API-server.
  • övervakning av bĂ„de infrastrukturdelarna (anvĂ€ndning av processor, minne, lagringssystem, nĂ€tverk) och applikationernas logik — hĂ€lsostatus för pods, antal tillgĂ€ngliga repliker, information om genomförande av liveness/readiness-checkar.

Del 1: Vad Àr en "plugin för Grafana"?

Ur ett tekniskt perspektiv Àr en plugin för Grafana en Angular-kontroller som lagras i data-katalogen för Grafana (/var/grafana/plugins/<your_plugin_name>/dist/module.js) och kan laddas som ett SystemJS-modul. I denna katalog bör det ocksÄ finnas en fil plugin.json som innehÄller all metadata om din plugin: namn, version, typ av plugin, lÀnkar till repository/sajt/licens, beroenden och sÄ vidare.

Utveckling av plugin för Grafana: en historia av samlade erfarenheter
module.ts

Utveckling av plugin för Grafana: en historia av samlade erfarenheter
plugin.json

Som visas i skÀrmdumpen har vi angett plugin.type = app. Plugins för Grafana kan vara av tre typer:

panel: den vanligaste typen av plugin — representerar en panel för visualisering av olika metrik, anvĂ€nds för att bygga olika dashboards.
datasource: plugin-anslutning till en datakÀlla (till exempel Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
app: ett plugin som lÄter dig bygga din egen frontend-applikation inom Grafana, skapa dina egna html-sidor och manuellt göra anslutningar till datakÀllor för att visualisera olika data. Andra typer av plugins (datasource, panel) och olika dashboards kan ocksÄ anvÀndas som beroenden.

Utveckling av plugin för Grafana: en historia av samlade erfarenheter
Exempel pÄ beroenden för plugin med type = app.

Som programmeringssprÄk kan bÄde JavaScript och TypeScript anvÀndas (vi valde det senare). Mallar för hello-world plugins av alla typer kan hittas via lÀnken: i detta repository finns ett stort antal starter-paket (det finns till och med ett experimentellt exempel pÄ en plugin i React) med förinstallerade och konfigurerade byggverktyg.

Del 2: förberedelse av den lokala miljön

För att arbeta med pluginet behöver vi naturligtvis en Kubernetes-kluster med alla förinstallerade verktyg: prometheus, node-exporter, kube-state-metrics, grafana. Miljön bör sÀttas upp snabbt, enkelt och utan problem, och för att sÀkerstÀlla hot-reload bör datakatalogen för Grafana monteras direkt frÄn utvecklarens maskin.

Det mest bekvÀma sÀttet att arbeta lokalt med Kubernetes, enligt vÄr mening, Àr minikube. NÀsta steg Àr att installera Prometheus + Grafana med hjÀlp av prometheus-operator. I denna artikel beskrivs installationsprocessen för prometheus-operator pÄ minikube i detalj. För att aktivera persistens mÄste parametern persistence: true i filen charts/grafana/values.yaml, lösa din egen PV och PVC och ange dem i parameter persistence.existingClaim

Det slutgiltiga startskriptet för minikube ser ut sÄ hÀr:

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

Del 3: direkt utveckling

Objektmodell

Som förberedelse för att implementera pluginen har vi beslutat att beskriva alla grundlÀggande entiteter i Kubernetes som vi kommer att arbeta med i form av TypeScript-klasser: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Varje klass Àrver frÄn en gemensam klass BaseModel, dÀr konstruktör, destruktör, metoder för uppdatering och visningsvÀxling beskrivs. I varje klass beskrivs inbÀddade relationer med andra entiteter, till exempel listan över poddar i en deployment-entitet.

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

Med hjÀlp av getters och setters kan vi visa eller stÀlla in de mÀtvÀrden för entiteter vi behöver pÄ ett bekvÀmt och lÀsbart sÀtt. Till exempel, formaterad utmatning av allocatable cpu för noden:

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

Sidor

Listan över alla sidor i vÄr plugin beskrivs ursprungligen i vÄr pluing.json i avsnittet för beroenden:

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

I blocket för varje sida mÄste vi ange SIDNAMN (det kommer sedan att konverteras till slug, vilket Àr hur denna sida kommer att vara tillgÀnglig); namnet pÄ komponenten som ansvarar för funktionen pÄ denna sida (listan över komponenter exporteras i module.ts); ange vilken anvÀndarroll som har tillgÄng till att arbeta med denna sida och instÀllningarna för navigation i sidopanelen.

I komponenten som ansvarar för sidan mÄste vi stÀlla in templateUrl och ange sökvÀgen till html-filen med markup. Inom controllern, genom dependency injection, kan vi fÄ tillgÄng till 2 viktiga Angular-tjÀnster:

  • backendSrv — tjĂ€nsten som möjliggör interaktion med api-servern för Grafana;
  • datasourceSrv — tjĂ€nsten som möjliggör lokal interaktion med alla datakĂ€llor som Ă€r installerade i din Grafana (till exempel, metoden .getAll() — returnerar en lista över alla installerade datakĂ€llor; .get() — returnerar objektinstansen av en specifik datakĂ€lla.

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

Del 4: datakÀlla

FrÄn Grafanas perspektiv representerar en datasourc exakt samma typ av plugin som alla andra: den har en ingÄngspunkt module.js och en fil med metadata plugin.json. NÀr vi utvecklar ett plugin med typ = app kan vi interagera bÄde med befintliga datasourcer (till exempel prometheus-datasource) och med egna som vi kan lagra direkt i pluginets katalog (dist/datasource/*) eller installera som beroende. I vÄrt fall levereras datasourcen tillsammans med pluginets kod. Det Àr ocksÄ nödvÀndigt att ha en mall config.html och kontrollern ConfigCtrl, som kommer att anvÀndas för konfigureringssidan av datasourc-exemplaret och kontrollern Datasource, dÀr logiken för din datasources funktionalitet implementeras.

I KubeGraf-pluginet, frÄn anvÀndargrÀnssnittets perspektiv, representerar en datasourc ett exempel pÄ en Kubernetes-kluster, dÀr följande funktioner Àr implementerade (kÀllkoden Àr tillgÀnglig via lÀnken):

  • hĂ€mtning av data frĂ„n k8s api-server (hĂ€mtning av listor över namespaces, deployments
)
  • proxying av förfrĂ„gningar till prometheus-datasource (som vĂ€ljs i plugininstĂ€llningarna för varje specifikt kluster) och formatering av svar för att anvĂ€nda data bĂ„de pĂ„ statiska sidor och i dashboards.
  • uppdatering av data pĂ„ statiska sidor i pluginet (med instĂ€lld uppdateringsfrekvens).
  • bearbetning av förfrĂ„gningar för att skapa template-listor i grafana-dashboards (metod .metriFindQuery())

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

  • test av anslutning till den slutgiltiga k8s-klustret.
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"};
       })
}

Enligt vÄr Äsikt Àr en intressant aspekt implementeringen av autentisering och auktorisering för datasource. Vanligtvis kan vi anvÀnda den inbyggda komponenten datasourceHttpSettings i Grafana för att konfigurera Ätkomst till den slutliga datakÀllan. Med denna komponent kan vi stÀlla in Ätkomst till http-datakÀllan genom att ange URL och grundlÀggande autentisering/Auktorisering: anvÀndarnamn-lösenord, eller client-cert/client-key. För att möjliggöra Ätkomstkonfiguration med ett bearer-token (de facto-standarden för k8s) var vi tvungna att göra lite "magik".

För att lösa detta problem kan den inbyggda mekanismen "Plugin Routes" i Grafana anvÀndas (mer information finns pÄ den officiella dokumentationssidan). I instÀllningarna för vÄr datasource kan vi deklarera en uppsÀttning routingregler som kommer att hanteras av grafana proxy-servern. Till exempel finns det för varje separat endpoint möjlighet att ange rubriker eller URL med templatering, vars data kan hÀmtas frÄn fÀlten jsonData och secureJsonData (för att lagra lösenord eller tokens i krypterad form). I vÄrt exempel kommer förfrÄgningar av typen /__proxy/api/v1/namespaces att proxas till URL av typen
/api/v1/namespaces med att rubriken Authorization: Bearer anger.

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

SjÀlvklart behöver vi en anvÀndare med readonly Ätkomst för att arbeta med k8s api-servern, och manifest för att skapa den kan du ocksÄ hitta i pluginens kÀllkod.

Del 5: release

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

Efter att du har skrivit din egen plugin för Grafana kommer du sjÀlvklart vilja publicera den offentligt. I Grafana finns det ett pluginbibliotek som Àr tillgÀngligt via lÀnken grafana.com/grafana/plugins

För att din plugin ska vara tillgÀnglig i den officiella butiken mÄste du göra en PR i detta repository, genom att lÀgga till innehÄllet av typen i filen repo.json:

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

dÀr version - versionen av din plugin, url - lÀnk till ditt repository, och commit - hash för den commit som den specifika versionen av pluginen kommer att vara tillgÀnglig.

Och till slut kommer du att se en underbar bild av typen:

Utveckling av plugin för Grafana: en historia av samlade erfarenheter

Data för den kommer automatiskt att samlas in frÄn din Readme.md, Changelog.md och plugin.json-filens beskrivning av pluginen.

Del 6: sammanfattning

Vi har inte slutat utveckla vĂ„r plugin efter lanseringen. Just nu arbetar vi med korrekt övervakning av resursanvĂ€ndningen av noderna i klustret, införandet av nya funktioner för att förbĂ€ttra anvĂ€ndarupplevelsen samt att bearbeta mĂ€ngder av feedback som vi har fĂ„tt efter installationer av pluginet, bĂ„de frĂ„n vĂ„ra kunder och genom issues pĂ„ GitHub (om du lĂ€mnar en issue eller pull request blir jag mycket glad 🙂 ).

Vi hoppas att denna artikel hjÀlper dig att förstÄ det fantastiska verktyget Grafana och kanske skriva din egen plugin.

Tack!)

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster