Hoi allegearre! In pear moannen lyn lansearren wy ús nije iepen-boarne-projekt yn produksje - de Grafana-plugin foar it kontrolearjen fan kubernetes, dy't wy neamden . De plugin boarnekoade is beskikber by . En yn dit artikel wolle wy it ferhaal mei jo diele oer hoe't wy de plugin makken, hokker ark wy brûkten en hokker falkûlen wy tsjinkamen tidens it ûntwikkelingsproses. Litte wy gean!
Diel 0 - ynliedend: hoe binne wy op dit punt kommen?
It idee om ús eigen plugin foar Grafan te skriuwen kaam ta ús tafallich ta. Us bedriuw kontrolearret al mear dan 10 jier webprojekten fan ferskate kompleksiteitsnivo's. Yn dizze tiid hawwe wy in grutte hoemannichte saakkundigens, ynteressante gefallen en ûnderfining sammele yn it brûken fan ferskate tafersjochsystemen. En op in stuit fregen wy ússels ôf: "Is d'r in magysk ark foar it kontrolearjen fan Kubernetes, sadat, sa't se sizze, "set it en ferjit it"?". Prometheus + Grafana kombinaasje. En as klearmakke oplossingen foar dizze stapel is d'r in grutte set fan ferskate soarten ark: prometheus-operator, in set fan kubernetes-mixin-dashboards, grafana-kubernetes-app.
De plugin grafana-kubernetes-app like de meast nijsgjirrige opsje foar ús te wêzen, mar it is net mear as in jier stipe en kin boppedat net wurkje mei nije ferzjes fan node-eksporter en kube-state-metriken. En op in stuit besletten wy: "Moatte wy net ús eigen beslút nimme?"
Hokker ideeën hawwe wy besletten om te ymplementearjen yn ús plugin:
- fisualisaasje fan 'e "applikaasjekaart": handige presintaasje fan applikaasjes yn it kluster, groepeare troch nammeromten, ynset ...;
- fisualisaasje fan ferbiningen lykas "ynset - tsjinst (+ havens)".
- fisualisaasje fan de ferdieling fan klusterapplikaasjes oer klusterknooppunten.
- kolleksje fan metriken en ynformaasje út ferskate boarnen: Prometheus en k8s api tsjinner.
- tafersjoch op sawol de ynfrastruktuer diel (gebrûk fan CPU tiid, ûnthâld, skiif subsysteem, netwurk) en applikaasje logika - sûnens-status pods, oantal beskikbere replika's, ynformaasje oer it trochjaan fan liveness / ree tests.
Diel 1: Wat is in "Grafana-plugin"?
Fanút in technysk eachpunt is de plugin foar Grafana in hoekkontrôler, dy't wurdt opslein yn 'e Grafana-gegevensmap (/var/grafana/plugins/ /dist/module.js) en kin laden wurde as in SystemJS-module. Ek yn dizze map moat d'r in plugin.json-bestân wêze mei alle meta-ynformaasje oer jo plugin: namme, ferzje, plugin-type, keppelings nei de repository/side/lisinsje, ôfhinklikens, ensfh.

module.ts

plugin.json
Lykas jo kinne sjen yn 'e skermôfbylding, spesifisearre wy plugin.type = app. Om't plugins foar Grafana fan trije soarten kinne wêze:
paniel: it meast foarkommende type plugin - it is in paniel foar it visualisearjen fan alle metriken, brûkt om ferskate dashboards te bouwen.
gegevensboarne: plugin-ferbining nei guon gegevensboarne (bygelyks Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
app: In plugin wêrmei jo jo eigen frontend-applikaasje yn Grafana kinne bouwe, jo eigen html-siden meitsje en manuell tagong krije ta de gegevensboarne om ferskate gegevens te visualisearjen. Ek kinne plugins fan oare soarten (databoarne, paniel) en ferskate dashboards brûkt wurde as ôfhinklikens.

Foarbyld plugin-ôfhinklikens mei type=app.
Jo kinne sawol JavaScript as TypeScript brûke as programmeartaal (wy hawwe it keazen). Tariedings foar hello-world plugins fan elk type dat jo kinne : dit repository befettet in grut oantal starterspakketten (d'r is sels in eksperiminteel foarbyld fan in plugin yn React) mei foarôf ynstalleare en konfigureare bouwers.
Diel 2: tariede de pleatslike omjouwing
Om oan it plugin te wurkjen, hawwe wy fansels in kubernetes-kluster nedich mei alle foarynstalleare ark: prometheus, node-eksporter, kube-state-metrics, grafana. De omjouwing moat fluch, maklik en natuerlik ynsteld wurde, en om hot-reload te garandearjen, moat de Grafana-gegevensmap direkt fan 'e masine fan' e ûntwikkelders monteare wurde.
De meast handige manier, neffens ús, om lokaal te wurkjen mei kubernetes is . De folgjende stap is om de kombinaasje Prometheus + Grafana te ynstallearjen mei prometheus-operator. YN It proses fan it ynstallearjen fan prometheus-operator op minikube wurdt yn detail beskreaun. Om persistinsje yn te skeakeljen, moatte jo de parameter ynstelle persistinsje: wier yn 'e charts/grafana/values.yaml-bestân, foegje jo eigen PV en PVC ta en spesifisearje se yn 'e parameter persistence.existingClaim
Us lêste minikube-lanseringsskript sjocht der sa út:
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.LDiel 3: eigentlike ûntwikkeling
Objekt Model
As tarieding op it ymplementearjen fan it plugin hawwe wy besletten alle basis Kubernetes-entiteiten te beskriuwen wêrmei wy sille wurkje yn 'e foarm fan TypeScript-klassen: pod, ynset, daemonset, statefulset, job, cronjob, tsjinst, knooppunt, nammeromte. Elk fan dizze klassen erft út de mienskiplike BaseModel klasse, dy't beskriuwt de constructor, destructor, metoaden foar it bywurkjen en wikseljen sichtberens. Elk fan 'e klassen beskriuwt geneste relaasjes mei oare entiteiten, Bygelyks, in list fan pods foar in entiteit fan type ynset.
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 = [];
}
}Mei help fan getters en setters kinne wy de entiteitsmetriken werjaan of ynstelle dy't wy nedich binne yn in handige en lêsbere foarm. Bygelyks, opmakke útfier fan allocateable cpu-knooppunten:
get cpuAllocatableFormatted(){
let cpu = this.data.status.allocatable.cpu;
if(cpu.indexOf('m') > -1){
cpu = parseInt(cpu)/1000;
}
return cpu;
}siden
In list fan al ús plugin-siden wurdt yn earste ynstânsje beskreaun yn ús pluing.json yn 'e seksje ôfhinklikens:

Yn it blok foar elke side moatte wy de PAGE NAME oanjaan (dy wurdt dan omset yn in slug wêrmei dizze side tagonklik is); de namme fan 'e komponint ferantwurdlik foar de wurking fan dizze side (de list mei komponinten wurdt eksportearre nei module.ts); de brûkersrol oanjaan wêrfoar wurk mei dizze side beskikber is en navigaasjeynstellingen foar de sydbalke.
Yn de komponint ferantwurdlik foar de wurking fan de side, wy moatte ynstelle templateUrl, trochjaan dêr it paad nei de html triem mei markup. Binnen de controller kinne wy fia ôfhinklikensynjeksje tagong krije ta maksimaal 2 wichtige hoektsjinsten:
- backendSrv - in tsjinst dy't ynteraksje leveret mei de Grafana API-tsjinner;
- datasourceSrv - in tsjinst dy't lokale ynteraksje leveret mei alle gegevensboarnen ynstalleare yn jo Grafana (bygelyks de .getAll() metoade - jout in list werom mei alle ynstallearre gegevensboarnen; .get( ) - jout in eksimplaarobjekt werom fan in spesifike gegevensboarne.



Diel 4: gegevensboarne
Ut Grafana syn eachpunt, datasource is krekt deselde plugin as alle oaren: it hat in eigen yngong punt module.js, der is in triem mei meta ynformaasje plugin.json. By it ûntwikkeljen fan in plugin mei type = app, kinne wy ynteraksje mei sawol besteande gegevensboarnen (bygelyks prometheus-datasource) en ús eigen, dy't wy direkt kinne opslaan yn 'e plugin-map (dist/datasource/*) of ynstallearje as ôfhinklikens. Yn ús gefal komt de gegevensboarne mei de plugin-koade. It is ek nedich om in config.html-sjabloan en in ConfigCtrl-controller te hawwen, dy't brûkt wurde foar de konfiguraasjeside fan gegevensboarneeksimplaar en de databoarnekontrôler, dy't de logika fan jo gegevensboarne ymplemintearret.
Yn it KubeGraf-plugin, út it eachpunt fan 'e brûkersynterface, is de gegevensboarne in eksimplaar fan in kubernetes-kluster dat de folgjende mooglikheden ymplemintearret (boarnekoade is beskikber ):
- gegevens sammelje fan 'e k8s api-server (in list krije mei nammeromten, ynset ...)
- proxying fersiken nei prometheus-datasource (dy't selektearre is yn 'e plugin-ynstellingen foar elke spesifike kluster) en opmaak fan antwurden om gegevens te brûken sawol yn statyske siden as yn dashboards.
- it bywurkjen fan gegevens op statyske plugin-siden (mei in ynstelde ferfarskingsfrekwinsje).
- ferwurkjen fan queries om in sjabloanblêd te generearjen yn grafana-dashboards (metriFindQuery () metoade)



- ferbining test mei de finale k8s kluster.
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"};
})
}In apart nijsgjirrich punt, nei ús miening, is de ymplemintaasje fan in autentikaasje- en autorisaasjemeganisme foar de gegevensboarne. Typysk, bûten it fak kinne wy de ynboude Grafana-komponint datasourceHttpSettings brûke om tagong ta de definitive gegevensboarne te konfigurearjen. Mei dizze komponint kinne wy tagong ta de http-gegevensboarne konfigurearje troch de url en de basisynstellingen foar ferifikaasje/autorisaasje op te jaan: login-wachtwurd, of client-cert/client-key. Om de mooglikheid te ymplementearjen om tagong te konfigurearjen mei in drager token (de de facto standert foar k8s), moasten wy in bytsje oanpassing dwaan.
Om dit probleem op te lossen, kinne jo it ynboude Grafana "Plugin Routes"-meganisme brûke (mear details op ). Yn 'e ynstellings fan ús gegevensboarne kinne wy in set routingregels ferklearje dy't sille wurde ferwurke troch de grafana proxy-tsjinner. Bygelyks, foar elk yndividueel einpunt is it mooglik om kopteksten of URL's yn te stellen mei de mooglikheid fan sjabloanen, gegevens wêrfoar kinne wurde nommen út 'e jsonData en secureJsonData fjilden (foar it bewarjen fan wachtwurden of tokens yn fersifere foarm). Yn ús foarbyld, queries lykas /__proxy/api/v1/namespaces wurdt proksearre nei de url fan it formulier
/api/v8/namespaces mei de Autorisaasje: Bearer-koptekst.


Fansels, om te wurkjen mei de k8s api-tsjinner, hawwe wy in brûker nedich mei allinich lêzen tagong, manifesten foar it meitsjen dy't jo ek kinne fine yn .
Diel 5: frijlitting

As jo ienris jo eigen Grafana-plugin skreaun hawwe, wolle jo it fansels iepenbier beskikber meitsje. Yn Grafana is dit in bibleteek fan plugins beskikber hjir
Om jo plugin te krijen yn 'e offisjele winkel, moatte jo in PR yn meitsje troch ynhâld lykas dit ta te foegjen oan it repo.json-bestân:

wêr't ferzje de ferzje fan jo plugin is, url is in keppeling nei it repository, en commit is de hash fan 'e commit wêrfoar in spesifike ferzje fan 'e plugin beskikber is.
En by de útfier sille jo in prachtige foto sjen lykas:

De gegevens dêrfoar wurde automatysk pakt fan jo Readme.md, Changelog.md en it plugin.json-bestân mei de plugin-beskriuwing.
Diel 6: ynstee fan konklúzjes
Wy binne net ophâlden mei it ûntwikkeljen fan ús plugin nei frijlitting. En no wurkje wy oan it korrekt kontrolearjen fan it gebrûk fan boarnen fan klusterknooppunten, nije funksjes yntrodusearje om UX te ferbetterjen, en ek in grutte hoemannichte feedback ophelje dy't ûntfongen is nei it ynstallearjen fan de plugin sawol troch ús kliïnten as fan minsken op GitHub (as jo fuortgean) jo kwestje of lûkfersyk, ik sil heul bliid wêze :)
Wy hoopje dat dit artikel jo sil helpe om sa'n prachtich ark as Grafana te begripen en, miskien, jo eigen plugin te skriuwen.
Dankewol!)
Boarne: www.habr.com
