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 KĂ€llkoden för plugin-programmet finns tillgĂ€nglig i Och 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.

modul.ts

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.

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 Detta 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 NÀsta steg Àr att installera Prometheus + Grafana-paketet med hjÀlp av prometheus-operator. 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.LDel 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:

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.



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())



- 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Ä I 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.


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 .
Del 5: SlÀpp

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Ä
För att ditt plugin ska vara tillgÀngligt i den officiella butiken mÄste du göra en PR i , lÀgger till innehÄll som detta i repo.json-filen:

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:

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
