Ahoj všichni! Před několika měsíci jsme uvedli do produkce náš nový open-source projekt — Grafana plugin pro monitoring Kubernetes, který jsme nazvali . Zdrojový kód pluginu je dostupný v . A v tomto článku bychom se s vámi chtěli podělit o příběh, jak jsme plugin vytvářeli, jaké nástroje jsme používali a s jakými překážkami jsme se během vývoje setkali. Jdeme na to!
Část 0 — úvod: jak jsme se k tomu dostali?
Myšlenka napsat vlastní plugin pro Grafanu nás napadla zcela náhodou. Naše společnost se již více než 10 let zabývá monitoringem webových projektů různé složitosti. Během této doby jsme nashromáždili bohaté zkušenosti, zajímavé případy a zkušenosti s různými monitorovacími systémy. A v určitém okamžiku jsme si položili otázku: „Existuje kouzelný nástroj pro monitoring Kubernetes, který by se dal „nainstalovat a zapomenout“?..“ Průmyslovým standardem pro monitoring k8s je samozřejmě už dlouho spojení Prometheus + Grafana. A pro tuto technologii existuje široká škála různých hotových nástrojů: prometheus-operator, sada dashboardů kubernetes-mixin, grafana-kubernetes-app.
Nejzajímavější možností pro nás se zdál plugin grafana-kubernetes-app, ale už více než rok není udržován a navíc neumí pracovat s novými verzemi node-exportera a kube-state-metrics. A v nějakém okamžiku jsme se rozhodli: „A neudělat si vlastní řešení?“
Jaké nápady jsme se rozhodli realizovat ve svém pluginu:
- vizualizace „mapy aplikace“: přehledné zobrazení aplikací v clusteru, uspořádaných podle namespace, deploymentů…;
- vizualizace vztahů typu „deployment — service (+ports)“.
- vizualizace rozložení aplikací clusteru po nodech clusteru.
- shromažďování metrik a informací z několika zdrojů: Prometheus a k8s API server.
- monitoring jak infrastrukturní části (využití procesorového času, paměti, diskového subsystému, sítě), tak logiky aplikací — health-status podů, počet dostupných replik, informace o provádění liveness/readiness testů.
Část 1: Co je to „plugin pro Grafanu“?
Z technického hlediska je plugin pro Grafanu angular-ovladač, který se ukládá do data adresáře Grafany (/var/grafana/plugins/<your_plugin_name>/dist/module.js) a může být načten jako SystemJS modul. Také v tomto adresáři by měl být soubor plugin.json, který obsahuje veškeré meta informace o vašem pluginu: název, verze, typ pluginu, odkazy na repozitář/web/license, závislosti a tak dále.

module.ts

plugin.json
Jak je vidět na screenshotu, uvedli jsme plugin.type = app. Pluginy pro Grafanu mohou mít tři typy:
panel: nejběžnější typ pluginů – představuje panel pro vizualizaci různých metrik, používá se pro vytváření různých dashboardů.
datasource: plugin-konektor k určitému zdroji dat (např. Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
app: plugin, který vám umožňuje vytvořit svou vlastní frontendovou aplikaci uvnitř Grafany, vytvářet vlastní html stránky a ručně se dotazovat na datasource pro vizualizaci různých dat. Také lze jako závislosti používat jiné typy pluginů (datasource, panel) a různé dashboardy.

Příklad závislostí pluginu s type = app.
Jako programovací jazyk je možné použít jak JavaScript, tak TypeScript (my jsme se rozhodli pro něj). Šablony pro hello-world pluginy jakéhokoli typu můžete : v tomto repozitáři je prezentováno velké množství starter-packů (je zde dokonce experimentální příklad pluginu na React) s předinstalovanými a nastavenými build systémy.
Část 2: příprava lokálního prostředí
Pro práci na pluginu budeme samozřejmě potřebovat Kubernetes klastr 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 bezstarostně, a pro zajištění hot-reload by měla být data directory Grafany připojena přímo z vývojářské stanice.
Nejlepším způsobem pro lokální práci s Kubernetes, podle našeho názoru, je . Dalším krokem je instalace spojení Prometheus + Grafana pomocí prometheus-operator. V je podrobně popsán proces instalace prometheus-operator na minikube. Pro zapnutí persistentnosti je nutné nastavit parametr persistence: true v souboru charts/grafana/values.yaml, přidat svůj vlastní PV a PVC a uvést je v parametru persistence.existingClaim
Náš finální spouštěcí skript pro 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: přímý vývoj
Objektový model
Jako přípravu na implementaci pluginu jsme se rozhodli popsat všechny základní entity Kubernetes, se kterými budeme pracovat, ve formě TypeScript tříd: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Každá z těchto tříd dědí od obecné třídy BaseModel, ve které jsou popsány konstruktor, destruktor, metody pro aktualizaci a přepínání viditelnosti. V každé z těchto tříd jsou popsány vnořené vztahy s jinými entitami, například seznam podů u entity typu deployment.
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 = [];
}
}Pomocí getterů a setterů můžeme zobrazit nebo nastavit potřebné metriky entit v pohodlném a čitelném formátu. Například naformátovaný výstup allocatable cpu nodu:
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šeho pluginu je původně popsán v našem pluing.json v sekci závislostí:

V bloku pro každou stránku musíme uvést NÁZEV STRÁNKY (ten bude pak převeden na slug, podle kterého bude tato stránka dostupná); název komponenty, která zajišťuje funkčnost této stránky (seznam komponentů je exportován v module.ts); specifikaci uživatelské role, pro kterou je práce s touto stránkou dostupná, a nastavení navigace pro postranní panel.
V komponentě, která zajišťuje funkčnost stránky, musíme nastavit templateUrl, kde předáme cestu k html souboru s rozložením. Uvnitř kontroleru, prostřednictvím dependency injection, získáme přístup k 2 důležitým angular službám:
- backendSrv — služba zajišťující interakci s api serverem Grafany;
- datasourceSrv — služba zajišťující lokální interakci se všemi datovými zdroji instalovanými ve vaší Grafaně (například metoda .getAll() — vrátí seznam všech nainstalovaných datových zdrojů; .get() — vrátí objekt-instantci konkrétního datového zdroje.



Část 4: datový zdroj
Z pohledu Grafany je datasource stejným typem pluginu jako všechny ostatní: má svůj vstupní bod module.js a soubor s metainformacemi plugin.json. Při vývoji pluginu s typem = app můžeme interagovat jak s již existujícími datasource (například prometheus-datasource), tak s našimi vlastními, které můžeme uložit přímo do adresáře pluginu (dist/datasource/*) nebo je instalovat jako závislost. V našem případě je datasource dodáván spolu s kódem pluginu. Také je nezbytné mít šablonu config.html a kontroler ConfigCtrl, které budou použity pro stránku konfigurace instance datasource a kontroler Datasource, ve kterém je implementována logika fungování vašeho datasource.
V pluginu KubeGraf, z pohledu uživatelského rozhraní, představuje datasource instanci kubernetes-clusteru, v němž jsou implementovány následující funkce (zdrojový kód je k dispozici ):
- získávání dat z api-serveru k8s (získání seznamu namespace, deployment...)
- proxyování požadavků na prometheus-datasource (který se vybírá 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 v dashboardech.
- aktualizace dat na statických stránkách pluginu (s nastaveným časovým intervalem obnovování).
- zpracování požadavků pro generování seznamu šablon v grafana-dashboards (metoda .metriFindQuery())



- testování připojení k cílovému k8s clusteru.
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: "Datasource je OK", title: "Úspěch"};
}else{
return {status: "error", message: "Datasource není OK", title: "Chyba"};
}
}, error => {
return {status: "error", message: "Datasource není OK", title: "Chyba"};
})
}Zajímavým aspektem je realizace mechanismu autentizace a autorizace pro datasource. Obvykle můžeme použít integrovanou komponentu Grafana — datasourceHttpSettings pro konfiguraci přístupu k cílovému datovému zdroji. Pomocí této komponenty můžeme nastavit přístup k http-datovému zdroji zadáním url a základních autentizačních/autorizacích nastavení: uživatelské jméno-heslo nebo client-cert/client-key. Aby bylo možné nastavit přístup pomocí bearer-tokenu (de facto standard pro k8s), muselo se trochu "pohrát".
K řešení tohoto úkolu lze použít integrovaný mechanismus Grafana „Plugin Routes“ (podrobněji na ). V nastavení našeho datasource můžeme deklarovat sadu pravidel směrování, která budou zpracovávána proxy serverem grafana. Například pro každý jednotlivý endpoint existuje možnost nastavit hlavičky nebo url s možností šablonování, přičemž data mohou být čerpána z polí jsonData a secureJsonData (pro uchování hesel nebo tokenů v zašifrované podobě). V našem příkladu budou požadavky ve formátu /__proxy/api/v1/namespaces procházet na url ve formátu
/api/v1/namespaces s nastavením hlavičky Authorization: Bearer.


Samozřejmě, pro práci s api serverem k8s potřebujeme uživatele s readonly přístupem, manifesty pro jeho vytvoření najdete také v .
Část 5: vydání

Po napsání vlastního pluginu pro Grafana se samozřejmě budete chtít o něj podělit s veřejností. V Grafana je knihovna pluginů dostupná na odkazu
Aby byl váš plugin dostupný v oficiálním obchodě, musíte vytvořit PR v , přidáním obsahu typu do souboru repo.json:

kde version — verze vašeho pluginu, url — odkaz na repozitář a commit — hash commitu, podle kterého bude dostupná konkrétní verze pluginu.
A na konci uvidíte úžasný obrázek ve formátu:

Data pro něj budou automaticky extrahována z vašeho 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. V současné době pracujeme na správném monitorování využití zdrojů uzlů clustera, implementaci nových funkcí pro zlepšení UX a řešíme velké množství zpětné vazby, kterou jsme obdrželi po instalaci pluginu, jak od našich klientů, tak ze záznamů na GitHubu (pokud zanecháte svůj issue nebo pull request, budu velmi rád 🙂 ).
Doufáme, že vám tento článek pomůže pochopit skvělý nástroj, jakým je Grafana, a možná napsat svůj vlastní plugin.
Děkujeme!)
Zdroj: habr.com
