Vývoj pluginu pro Grafana: historie velkých záběrů

Ahoj všichni! Před pár měsíci jsme spustili do výroby náš nový open-source projekt - plugin Grafana pro monitorování kubernetes, který jsme nazvali DevOpsProdigy KubeGraf. Zdrojový kód pluginu je dostupný na veřejné úložiště na GitHubu. A v tomto článku se s vámi chceme podělit o příběh, jak jsme plugin vytvářeli, jaké nástroje jsme používali a na jaká úskalí jsme během vývoje narazili. Pojďme!

Část 0 - úvodní: jak jsme se dostali k tomuto bodu?

Nápad napsat vlastní plugin pro Grafan nás napadl zcela náhodou. Naše společnost již více než 10 let sleduje webové projekty různé úrovně složitosti. Za tuto dobu jsme nashromáždili velké množství odborných znalostí, zajímavých případů a zkušeností s používáním různých monitorovacích systémů. A v určitém okamžiku jsme se sami sebe zeptali: „Existuje kouzelný nástroj pro monitorování Kubernetes, takže, jak se říká, „nastav a zapomeň“?“. Průmyslovým standardem pro monitorování k8 je samozřejmě již dlouho Kombinace Prometheus + Grafana. A jako hotová řešení pro tento stack existuje velká sada různých druhů nástrojů: prometheus-operator, sada dashboardů kubernetes-mixin, grafana-kubernetes-app.

Jako nejzajímavější varianta se nám jevil plugin grafana-kubernetes-app, který však již více než rok není podporován a navíc neumí pracovat s novými verzemi node-exporter a kube-state-metrics. A v určitém okamžiku jsme se rozhodli: "Neměli bychom se rozhodnout sami?"

Jaké nápady jsme se rozhodli implementovat do našeho pluginu:

  • vizualizace „aplikační mapy“: pohodlná prezentace aplikací v clusteru, seskupených podle jmenných prostorů, nasazení...;
  • vizualizace spojení jako „nasazení – služba (+porty)“.
  • vizualizace distribuce klastrových aplikací mezi uzly klastru.
  • sběr metrik a informací z několika zdrojů: Prometheus a k8s api server.
  • monitorování jak části infrastruktury (využití CPU času, paměti, diskového subsystému, sítě), tak aplikační logiky - health-status pods, počet dostupných replik, informace o absolvování testů životnosti/připravenosti.

Část 1: Co je to „Grafana plugin“?

Z technického hlediska je plugin pro Grafana úhlový ovladač, který je uložen v datovém adresáři Grafana (/var/grafana/plugins/ /dist/module.js) a lze jej načíst jako modul SystemJS. Také v tomto adresáři by měl být soubor plugin.json obsahující všechny meta informace o vašem pluginu: název, verze, typ pluginu, odkazy na úložiště/stránku/licenci, závislosti atd.

Vývoj pluginu pro Grafana: historie velkých záběrů
modul.ts

Vývoj pluginu pro Grafana: historie velkých záběrů
plugin.json

Jak můžete vidět na snímku obrazovky, zadali jsme plugin.type = app. Protože pluginy pro Grafana mohou být tří typů:

panel: nejrozšířenější typ pluginu - je to panel pro vizualizaci libovolných metrik, sloužící k sestavování různých dashboardů.
zdroj dat: konektor pluginu k nějakému zdroji dat (například Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
aplikace: Plugin, který vám umožní vytvořit si vlastní frontendovou aplikaci v Grafaně, vytvořit si vlastní html stránky a ručně přistupovat ke zdroji dat pro vizualizaci různých dat. Jako závislosti lze také použít pluginy jiných typů (zdroj dat, panel) a různé dashboardy.

Vývoj pluginu pro Grafana: historie velkých záběrů
Příklad závislostí pluginu s type=app.

Jako programovací jazyk můžete použít JavaScript i TypeScript (vybrali jsme si jej). Přípravy na hello-world pluginy jakéhokoli typu najít odkaz: toto úložiště obsahuje velké množství startovacích balíčků (v Reactu je dokonce experimentální příklad pluginu) s předinstalovanými a nakonfigurovanými buildery.

Část 2: Příprava místního prostředí

K práci na pluginu přirozeně potřebujeme cluster kubernetes se všemi předinstalovanými nástroji: prometheus, node-exporter, kube-state-metrics, grafana. Prostředí by mělo být nastaveno rychle, snadno a přirozeně a pro zajištění hot-reload by měl být datový adresář Grafana připojen přímo z vývojářského stroje.

Nejpohodlnější způsob, jak pracovat lokálně s kubernetes, je podle našeho názoru minikube. Dalším krokem je instalace kombinace Prometheus + Grafana pomocí prometheus-operátor. V tento článek Podrobně je popsán proces instalace prometheus-operátora na minikube. Chcete-li povolit persistenci, musíte nastavit parametr vytrvalost: pravda v souboru charts/grafana/values.yaml přidejte vlastní PV a PVC a specifikujte je v parametru persistence.existingClaim

Náš finální spouštěcí skript minikube vypadá takto:

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

Část 3: skutečný vývoj

Objektový model

V rámci přípravy na implementaci pluginu jsme se rozhodli popsat všechny základní entity Kubernetes, se kterými budeme pracovat, formou TypeScript tříd: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Každá z těchto tříd dědí ze společné třídy BaseModel, která popisuje konstruktor, destruktor, metody pro aktualizaci a přepínání viditelnosti. Každá z tříd popisuje vnořené vztahy s jinými entitami, například seznam podů pro entitu typu nasazení.

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

Pomocí getterů a setterů můžeme zobrazit nebo nastavit potřebné metriky entity v pohodlné a čitelné podobě. Například formátovaný výstup alokovatelných uzlů CPU:

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

stránky

Seznam všech stránek našich pluginů je zpočátku popsán v našem souboru pluing.json v sekci závislostí:

Vývoj pluginu pro Grafana: historie velkých záběrů

V bloku pro každou stránku musíme uvést NÁZEV STRÁNKY (ten se pak převede na slug, pomocí kterého bude tato stránka přístupná); název komponenty zodpovědné za provoz této stránky (seznam komponent je exportován do module.ts); označující uživatelskou roli, pro kterou je práce s touto stránkou dostupná, a nastavení navigace pro postranní panel.

V komponentě zodpovědné za provoz stránky musíme nastavit templateUrl a předat tam cestu k html souboru s označením. Uvnitř ovladače můžeme prostřednictvím vkládání závislostí přistupovat až ke 2 důležitým úhlovým službám:

  • backendSrv - služba, která zajišťuje interakci se serverem Grafana API;
  • datasourceSrv – služba, která poskytuje místní interakci se všemi datovými zdroji nainstalovanými ve vaší Grafaně (například metoda .getAll() – vrací seznam všech nainstalovaných zdrojů dat; .get( ) - vrátí objekt instance konkrétního zdroje dat.

Vývoj pluginu pro Grafana: historie velkých záběrů

Vývoj pluginu pro Grafana: historie velkých záběrů

Vývoj pluginu pro Grafana: historie velkých záběrů

Část 4: Zdroj dat

Z pohledu Grafany je datasource úplně stejný plugin jako všechny ostatní: má svůj vlastní vstupní bod module.js, existuje soubor s metainformacemi plugin.json. Při vývoji pluginu s typem = app můžeme interagovat jak s existujícími datovými zdroji (například prometheus-datasource), tak s našimi vlastními, které můžeme uložit přímo do adresáře pluginu (dist/datasource/*) nebo nainstalovat jako závislost. V našem případě je zdroj dat dodáván s kódem pluginu. Je také nutné mít šablonu config.html a řadič ConfigCtrl, který bude použit pro konfigurační stránku instance zdroje dat a řadič Datasource, který implementuje logiku vašeho zdroje dat.

V pluginu KubeGraf je z pohledu uživatelského rozhraní zdrojem dat instance clusteru kubernetes, který implementuje následující schopnosti (zdrojový kód je k dispozici по ссылке):

  • shromažďování dat z k8s api-serveru (získávání seznamu jmenných prostorů, nasazení...)
  • proxy serverové požadavky na prometheus-datasource (který je vybrán v nastavení pluginu pro každý konkrétní cluster) a formátování odpovědí pro použití dat jak na statických stránkách, tak na dashboardech.
  • aktualizace dat na stránkách statických pluginů (s nastavenou obnovovací frekvencí).
  • zpracování dotazů pro generování šablony v grafana-dashboardech (metoda metriFindQuery())

Vývoj pluginu pro Grafana: historie velkých záběrů

Vývoj pluginu pro Grafana: historie velkých záběrů

Vývoj pluginu pro Grafana: historie velkých záběrů

  • test spojení s finálním clusterem k8s.
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"};
       })
}

Samostatným zajímavým bodem je podle našeho názoru implementace autentizačního a autorizačního mechanismu pro zdroj dat. Obvykle můžeme použít vestavěnou komponentu Grafana datasourceHttpSettings ke konfiguraci přístupu ke konečnému zdroji dat. Pomocí této komponenty můžeme nakonfigurovat přístup ke zdroji dat http zadáním adresy URL a základního nastavení autentizace/autorizace: login-password, nebo client-cert/client-key. Abychom mohli implementovat možnost konfigurovat přístup pomocí tokenu nosiče (de facto standard pro k8), museli jsme udělat malé úpravy.

K vyřešení tohoto problému můžete použít vestavěný mechanismus Grafana „Plugin Routes“ (více podrobností na oficiální dokumentační stránka). V nastavení našeho zdroje dat můžeme deklarovat sadu směrovacích pravidel, která bude zpracovávat grafana proxy server. Například pro každý jednotlivý koncový bod je možné nastavit hlavičky nebo url s možností šablonování, data pro ně lze přebírat z polí jsonData a secureJsonData (pro ukládání hesel nebo tokenů v zašifrované podobě). V našem příkladu jsou dotazy jako /__proxy/api/v1/namespaces bude přesměrován na adresu URL formuláře
/api/v8/namespaces s hlavičkou Authorization: Bearer.

Vývoj pluginu pro Grafana: historie velkých záběrů

Vývoj pluginu pro Grafana: historie velkých záběrů

Pro práci se serverem k8s api samozřejmě potřebujeme uživatele s přístupem pouze pro čtení, manifesty pro vytváření, které můžete také najít v zdrojový kód pluginu.

Část 5: vydání

Vývoj pluginu pro Grafana: historie velkých záběrů

Jakmile si napíšete svůj vlastní plugin Grafana, přirozeně jej budete chtít zpřístupnit veřejnosti. V Grafaně je to knihovna pluginů dostupných zde grafana.com/grafana/plugins

Aby byl váš plugin dostupný v oficiálním obchodě, musíte provést PR toto úložištěpřidáním obsahu, jako je tento, do souboru repo.json:

Vývoj pluginu pro Grafana: historie velkých záběrů

kde version je verze vašeho pluginu, url je odkaz na úložiště a commit je hash odevzdání, pro který bude k dispozici konkrétní verze pluginu.

A na výstupu uvidíte nádherný obrázek jako:

Vývoj pluginu pro Grafana: historie velkých záběrů

Data pro něj budou automaticky získána z vašeho souboru Readme.md, Changelog.md a souboru plugin.json s popisem pluginu.

Část 6: místo závěrů

Po vydání jsme nepřestali vyvíjet náš plugin. A nyní pracujeme na správném monitorování využití zdrojů uzlů clusteru, zavádění nových funkcí pro zlepšení uživatelského prostředí a také na shromažďování velkého množství zpětné vazby obdržené po instalaci pluginu jak od našich klientů, tak od lidí na GitHubu (pokud odejdete váš problém nebo žádost o stažení, budu velmi rád :)

Doufáme, že vám tento článek pomůže porozumět tak skvělému nástroji, jako je Grafana, a možná i napsat svůj vlastní plugin.

Děkuji!)

Zdroj: www.habr.com

Přidat komentář