Utveckling av ett plugin för Grafana: en historia av stora skott

Hej allihopa! För nĂ„gra mĂ„nader sedan lanserade vi vĂ„rt nya open source-projekt i produktion - ett Grafana-plugin för övervakning av Kubernetes, som vi kallade DevOpsProdigy KubeGrafKĂ€llkoden för plugin-programmet finns tillgĂ€nglig i offentligt arkiv pĂ„ GitHubOch i den hĂ€r artikeln vill vi dela med oss ​​av historien om hur vi skapade pluginet, vilka verktyg vi anvĂ€nde och vilka fallgropar vi stötte pĂ„ under utvecklingsprocessen. Nu kör vi!

Del 0 - Introduktion: Hur hamnade vi hÀr?

Idén att skriva vÄrt eget plugin för Grafana kom till oss helt av en slump. VÄrt företag har övervakat webbprojekt av varierande komplexitet i över 10 Är. Under denna tid har vi samlat pÄ oss en mÀngd expertis, intressanta fall och erfarenhet av att anvÀnda olika övervakningssystem. Och vid nÄgon tidpunkt frÄgade vi oss sjÀlva: "Finns det ett magiskt verktyg för att övervaka Kubernetes som man, som man sÀger, kan "stÀlla in och glömma"?" Naturligtvis har Prometheus + Grafana-paketet lÀnge varit branschstandarden för att övervaka K8S. Och som fÀrdiga lösningar för denna stack finns en stor uppsÀttning olika verktyg: prometheus-operator, en uppsÀttning dashboards kubernetes-mixin, grafana-kubernetes-app.

Det mest intressanta alternativet för oss verkade vara grafana-kubernetes-app-pluginet, men det har inte stödts pÄ över ett Är och dessutom kan det inte fungera med nya versioner av node-exporter och kube-state-metrics. Och vid nÄgon tidpunkt bestÀmde vi oss: "Varför inte skapa vÄr egen lösning?"

Vilka idéer bestÀmde vi oss för att implementera i vÄrt plugin:

  • visualisering av "applikationskartan": en bekvĂ€m representation av applikationer i ett kluster, grupperade efter namnrymder, distributioner etc.;
  • visualisering av anslutningar av typen "distribution - tjĂ€nst (+portar)".
  • visualisering av distributionen av klusterapplikationer över klusternoder.
  • samlar in mĂ€tvĂ€rden och information frĂ„n flera kĂ€llor: Prometheus och K8s API-server.
  • övervakning av bĂ„de infrastrukturdelen (anvĂ€ndning av processortid, minne, diskundersystem, nĂ€tverk) och applikationslogik - hĂ€lsostatus för poddar, antal tillgĂ€ngliga repliker, information om genomförande av liveness-/beredskapstester.

Del 1: Vad Àr ett "Grafana-plugin"?

Tekniskt sett Àr ett Grafana-plugin en vinkelkontroller som lagras i Grafanas datakatalog (/var/grafana/plugins/ /dist/module.js) och kan laddas som en SystemJS-modul. I den hÀr katalogen bör det ocksÄ finnas en fil plugin.json, som innehÄller all metainformation om ditt plugin: namn, version, plugin-typ, lÀnkar till repository/site/licens, beroenden etc.

Utveckling av ett plugin för Grafana: en historia av stora skott
modul.ts

Utveckling av ett plugin för Grafana: en historia av stora skott
plugin.json

Som du kan se pÄ skÀrmdumpen angav vi plugin.type = app. Eftersom plugins för Grafana kan vara av tre typer:

panel: den vanligaste typen av plugin - Àr en panel för att visualisera vissa mÀtvÀrden, som anvÀnds för att bygga olika dashboards.
datakÀllaen plugin-koppling till nÄgon datakÀlla (till exempel Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
app: ett plugin som lÄter dig bygga din egen frontend-applikation i Grafana, skapa dina egna html-sidor och manuellt komma Ät datakÀllan för att visualisera olika data. Andra typer av plugins (datakÀlla, panel) och olika dashboards kan ocksÄ anvÀndas som beroenden.

Utveckling av ett plugin för Grafana: en historia av stora skott
Exempel pÄ plugin-beroenden med type = app.

Du kan anvÀnda antingen JavaScript eller TypeScript som programmeringssprÄk (vi valde det). Du kan hitta mallar för hello-world-plugins av alla typer hitta via lÀnkDetta repository innehÄller ett stort antal startpaket (det finns till och med ett experimentellt exempel pÄ ett plugin pÄ React) med förinstallerade och konfigurerade bundlers.

Del 2: Förbereda den lokala miljön

För att arbeta med pluginet behöver vi naturligtvis ett Kubernetes-kluster med alla förinstallerade verktyg: prometheus, node-exporter, kube-state-metrics, grafana. Miljön bör konfigureras snabbt, enkelt och smidigt, och för att sÀkerstÀlla snabb Äterladdning bör Grafana-datakatalogen monteras direkt frÄn utvecklarens maskin.

Enligt vÄr mening Àr det enklaste sÀttet att arbeta lokalt med Kubernetes minikubeNÀsta steg Àr att installera Prometheus + Grafana-paketet med hjÀlp av prometheus-operator. Denna artikel Processen för att installera prometheus-operator pÄ minikube beskrivs i detalj. För att aktivera persistens mÄste du stÀlla in parametern uthÄllighet: sant I filen charts/grafana/values.yaml, lÀgg till din egen PV och PVC och ange dem i parametern persistence.existingClaim.

VÄrt slutgiltiga lanseringsskript 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 inför plugin-implementeringen bestÀmde vi oss för att beskriva alla grundlÀggande Kubernetes-entiteter som vi kommer att arbeta med som TypeScript-klasser: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Var och en av dessa klasser Àrvs frÄn den gemensamma BaseModel-klassen, som beskriver konstruktorn, destruktorn, metoder för att uppdatera och byta synlighet. Var och en av klasserna beskriver kapslade relationer med andra entiteter, till exempel en lista över poddar för en entitet av deployment-typen.

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

Med hjÀlp av getters och setters kan vi mata ut eller stÀlla in de entitetsmÄtt vi behöver i en bekvÀm och lÀsbar form. Till exempel, den formaterade utdata frÄn allokerbara CPU-noder:

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Ärt plugin beskrivs initialt i vÄr pluing.json i avsnittet om beroenden:

Utveckling av ett plugin för Grafana: en historia av stora skott

I blocket för varje sida mÄste vi ange SIDENAMNET (det kommer dÄ att konverteras till en slug genom vilken sidan blir tillgÀnglig); namnet pÄ komponenten som ansvarar för driften av denna sida (listan över komponenter exporteras till module.ts); indikation av anvÀndarrollen för vilken arbete med denna sida Àr tillgÀngligt och navigeringsinstÀllningar för sidofÀltet.

I komponenten som ansvarar för sidan mÄste vi stÀlla in templateUrl och skicka dit sökvÀgen till html-filen med markupen. Inuti kontrollenheten kan vi, genom dependency injection, fÄ tillgÄng till tvÄ viktiga Angular-tjÀnster:

  • backendSrv Ă€r en tjĂ€nst som tillhandahĂ„ller interaktion med grafanas API-server;
  • datasourceSrv — en tjĂ€nst som tillhandahĂ„ller lokal interaktion med alla datakĂ€llor som Ă€r installerade i din Grafana (till exempel returnerar metoden .getAll() en lista över alla installerade datakĂ€llor; .get() ) - returnerar ett instansobjekt för en specifik datakĂ€lla.

Utveckling av ett plugin för Grafana: en historia av stora skott

Utveckling av ett plugin för Grafana: en historia av stora skott

Utveckling av ett plugin för Grafana: en historia av stora skott

Del 4: datakÀlla

Ur Grafanas synvinkel Àr datasource exakt samma plugin som alla andra: det har sin egen entry point module.js, det finns en fil med metainformation plugin.json. NÀr vi utvecklar ett plugin med typen = app kan vi interagera med bÄde befintliga datakÀllor (till exempel prometheus-datasource) och vÄra egna, som vi kan lagra direkt i plugin-katalogen (dist/datasource/*) eller installera som ett beroende. I vÄrt fall levereras datasourcen med plugin-koden. Dessutom krÀvs config.html-mallen och ConfigCtrl-kontrollanten, som kommer att anvÀndas för konfigurationssidan för datasource-instansen och Datasource-kontrollanten, som implementerar logiken för din datasource.

I KubeGraf-pluginet Ă€r en datakĂ€lla, ur anvĂ€ndargrĂ€nssnittsperspektiv, en instans av ett Kubernetes-kluster som implementerar följande funktioner (kĂ€llkod tillgĂ€nglig ĐżĐŸ ссылĐșĐ”):

  • hĂ€mtar data frĂ„n k8s api-server (hĂ€mtar en lista över namnrymder, distributioner...)
  • proxyförfrĂ„gningar till prometheus-datasource (som vĂ€ljs i plugin-instĂ€llningarna för varje specifikt kluster) och formatering av svar för att anvĂ€nda data bĂ„de pĂ„ statiska sidor och i dashboards.
  • uppdaterar data pĂ„ statiska sidor i plugin-programmet (med den instĂ€llda uppdateringsfrekvenstiden).
  • bearbetar frĂ„gor för att generera ett mallark i grafana-dashboards (metod .metriFindQuery())

Utveckling av ett plugin för Grafana: en historia av stora skott

Utveckling av ett plugin för Grafana: en historia av stora skott

Utveckling av ett plugin för Grafana: en historia av stora skott

  • testanslutning med det slutliga 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"};
       })
}

En separat intressant punkt, enligt vĂ„r mening, Ă€r implementeringen av autentiserings- och auktoriseringsmekanismen för datakĂ€llan. Som regel kan vi, direkt ur lĂ„dan, anvĂ€nda den inbyggda Grafana-komponenten — datasourceHttpSettings. Med den hĂ€r komponenten kan vi konfigurera Ă„tkomst till http-datakĂ€llan genom att ange url:en och grundlĂ€ggande autentiserings-/auktoriseringsinstĂ€llningar: login-password eller client-cert/client-key. För att implementera möjligheten att konfigurera Ă„tkomst med en bearer-token (de facto-standarden för k8s) var vi tvungna att "fuska" lite.

För att lösa detta problem kan du anvÀnda den inbyggda Grafana-mekanismen "Plugin Routes" (mer information finns pÄ officiell dokumentationssidaI instÀllningarna för vÄr datakÀlla kan vi deklarera en uppsÀttning routingregler som kommer att bearbetas av grafana-proxyservern. Till exempel, för varje enskild slutpunkt finns det möjlighet att ange rubriker eller URL med möjlighet att skapa mallar, 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 Àr förfrÄgningar av typen /__proxy/api/v1/namnrymder kommer att skickas via proxy till webbadresser av formen
/api/v8/namnrymder med headern Authorization: Bearer uppsatt.

Utveckling av ett plugin för Grafana: en historia av stora skott

Utveckling av ett plugin för Grafana: en historia av stora skott

Naturligtvis behöver vi en anvÀndare med skrivskyddad Ätkomst för att arbeta med k8s API-server, manifesten för att skapa dessa finns ocksÄ i plugin-kÀllkod.

Del 5: SlÀpp

Utveckling av ett plugin för Grafana: en historia av stora skott

NÀr du vÀl har skrivit ditt eget Grafana-plugin vill du naturligtvis göra det med öppen kÀllkod. I Grafana Àr detta ett plugin-bibliotek, tillgÀngligt pÄ grafana.com/grafana/plugins

För att ditt plugin ska vara tillgÀngligt i den officiella butiken mÄste du göra en PR i detta förrÄd, lÀgger till innehÄll som detta i repo.json-filen:

Utveckling av ett plugin för Grafana: en historia av stora skott

dÀr version Àr versionen av ditt plugin, url Àr lÀnken till arkivet och commit Àr hashen för den commit som gör den specifika versionen av pluginet tillgÀnglig.

Och vid utgÄngen ser du en underbar bild som denna:

Utveckling av ett plugin för Grafana: en historia av stora skott

Data för den hÀmtas automatiskt frÄn dina Readme.md-, Changelog.md- och plugin.json-filer med plugin-beskrivningen.

Del 6: IstÀllet för slutsatser

Vi har inte slutat utveckla vĂ„rt plugin efter lanseringen. Och nu arbetar vi med korrekt övervakning av resursanvĂ€ndningen för klusternoder, implementerar nya funktioner för att förbĂ€ttra anvĂ€ndarupplevelsen och bearbetar Ă€ven en stor mĂ€ngd feedback som vi fĂ„tt efter plugininstallationer, bĂ„de frĂ„n vĂ„ra kunder och frĂ„n förfrĂ„gningar pĂ„ GitHub (om ni lĂ€mnar ert Ă€rende eller pull request blir jag vĂ€ldigt glad 🙂).

Vi hoppas att den hÀr artikeln hjÀlper dig att förstÄ ett sÄ fantastiskt verktyg som Grafana och kanske skriva ditt eget plugin.

Tack!)

KĂ€lla: will.com

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