Hej alla! För några månader sedan lanserade vi vårt nya open source-projekt i produktion - Grafana-plugin för övervakning av kubernetes, som vi kallade
Del 0 - inledning: hur kom vi till denna punkt?
Idén att skriva ett eget plugin för Grafan kom till oss av en slump. Vårt företag har övervakat webbprojekt av olika komplexitetsnivåer i mer än 10 år. Under denna tid har vi samlat på oss en stor mängd expertis, intressanta fall och erfarenhet av att använda olika övervakningssystem. Och vid något tillfälle frågade vi oss själva: "Finns det ett magiskt verktyg för att övervaka Kubernetes, så att, som de säger, "ställ in det och glöm det"?"... Branschstandarden för att övervaka k8s har naturligtvis länge varit Prometheus + Grafana kombination. Och som färdiga lösningar för denna stack finns det en stor uppsättning olika typer av verktyg: prometheus-operator, en uppsättning kubernetes-mixin-dashboards, grafana-kubernetes-app.
Insticksprogrammet grafana-kubernetes-app verkade vara det mest intressanta alternativet för oss, men det har inte stötts på mer än ett år och kan dessutom inte fungera med nya versioner av node-exporter och kube-state-metrics. Och vid något tillfälle bestämde vi oss: "Ska vi inte fatta vårt eget beslut?"
Vilka idéer vi bestämde oss för att implementera i vårt plugin:
- visualisering av "applikationskartan": bekväm presentation av applikationer i klustret, grupperade efter namnrymder, distributioner...;
- visualisering av anslutningar som "deployment - service (+ports)".
- visualisering av fördelningen av klusterapplikationer över klusternoder.
- insamling av mätvärden och information från flera källor: Prometheus och k8s api-server.
- övervakning av både infrastrukturdelen (användning av CPU-tid, minne, diskdelsystem, nätverk) och applikationslogik - hälsostatuspods, antal tillgängliga repliker, information om att klara liveness/readyness-tester.
Del 1: Vad är ett "Grafana-plugin"?
Ur teknisk synvinkel är plugin för Grafana en vinkelstyrenhet, som lagras i Grafanas datakatalog (/var/grafana/plugins/ /dist/module.js) och kan laddas som en SystemJS-modul. Även i den här katalogen bör det finnas en plugin.json-fil som innehåller all metainformation om din plugin: namn, version, plugin-typ, länkar till arkivet/webbplatsen/licensen, beroenden och så vidare.
module.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 - det är en panel för att visualisera alla mätvärden, som används för att bygga olika instrumentpaneler.
datakälla: plugin-anslutning till någon datakälla (till exempel Prometheus-datakälla, ClickHouse-datakälla, ElasticSearch-datakälla).
app: Ett plugin som låter dig bygga din egen frontend-applikation inuti Grafana, skapa dina egna html-sidor och manuellt komma åt datakällan för att visualisera olika data. Även plugins av andra typer (datakälla, panel) och olika instrumentpaneler kan användas som beroenden.
Exempel på plugin-beroenden med type=app.
Du kan använda både JavaScript och TypeScript som programmeringsspråk (vi valde det). Förberedelser för hello-world plugins av vilken typ du kan
Del 2: förbereda den lokala miljön
För att arbeta med plugin-programmet behöver vi naturligtvis ett kubernetes-kluster med alla förinstallerade verktyg: prometheus, node-exporter, kube-state-metrics, grafana. Miljön bör ställas in snabbt, enkelt och naturligt, och för att säkerställa hot-reload bör Grafana-datakatalogen monteras direkt från utvecklarens maskin.
Det bekvämaste sättet, enligt vår mening, att arbeta lokalt med kubernetes är
Vårt sista minikube-lanseringsskript 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: faktisk utveckling
Objektmodell
Som förberedelse för att implementera pluginet bestämde vi oss för att beskriva alla grundläggande Kubernetes-entiteter som vi kommer att arbeta med i form av TypeScript-klasser: pod, deployment, daemonset, statefulset, jobb, cronjob, service, nod, namnområde. Var och en av dessa klasser ärver från den gemensamma BaseModel-klassen, som beskriver konstruktorn, destruktorn, metoderna för uppdatering och växling av synlighet. Var och en av klasserna beskriver kapslade relationer med andra entiteter, till exempel en lista med poddar för en entitet av typen distribution.
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 seters kan vi visa eller ställa in de entitetsmått vi behöver i en bekväm och läsbar form. Till exempel, formaterad 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
En lista över alla våra plugin-sidor beskrivs initialt i vår pluing.json i avsnittet beroenden:
I blocket för varje sida måste vi ange PAGE NAME (det kommer sedan att konverteras till en slug som den här sidan kommer att vara tillgänglig); namnet på den komponent som är ansvarig för driften av denna sida (listan över komponenter exporteras till module.ts); anger användarrollen för vilken arbete med den här sidan är tillgängligt och navigeringsinställningar för sidofältet.
I komponenten som är ansvarig för driften av sidan måste vi ställa in templateUrl och skicka sökvägen till html-filen med markup dit. Inuti styrenheten, genom beroendeinjektion, kan vi komma åt upp till två viktiga vinkeltjänster:
- backendSrv - en tjänst som ger interaktion med Grafana API-servern;
- datasourceSrv - en tjänst som tillhandahåller lokal interaktion med alla datakällor installerade i din Grafana (till exempel metoden .getAll() - returnerar 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 datakällan exakt samma plugin som alla andra: den har sin egen ingångspunkt module.js, det finns en fil med metainformation plugin.json. När vi utvecklar ett plugin med typ = 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 kommer datakällan med plugin-koden. Det är också nödvändigt att ha en config.html-mall och en ConfigCtrl-kontroller, som kommer att användas för datakällans instanskonfigurationssida och Datasource-kontrollanten, som implementerar logiken för din datakälla.
I insticksprogrammet KubeGraf, ur användargränssnittets synvinkel, är datakällan en instans av ett kubernetes-kluster som implementerar följande funktioner (källkod är tillgänglig
- samla in data från k8s api-server (får en lista över namnområden, distributioner...)
- proxyfö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 instrumentpaneler.
- uppdatering av data på statiska plugin-sidor (med en inställd uppdateringsfrekvens).
- bearbetar frågor för att generera ett mallblad i grafana-dashboards (metriFindQuery()-metoden)
- anslutningstest med det sista 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 en autentiserings- och auktoriseringsmekanism för datakällan. Vanligtvis kan vi ur lådan använda den inbyggda Grafana-komponenten datasourceHttpSettings för att konfigurera åtkomst till den slutliga datakällan. Med den här komponenten kan vi konfigurera åtkomst till http-datakällan genom att ange webbadressen och grundläggande autentiserings-/auktoriseringsinställningar: login-lösenord eller client-cert/client-key. För att implementera möjligheten att konfigurera åtkomst med hjälp av en bärartoken (de facto-standarden för k8s), var vi tvungna att göra lite justeringar.
För att lösa detta problem kan du använda den inbyggda Grafana "Plugin Routes"-mekanismen (mer information på
/api/v8/namespaces med rubriken Authorization: Bearer.
Naturligtvis, för att arbeta med k8s api-servern behöver vi en användare med skrivskyddad åtkomst, manifest för att skapa som du också kan hitta i
Del 5: release
När du väl har skrivit ditt eget Grafana-plugin, vill du naturligtvis göra det tillgängligt för allmänheten. I Grafana är detta ett bibliotek med plugins som är tillgängliga här
För att ditt plugin ska vara tillgängligt i den officiella butiken måste du göra en PR in
där version är versionen av ditt plugin, url är en länk till arkivet och commit är hashen för commit för vilken en specifik version av plugin kommer att vara tillgänglig.
Och vid utgången kommer du att se en underbar bild som:
Data för den kommer automatiskt att hämtas från din Readme.md, Changelog.md och plugin.json-filen med plugin-beskrivningen.
Del 6: istället för slutsatser
Vi slutade inte utveckla vårt plugin efter release. Och nu arbetar vi på att korrekt övervaka användningen av resurser för klusternoder, introducera nya funktioner för att förbättra UX och även samla in en stor mängd feedback som erhållits efter installation av plugin både av våra kunder och från personer på GitHub (om du lämnar din fråga eller pull-förfrågan, jag blir väldigt glad :)
Vi hoppas att den här artikeln kommer att hjälpa dig att förstå ett så underbart verktyg som Grafana och kanske skriva ditt eget plugin.
Tack!)
Källa: will.com