Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Kamusta kayong lahat! Ilang buwan na ang nakalipas, inilunsad namin ang aming bagong open-source na proyekto sa produksyon - ang Grafana plugin para sa pagsubaybay sa mga kubernetes, na tinawag naming DevOpsProdigy KubeGraf. Available ang source code ng plugin sa pampublikong imbakan sa GitHub. At sa artikulong ito gusto naming ibahagi sa iyo ang kuwento kung paano namin ginawa ang plugin, anong mga tool ang ginamit namin at anong mga pitfalls ang naranasan namin sa proseso ng pag-develop. Tara na!

Bahagi 0 - panimula: paano tayo nakarating sa puntong ito?

Ang ideya na magsulat ng aming sariling plugin para sa Grafan ay dumating sa amin nang hindi sinasadya. Ang aming kumpanya ay sinusubaybayan ang mga proyekto sa web ng iba't ibang antas ng pagiging kumplikado sa loob ng higit sa 10 taon. Sa panahong ito, nakaipon kami ng malaking bilang ng kadalubhasaan, mga kawili-wiling kaso, at karanasan sa paggamit ng iba't ibang sistema ng pagsubaybay. At sa isang punto ay tinanong namin ang aming sarili: "Mayroon bang magic tool para sa pagsubaybay sa Kubernetes, upang, tulad ng sinasabi nila, "itakda ito at kalimutan ito"?".. Ang pamantayan ng industriya para sa pagsubaybay sa mga k8, siyempre, ay matagal nang naging Prometheus + Grafana na kumbinasyon. At bilang mga handa na solusyon para sa stack na ito, mayroong isang malaking hanay ng iba't ibang uri ng mga tool: prometheus-operator, isang set ng kubernetes-mixin dashboard, grafana-kubernetes-app.

Ang grafana-kubernetes-app plugin ay tila ang pinaka-kagiliw-giliw na opsyon para sa amin, ngunit hindi ito suportado nang higit sa isang taon at, higit pa rito, hindi maaaring gumana sa mga bagong bersyon ng node-exporter at kube-state-metrics. At sa isang punto nagpasya kami: "Hindi ba dapat tayo ang gumawa ng sarili nating desisyon?"

Anong mga ideya ang napagpasyahan naming ipatupad sa aming plugin:

  • visualization ng "application map": maginhawang presentasyon ng mga application sa cluster, na nakapangkat ayon sa mga namespace, deployment...;
  • visualization ng mga koneksyon tulad ng "deployment - serbisyo (+ports)".
  • visualization ng pamamahagi ng mga cluster application sa mga cluster node.
  • koleksyon ng mga sukatan at impormasyon mula sa ilang mapagkukunan: Prometheus at k8s api server.
  • pagsubaybay sa parehong bahagi ng imprastraktura (paggamit ng oras ng CPU, memorya, subsystem ng disk, network) at lohika ng aplikasyon - mga pod na status sa kalusugan, bilang ng mga magagamit na replika, impormasyon tungkol sa pagpasa sa mga pagsubok sa pagiging aktibo/kahandaan.

Bahagi 1: Ano ang "Grafana plugin"?

Mula sa teknikal na pananaw, ang plugin para sa Grafana ay isang angular na controller, na nakaimbak sa direktoryo ng data ng Grafana (/var/grafana/plugins/ /dist/module.js) at maaaring i-load bilang isang SystemJS module. Gayundin sa direktoryo na ito ay dapat mayroong isang plugin.json file na naglalaman ng lahat ng meta impormasyon tungkol sa iyong plugin: pangalan, bersyon, uri ng plugin, mga link sa repositoryo/site/lisensya, dependencies, at iba pa.

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha
module.ts

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha
plugin.json

Gaya ng nakikita mo sa screenshot, tinukoy namin ang plugin.type = app. Dahil ang mga plugin para sa Grafana ay maaaring may tatlong uri:

panel: ang pinakakaraniwang uri ng plugin - ito ay isang panel para sa pagpapakita ng anumang sukatan, na ginagamit upang bumuo ng iba't ibang mga dashboard.
pinanggalingan ng Datos: plugin connector sa ilang data source (halimbawa, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
app: Isang plugin na nagbibigay-daan sa iyo na bumuo ng iyong sariling frontend na application sa loob ng Grafana, lumikha ng iyong sariling mga html na pahina at manu-manong i-access ang datasource upang mailarawan ang iba't ibang data. Gayundin, ang mga plugin ng iba pang mga uri (datasource, panel) at iba't ibang mga dashboard ay maaaring gamitin bilang mga dependency.

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha
Halimbawa ng mga dependency ng plugin na may type=app.

Maaari mong gamitin ang parehong JavaScript at TypeScript bilang isang programming language (pinili namin ito). Mga paghahanda para sa hello-world na mga plugin ng anumang uri na magagawa mo hanapin ang link: ang repositoryong ito ay naglalaman ng malaking bilang ng mga starter-pack (mayroong pang-eksperimentong halimbawa ng isang plugin sa React) na may mga paunang naka-install at naka-configure na mga tagabuo.

Bahagi 2: paghahanda ng lokal na kapaligiran

Upang gumana sa plugin, natural na kailangan namin ng kubernetes cluster kasama ang lahat ng mga na-preinstall na tool: prometheus, node-exporter, kube-state-metrics, grafana. Ang kapaligiran ay dapat na mai-set up nang mabilis, madali at natural, at upang matiyak ang mainit na pag-reload, dapat na direktang i-mount ang direktoryo ng data ng Grafana mula sa makina ng developer.

Ang pinaka-maginhawang paraan, sa aming opinyon, upang gumana nang lokal sa mga kubernetes ay minikube. Ang susunod na hakbang ay i-install ang kumbinasyon ng Prometheus + Grafana gamit ang prometheus-operator. SA Ang artikulong ito Ang proseso ng pag-install ng prometheus-operator sa minikube ay inilarawan nang detalyado. Upang paganahin ang pagtitiyaga, dapat mong itakda ang parameter pagpupursige: totoo sa charts/grafana/values.yaml file, idagdag ang sarili mong PV at PVC at tukuyin ang mga ito sa persistence.existingClaim parameter

Ang aming huling script ng paglulunsad ng minikube ay ganito:

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

Bahagi 3: aktwal na pag-unlad

Modelo ng bagay

Bilang paghahanda sa pagpapatupad ng plugin, nagpasya kaming ilarawan ang lahat ng mga pangunahing entity ng Kubernetes kung saan kami gagana sa anyo ng mga klase ng TypeScript: pod, deployment, daemonset, statefulset, trabaho, cronjob, serbisyo, node, namespace. Ang bawat isa sa mga klase na ito ay nagmamana mula sa karaniwang klase ng BaseModel, na naglalarawan sa constructor, destructor, mga pamamaraan para sa pag-update at paglipat ng visibility. Ang bawat isa sa mga klase ay naglalarawan ng mga nested na relasyon sa iba pang mga entity, halimbawa, isang listahan ng mga pod para sa isang entity ng uri ng deployment.

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

Sa tulong ng mga getter at setter, maaari naming ipakita o itakda ang mga sukatan ng entity na kailangan namin sa isang maginhawa at nababasang anyo. Halimbawa, ang na-format na output ng mga mailalaang cpu node:

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

Pahina

Ang isang listahan ng lahat ng aming mga pahina ng plugin ay unang inilarawan sa aming pluing.json sa seksyon ng dependencies:

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Sa block para sa bawat pahina dapat naming ipahiwatig ang PAGE NAME (ito ay mako-convert sa isang slug kung saan ang pahinang ito ay maa-access); ang pangalan ng sangkap na responsable para sa pagpapatakbo ng pahinang ito (ang listahan ng mga bahagi ay na-export sa module.ts); na nagpapahiwatig ng tungkulin ng user kung saan magagamit ang page na ito at mga setting ng navigation para sa sidebar.

Sa bahagi na responsable para sa pagpapatakbo ng pahina, dapat naming itakda ang templateUrl, na ipinapasa doon ang landas sa html file na may markup. Sa loob ng controller, sa pamamagitan ng dependency injection, maa-access namin ang hanggang sa 2 mahalagang angular na serbisyo:

  • backendSrv - isang serbisyo na nagbibigay ng pakikipag-ugnayan sa server ng Grafana API;
  • datasourceSrv - isang serbisyong nagbibigay ng lokal na pakikipag-ugnayan sa lahat ng datasource na naka-install sa iyong Grafana (halimbawa, ang .getAll() na paraan - nagbabalik ng listahan ng lahat ng naka-install na datasource; .get( ) - nagbabalik ng instance object ng isang partikular na datasource.

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Bahagi 4: pinagmumulan ng data

Mula sa pananaw ni Grafana, ang datasource ay eksaktong kapareho ng plugin tulad ng lahat ng iba pa: mayroon itong sariling entry point module.js, mayroong isang file na may meta information plugin.json. Kapag bumubuo ng isang plugin na may type = app, maaari kaming makipag-ugnayan sa parehong mga kasalukuyang datasource (halimbawa, prometheus-datasource) at sa aming sarili, na maaari naming i-store nang direkta sa direktoryo ng plugin (dist/datasource/*) o i-install bilang dependency. Sa aming kaso, ang datasource ay kasama ng plugin code. Kinakailangan din na magkaroon ng config.html template at ConfigCtrl controller, na gagamitin para sa datasource instance configuration page at Datasource controller, na nagpapatupad ng logic ng iyong datasource.

Sa KubeGraf plugin, mula sa user interface point of view, ang datasource ay isang instance ng kubernetes cluster na nagpapatupad ng mga sumusunod na kakayahan (source code ay available ΠΏΠΎ ссылкС):

  • pagkolekta ng data mula sa k8s api-server (pagkuha ng listahan ng mga namespace, deployment...)
  • mga kahilingan sa proxying sa prometheus-datasource (na pinipili sa mga setting ng plugin para sa bawat partikular na cluster) at pag-format ng mga tugon upang magamit ang data sa parehong mga static na page at sa mga dashboard.
  • pag-update ng data sa mga static na pahina ng plugin (na may nakatakdang refresh rate).
  • pagpoproseso ng mga query para makabuo ng template sheet sa grafana-dashboards (metriFindQuery() method)

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

  • pagsubok sa koneksyon sa huling k8s cluster.
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"};
       })
}

Ang isang hiwalay na kawili-wiling punto, sa aming opinyon, ay ang pagpapatupad ng isang authentication at authorization mechanism para sa datasource. Karaniwan, sa labas ng kahon, maaari naming gamitin ang built-in na Grafana component datasourceHttpSettings upang i-configure ang access sa huling data source. Gamit ang bahaging ito, maaari naming i-configure ang access sa http data source sa pamamagitan ng pagtukoy sa url at pangunahing mga setting ng pagpapatunay/awtorisasyon: login-password, o client-cert/client-key. Upang maipatupad ang kakayahang i-configure ang access gamit ang isang bearer token (ang de facto na pamantayan para sa mga k8), kinailangan naming gumawa ng kaunting pagsasaayos.

Upang malutas ang problemang ito, maaari mong gamitin ang built-in na Grafana na "Mga Ruta ng Plugin" (higit pang mga detalye sa opisyal na pahina ng dokumentasyon). Sa mga setting ng aming datasource, maaari kaming magdeklara ng isang hanay ng mga panuntunan sa pagruruta na ipoproseso ng grafana proxy server. Halimbawa, para sa bawat indibidwal na endpoint posibleng magtakda ng mga header o url na may posibilidad ng pag-templat, ang data na maaaring kunin mula sa jsonData at secureJsonData na mga patlang (para sa pag-iimbak ng mga password o token sa naka-encrypt na form). Sa aming halimbawa, ang mga query tulad ng /__proxy/api/v1/namespaces ay i-proxy sa url ng form
/api/v8/namespaces na may Authorization: Bearer header.

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Naturally, upang gumana sa k8s api server kailangan namin ng isang user na may readonly na access, na nagpapakita para sa paglikha na maaari mo ring mahanap sa source code ng plugin.

Part 5: release

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Kapag naisulat mo na ang sarili mong Grafana plugin, natural na gusto mong gawin itong available sa publiko. Sa Grafana ito ay isang library ng mga plugin na magagamit dito grafana.com/grafana/plugins

Upang maging available ang iyong plugin sa opisyal na tindahan, kailangan mong gumawa ng PR imbakan na itosa pamamagitan ng pagdaragdag ng nilalamang tulad nito sa repo.json file:

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

kung saan ang bersyon ay ang bersyon ng iyong plugin, ang url ay isang link sa repositoryo, at ang commit ay ang hash ng commit kung saan ang isang partikular na bersyon ng plugin ay magagamit.

At sa output makikita mo ang isang kahanga-hangang larawan tulad ng:

Pagbuo ng isang plugin para sa Grafana: isang kasaysayan ng malalaking kuha

Ang data para dito ay awtomatikong kukunin mula sa iyong Readme.md, Changelog.md at ang plugin.json file na may paglalarawan ng plugin.

Bahagi 6: sa halip na mga konklusyon

Hindi kami huminto sa pagbuo ng aming plugin pagkatapos ng paglabas. At ngayon ay nagsusumikap kami sa wastong pagsubaybay sa paggamit ng mga mapagkukunan ng mga cluster node, pagpapakilala ng mga bagong feature para mapahusay ang UX, at pagkuha din ng malaking halaga ng feedback na natanggap pagkatapos i-install ang plugin ng aming mga kliyente at mula sa mga tao sa GitHub (kung aalis ka ang iyong isyu o kahilingan sa paghila, ako ay magiging masaya :)

Inaasahan namin na ang artikulong ito ay makakatulong sa iyo na maunawaan ang napakagandang tool tulad ng Grafana at, marahil, isulat ang iyong sariling plugin.

Salamat!)

Pinagmulan: www.habr.com

Magdagdag ng komento