Razvoj plugina za Grafana: povijest naučenih lekcija

Pozdrav svima! Prije nekoliko mjeseci pokrenuli smo naš novi open-source projekt u produkciji — Grafana plugin za praćenje kubernetes, kojeg smo nazvali DevOpsProdigy KubeGraf. Izvorni kod plugina dostupan je u javnom repozitoriju na GitHubu. U ovom članku želimo podijeliti s vama priču o tome kako smo razvijali plugin, koje alate smo koristili i s kakvim smo se izazovima susreli tijekom razvoja. Krenimo!

Dio 0 — uvod: kako smo došli do ovoga?

Ideja da napisemo vlastiti plugin za Grafanu pojavila se sasvim slučajno. Naša kompanija više od 10 godina se bavi praćenjem web projekata različitih složenosti. Tijekom tog vremena stekli smo bogato iskustvo, zanimljive slučajeve i iskustva korištenja raznih sustava za praćenje. I u jednom trenutku postavili smo si pitanje: „Postoji li čarobni alat za praćenje Kubernetes-a, da, kako se kaže, 'instaliraš i zaboraviš'?”? Normativ za praćenje k8s već dugo je kombinacija Prometheus + Grafana. Kao gotova rješenja za ovaj stack postoji veliki broj različitih alata: prometheus-operator, set nadzornika kubernetes-mixin, grafana-kubernetes-app.

Najzanimljivija opcija za nas činila se plugin grafana-kubernetes-app, no nije podržana već više od godinu dana i, osim toga, ne može raditi s novim verzijama node-exportera i kube-state-metricsa. I u jednom trenutku odlučili smo: „Zašto ne bismo napravili svoje vlastito rješenje?”

Koje ideje smo odlučili realizirati u svom pluginu:

  • vizualizacija 'mape aplikacije': prikladno predstavljanje aplikacija u klasteru, grupiranih po namespace-ima, deployment-ima...;
  • vizualizacija odnosa tipa 'deployment — service (+ports)'.
  • vizualizacija raspodjele aplikacija klastera po nodovima klastera.
  • prikupljanje metrika i informacija iz više izvora: Prometheus i k8s API server.
  • praćenje kako infrastrukturnih dijelova (korištenje procesorskog vremena, memorije, diska, mreže), tako i logike aplikacija — health-status pod-ova, broj dostupnih replika, informacije o prolasku liveness/readyness provjera.

Dio 1: Što je 'plugin za Grafana'?

S tehničke točke gledišta, plugin za Grafanu — to je angular-kontroler, koji se čuva u data-direktoriju Grafane (/var/grafana/plugins/<your_plugin_name>/dist/module.js) lahko naložite tudi kot SystemJS modul. V tej mapi mora biti tudi datoteka plugin.json, ki vsebuje vse metapodatke o vašem vtičniku: ime, različica, tip vtičnika, povezave na repozitorij/spletno stran/licenco, odvisnosti in tako naprej.

Razvoj plugina za Grafana: povijest naučenih lekcija
module.ts

Razvoj plugina za Grafana: povijest naučenih lekcija
plugin.json

Kot je razvidno na zaslonu, smo navedli plugin.type = app. Vtičniki za Grafano so lahko treh vrst:

panel: najpogostejša vrsta vtičnikov — predstavlja panel za vizualizacijo različnih metrik, uporablja se za izdelavo različnih nadzornih plošč.
datasource: vtičnik-connector za katerikoli vir podatkov (na primer, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
app: vtičnik, ki vam omogoča, da zgradite svojo lastno aplikacijo za frontend znotraj Grafane, ustvarite svoje HTML strani in ročno dostopate do datasource za vizualizacijo različnih podatkov. Tudi vtičniki drugih vrst (datasource, panel) in različne nadzorne plošče se lahko uporabljajo kot odvisnosti.

Razvoj plugina za Grafana: povijest naučenih lekcija
Primer odvisnosti vtičnika tipa app.

Kot programski jezik lahko uporabite tako JavaScript kot TypeScript (mi smo se odločili za slednjega). Predloge za hello-world vtičnike katerega koli tipa lahko najdete na povezavi: v tem repozitoriju je predstavljen velik števil od starter-packov (tudi eksperimentalni primer vtičnika v React) s prednastavljenimi in konfiguriranimi gradbeniki.

Del 2: priprava lokalnega okolja

Za delo na vtičniku bomo seveda potrebovali kubernetes grozd z vsemi prednastavljenimi orodji: prometheus, node-exporter, kube-state-metrics, grafana. Okolje bi se moralo hitro, enostavno in nekonfliktno nastaviti, za zagotavljanje hot-reload pa mora biti data-map Grafane montažna neposredno z razvojne naprave.

Najbolj priročen način lokalnega dela z kubernetes se nam zdi minikube. Naslednji korak je namestitev povezave Prometheus + Grafana z uporabo prometheus-operator. V tem članku je podrobno opisan postopek namestitve prometheus-operator na minikube. Za omogočanje obstojnosti je potrebno nastaviti parameter persistence: true v datoteki charts/grafana/values.yaml, dodajte svoj lasten PV in PVC ter jih navedite v parametru persistence.existingClaim

Končni skript za zagon minikube je videti takole:

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

Dio 3: neposredno razvoj

Objektni model

Kao pripremu za implementaciju plugina, odlučili smo opisati sve osnovne entitete Kubernetes-a koje ćemo koristiti u obliku TypeScript klasa: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Svaka od ovih klasa nasleđuje zajedničku klasu BaseModel, u kojoj su opisani konstruktor, destruktor, metode za ažuriranje i prebacivanje vidljivosti. U svakoj od klasa su opisani ugniježdeni odnosi s drugim entitetima, na primer, lista podova za entitet tipa 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 = [];
   }
}

Pomoću getter-a i setter-a možemo prikazati ili postaviti potrebne metrikе entiteta na zgodan i čitljiv način. Na primer, formatirani prikaz allocatable cpu nod-a:

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

Stranice

Lista svih stranica našeg plugina prvobitno se opisuje u našem pluing.json u odeljku zavisnosti:

Razvoj plugina za Grafana: povijest naučenih lekcija

U bloku za svaku stranicu moramo navesti NAZIV STRANICE (koji će potom biti konvertovan u slug, pod kojim će ova stranica biti dostupna); naziv komponente koja je odgovorna za rad na ovoj stranici (lista komponenti se eksportuje u module.ts); navođenje uloge korisnika za koju je dostupno korišćenje ove stranice i podešavanja navigacije za bočnu traku.

U komponenti koja je odgovorna za rad na stranici, moramo postaviti templateUrl, predajući putanju do html datoteke sa markup-om. Unutar kontrolera, putem dependency injection-a, možemo dobiti pristup do 2 važna angular servisa:

  • backendSrv — servis koji omogućava interakciju s api-serverom Grafane;
  • datasourceSrv — servis koji omogućava lokalnu interakciju sa svim datasource-ima instaliranim u vašoj Grafani (na primer, metoda .getAll() — vraća listu svih instaliranih datasource-a; .get() — vraća objekat-instanac konkretnog datasource-a.

Razvoj plugina za Grafana: povijest naučenih lekcija

Razvoj plugina za Grafana: povijest naučenih lekcija

Razvoj plugina za Grafana: povijest naučenih lekcija

Dio 4: datasource

Z vidika Grafane, podatkovni vir je prav tako vtičnik kot kateri koli drugi: ima svoj vstopni modul module.js in datoteko z metainformacijami plugin.json. Pri razvoju vtičnika s tipom = app lahko komuniciramo tako z obstoječimi podatkovnimi viri (na primer prometheus-datasource) kot z lastnimi, ki jih lahko shranimo neposredno v direktorij vtičnika (dist/datasource/*) ali jih namestimo kot odvisnost. V našem primeru se podatkovni vir dostavi skupaj s kodo vtičnika. Prav tako je obvezna prisotnost predloge config.html in kontrolerja ConfigCtrl, ki se bosta uporabljala za konfiguracijsko stran instančnega podatkovnega vira ter kontrolerja Datasource, v katerem je implementirana logika delovanja vašega podatkovnega vira.

V vtičniku KubeGraf, z vidika uporabniškega vmesnika, podatkovni vir predstavlja instanco kubernetes grozda, v katerem so implementirane naslednje funkcionalnosti (izvorna koda je na voljo na povezavi):

  • pridobivanje podatkov iz api-serverja k8s (pridobitev seznama namespace-ov, deployment-ov…)
  • proksiranje zahtevkov v prometheus-datasource (ki se izbere v nastavitvah vtičnika za vsak konkretni grozd) in formatiranje odgovorov za uporabo podatkov tako na statičnih straneh kot na nadzornih ploščah.
  • posodabljanje podatkov na statičnih straneh vtičnika (z nastavljenim časom osveževanja).
  • obdelava zahtevkov za oblikovanje seznama predlog v grafana-nadzornih ploščah (metoda .metriFindQuery())

Razvoj plugina za Grafana: povijest naučenih lekcija

Razvoj plugina za Grafana: povijest naučenih lekcija

Razvoj plugina za Grafana: povijest naučenih lekcija

  • test povezave s končnim k8s grozdom.
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: "Z virom podatkov je vse v redu", title: "Uspeh"};
           } else {
               return {status: "error", message: "Vir podatkov ni v redu", title: "Napaka"};
           }
       }, error => {
           return {status: "error", message: "Vir podatkov ni v redu", title: "Napaka"};
       })
}

Zanimljiv aspekt, s našeg gledišta, je implementacija mehanizma autentifikacije i autorizacije za datasource. Obično, out-of-the-box, za postavljanje pristupa krajnjem izvoru podataka možemo koristiti ugrađenu komponentu Grafana — datasourceHttpSettings. Pomoću ove komponente možemo konfigurisati pristup http-izvoru podataka, navodeći url i osnovne postavke autentifikacije/autorization: korisničko ime-lozinka, ili client-cert/client-key. Da bismo omogućili podešavanje pristupa preko bearer tokena (de facto standard za k8s), morali smo malo „hemijati“.

Za rešavanje ovog zadatka može se iskoristiti ugrađeni mehanizam Grafana „Plugin Routes“ (više o tome na službenoj stranici dokumentacije). U postavkama našeg datasource-a možemo deklarisati skup pravila usmeravanja, koja će se obrađivati proxy-serverom grafana. Na primer, za svaki pojedinačni endpoint postoji mogućnost postavljanja zaglavlja ili url-a sa mogućnošću šablonizacije, podaci za koje mogu biti uzeti iz polja jsonData i secureJsonData (za čuvanje lozinki ili tokena u šifrovanom obliku). U našem primeru zahtevi ovog tipa /__proxy/api/v1/namespaces biće proxirani na url ovog tipa
/api/v1/namespaces uz postavljanje zaglavlja Authorization: Bearer.

Razvoj plugina za Grafana: povijest naučenih lekcija

Razvoj plugina za Grafana: povijest naučenih lekcija

Naravno, za rad sa api-serverom k8s nam je potreban korisnik sa readonly pristupima, manifesti za kreiranje kojeg možete pronaći i u izvornom kodu plugina.

Deo 5: izdanje

Razvoj plugina za Grafana: povijest naučenih lekcija

Nakon što napišete svoj vlastiti plugin za Grafana, naravno, poželećete da ga objavite javno. U Grafani postoji biblioteka plugina, dostupna na linku grafana.com/grafana/plugins

Da bi vaš plugin bio dostupan u zvaničnom prodavcu, potrebno je da napravite PR u ovu репозиторију, dodajući u fajl repo.json sadržaj ovakvog tipa:

Razvoj plugina za Grafana: povijest naučenih lekcija

gde version — verzija vašeg plugina, url — link ka репозиторији, a commit — hash commit-a, prema kojem će biti dostupna konkretna verzija plugina.

I na izlazu ćete videti sjajan prikaz ovog tipa:

Razvoj plugina za Grafana: povijest naučenih lekcija

Podaci za njega biće automatski prikupljeni iz vašeg Readme.md, Changelog.md i fajla plugin.json sa opisom plugina.

Deo 6: umesto zaključaka

Nismo prekinuli razvoj našeg dodatka nakon objave. Sada radimo na pravilnom praćenju korišćenja resursa čvorova klastera, implementaciji novih funkcija za poboljšanje UX-a, kao i na rešavanju velike količine povratnih informacija dobijenih nakon instalacija dodatka, kako od naših klijenata, tako i iz izveštaja na GitHub-u (ako ostavite svoje pitanje ili zahtev za povlačenje, biću veoma srećan 🙂 ).

Nadamo se da će vam ovaj članak pomoći da razumete ovaj divan alat kao što je Grafana i, možda, da napišete svoj vlastiti dodatak.

Hvala!)

Izvor: habr.com

Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki 🔥 Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki | ProHoster