{"id":52343,"date":"2019-11-06T00:00:00","date_gmt":"2019-11-05T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek"},"modified":"2020-02-18T14:00:02","modified_gmt":"2020-02-18T11:00:02","slug":"razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek","status":"publish","type":"post","link":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek","title":{"rendered":"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Salut tuturor! Cu c\u00e2teva luni \u00een urm\u0103, am lansat \u00een produc\u021bie noul nostru proiect open-source \u2014 un plugin Grafana pentru monitorizarea Kubernetes, pe care l-am numit <b><noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/grafana\/plugins\/devopsprodigy-kubegraf-app\">DevOpsProdigy KubeGraf<\/a><\/noindex><\/b>. Codul surs\u0103 al pluginului este disponibil \u00een <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/kubegraf\">repozitoriul public de pe GitHub<\/a><\/noindex>. Iar \u00een acest articol, dorim s\u0103 \u00eemp\u0103rt\u0103\u0219im cu voi povestea despre cum am creat pluginul, ce instrumente am folosit \u0219i cu ce obstacole ne-am confruntat \u00een procesul de dezvoltare. S\u0103 \u00eencepem!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h4>Partea 0 \u2014 introducere: cum am ajuns \u00een aceast\u0103 situa\u021bie?<\/h4>\n<p>\nIdeea de a scrie propriul nostru plugin pentru Grafana ne-a venit complet \u00eent\u00e2mpl\u0103tor. Compania noastr\u0103 se ocup\u0103 de mai bine de 10 ani cu monitorizarea proiectelor web de diferite niveluri de complexitate. \u00cen acest timp, am acumulat o mare expertiz\u0103, cazuri interesante \u0219i experien\u021b\u0103 \u00een utilizarea diferitelor sisteme de monitorizare. \u0218i, la un moment dat, ne-am pus \u00eentrebarea: \u201eExist\u0103 un instrument magic pentru monitorizarea Kubernetes, care pur \u0219i simplu s\u0103 poat\u0103 fi \u201einstalat \u0219i uitat\u201d?... Standardul industrial pentru monitorizarea k8s este, desigur, combina\u021bia Prometheus + Grafana. \u0218i pentru acest stack exist\u0103 o gam\u0103 larg\u0103 de instrumente gata de utilizare: prometheus-operator, seturi de tablouri kubernetes-mixin, grafana-kubernetes-app. <\/p>\n<p>Cel mai interesant dintre acestea pentru noi s-a dovedit a fi pluginul grafana-kubernetes-app, dar acesta nu a mai fost \u00eentre\u021binut de mai bine de un an \u0219i, \u00een plus, nu poate func\u021biona cu versiunile noi ale node-exporter \u0219i kube-state-metrics. \u0218i la un moment dat, am decis: \u201eS\u0103 nu facem oare o solu\u021bie proprie?\u201d<\/p>\n<p>Ce idei am decis s\u0103 implement\u0103m \u00een pluginul nostru:<\/p>\n<ul>\n<li>vizualizarea \u201ehart\u0103 a aplica\u021biei\u201d: o reprezentare convenabil\u0103 a aplica\u021biilor din cluster, grupate dup\u0103 namespaces, deployments\u2026;<\/li>\n<li>vizualizarea rela\u021biilor de tip \u201edeployment \u2014 service (+ports)\u201d.<\/li>\n<li>vizualizarea distribu\u021biei aplica\u021biilor din cluster pe nodurile clusterului.<\/li>\n<li>colectarea metricilor \u0219i a informa\u021biilor din mai multe surse: Prometheus \u0219i k8s api server.<\/li>\n<li>monitorizarea at\u00e2t a p\u0103r\u021bii infrastructurale (utilizarea timpului CPU, memorie, subsistem de stocare, re\u021bea), c\u00e2t \u0219i a logicii aplica\u021biilor \u2014 starea de s\u0103n\u0103tate a podurilor, num\u0103rul de replici disponibile, informa\u021bii despre trecerea testelor de liveness\/readyness.<\/li>\n<\/ul>\n<p><\/p>\n<h4>Partea 1: Ce este un \u201eplugin pentru Grafana\u201d?<\/h4>\n<p>\nDin punct de vedere tehnic, un plugin pentru Grafana este un controler angular, care este stocat \u00een directorul data al Grafana (<i>\/var\/grafana\/plugins\/&lt;your_plugin_name&gt;\/dist\/module.js<\/i>) \u0219i poate fi \u00eenc\u0103rcat ca modul SystemJS. De asemenea, \u00een acest director ar trebui s\u0103 existe un fi\u0219ier plugin.json, care s\u0103 con\u021bin\u0103 toate metainforma\u021biile despre pluginul dumneavoastr\u0103: numele, versiunea, tipul pluginului, linkurile c\u0103tre repository\/site\/licen\u021b\u0103, dependen\u021bele \u0219i a\u0219a mai departe.<\/p>\n<p><img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/5993fec77a3904ed8b9e19a5addbb6ea.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>module.ts<\/i><\/p>\n<p><img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/1e5b780837e5a9385e5e22a27d83f567.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>plugin.json<\/i><\/p>\n<p>Dup\u0103 cum se vede \u00een captur\u0103 de ecran, am specificat plugin.type = app. Deoarece pluginurile pentru Grafana pot fi de trei tipuri:<\/p>\n<p><b>panel<\/b>: cel mai comun tip de pluginuri \u2014 reprezint\u0103 un panou pentru vizualizarea unor metrici, utilizat pentru construirea diferitelor tablouri de bord.<br \/>\n<b>datasource<\/b>: plugin-conector pentru o surs\u0103 de date (de exemplu, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).<br \/>\n<b>app<\/b>: plugin care v\u0103 permite s\u0103 construi\u021bi propria aplica\u021bie frontend \u00een interiorul Grafana, s\u0103 crea\u021bi propriile pagini html \u0219i s\u0103 accesa\u021bi manual sursa de date pentru vizualizarea diferitelor date. De asemenea, pot fi utilizate ca dependen\u021be pluginuri de alte tipuri (datasource, panel) \u0219i diferite tablouri de bord.<\/p>\n<p><img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/3cd53c7c3a2635f3f20831d52198b5f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Exemplu de dependen\u021be ale pluginului cu type = app<\/i>.<\/p>\n<p>Ca limbaj de programare, se poate folosi at\u00e2t JavaScript, c\u00e2t \u0219i TypeScript (am ales s\u0103 ne oprim asupra acestuia). \u0218abloanele pentru pluginuri hello-world de orice tip le pute\u021bi <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CorpGlory\">g\u0103si la linkul<\/a><\/noindex>: \u00een acest repository este prezentat un num\u0103r mare de starter-pack-uri (exist\u0103 chiar \u0219i un exemplu experimental de plugin pe React) cu constructori preinstala\u021bi \u0219i configura\u021bi. <\/p>\n<h4>Partea 2: preg\u0103tirea mediului local<\/h4>\n<p>\nPentru a lucra la plugin, avem, desigur, nevoie de un cluster kubernetes cu toate instrumentele preinstalate: prometheus, node-exporter, kube-state-metrics, grafana. Mediul trebuie s\u0103 se configureze rapid, u\u0219or \u0219i f\u0103r\u0103 efort, iar pentru a asigura reload-ul rapid, directorul de date al Grafana trebuie s\u0103 fie montat direct de pe ma\u0219ina dezvoltatorului.<\/p>\n<p>Cel mai convenabil, din punctul nostru de vedere, mod de lucru local cu kubernetes este <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-minikube\/\">minikube<\/a><\/noindex>. Pasul urm\u0103tor este s\u0103 instal\u0103m combina\u021bia Prometheus + Grafana folosind prometheus-operator. \u00cen <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/faun\/trying-prometheus-operator-with-helm-minikube-b617a2dccfa3\">acest articol<\/a><\/noindex> este descris \u00een detaliu procesul de instalare a prometheus-operator pe minikube. Pentru a activa persisten\u021ba, trebuie s\u0103 instala\u021bi parametrul <i>persistence: true<\/i> \u00een fi\u0219ierul charts\/grafana\/values.yaml, s\u0103 ad\u0103uga\u021bi propriul dvs. PV \u0219i PVC \u0219i s\u0103 le specifica\u021bi \u00een parametrul persistence.existingClaim<\/p>\n<p>Scriptul final de lansare minikube arat\u0103 a\u0219a:<\/p>\n<pre><code class=\"plaintext\">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\nminikube mount \n\/home\/sergeisporyshev\/Projects\/Grafana:\/var\/grafana --gid=472 --uid=472 --9p-version=9p2000.L<\/code><\/pre>\n<p><\/p>\n<h4>Partea 3: dezvoltarea efectiv\u0103<\/h4>\n<p>\n<b>Modelul obiectelor<\/b><\/p>\n<p>Ca preg\u0103tire pentru implementarea plugin-ului, am decis s\u0103 descriem toate entit\u0103\u021bile de baz\u0103 Kubernetes cu care vom lucra sub form\u0103 de clase TypeScript: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Fiecare dintre aceste clase mo\u0219tene\u0219te de la clasa comun\u0103 BaseModel, care descrie constructorul, destructorul, metodele pentru actualizare \u0219i comutarea vizibilit\u0103\u021bii. \u00cen fiecare dintre clase sunt descrise rela\u021biile \u00eenn\u0103scute cu alte entit\u0103\u021bi, de exemplu, lista pod-urilor pentru entitatea de tip deployment.<\/p>\n<pre><code class=\"plaintext\">import {Pod} from \".\/pod\";\nimport {Service} from \".\/service\";\nimport {BaseModel} from '.\/traits\/baseModel';\n\nexport class Deployment extends BaseModel{\n   pods: Array;\n   services: Array;\n\n   constructor(data: any){\n       super(data);\n       this.pods = [];\n       this.services = [];\n   }\n}<\/code><\/pre>\n<p>\nFolosind getter-e \u0219i setter-e, putem afi\u0219a sau seta metricile necesare pentru entit\u0103\u021bi \u00eentr-un mod convenabil \u0219i lizibil. De exemplu, afi\u0219area formatat\u0103 a cpu-ului allocat nod-ului:<\/p>\n<pre><code class=\"plaintext\">get cpuAllocatableFormatted(){\n   let cpu = this.data.status.allocatable.cpu;\n   if(cpu.indexOf('m') &gt; -1){\n       cpu = parseInt(cpu)\/1000;\n   }\n   return cpu;\n}<\/code><\/pre>\n<p>\n<b>Pagini<\/b><\/p>\n<p>Lista tuturor paginilor plugin-ului nostru este descris\u0103 ini\u021bial \u00een pluing.json la sec\u021biunea de dependen\u021be:<\/p>\n<p><img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/b86c74839ad0d9c64b97ffc3f2a84bdf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00cen blocul pentru fiecare pagin\u0103, trebuie s\u0103 specific\u0103m DENUMIREA PAGINII (aceasta va fi ulterior convertit\u0103 \u00een slug, prin care pagina va fi accesibil\u0103); numele componentei responsabile pentru func\u021bionarea acestei pagini (lista componentelor este exportat\u0103 \u00een module.ts); specificarea rolului utilizatorului pentru care este disponibil\u0103 utilizarea acestei pagini \u0219i set\u0103rile de navigare pentru bara lateral\u0103. <\/p>\n<p>\u00cen componenta responsabil\u0103 pentru func\u021bionarea paginii, trebuie s\u0103 stabilim templateUrl, oferind calea c\u0103tre fi\u0219ierul html cu markup. \u00cen interiorul controller-ului, prin injec\u021bia de dependen\u021b\u0103, putem accesa 2 servicii Angular importante:<\/p>\n<ul>\n<li>backendSrv \u2014 serviciul care asigur\u0103 interac\u021biunea cu serverul API Grafana;<\/li>\n<li>datasourceSrv \u2014 serviciul care asigur\u0103 interac\u021biunea local\u0103 cu toate sursele de date instalate \u00een Grafana dvs. (de exemplu, metoda .getAll() \u2014 returneaz\u0103 lista tuturor surselor de date instalate; .get() \u2014 returneaz\u0103 obiectul-instan\u021b\u0103 al unei surse de date specifice.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/e616e74c2e31ca3a81b7ed91ca333208.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/5e1d45f570dda50774088405abb41c9f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/c072867623824e799518984c7b1bee93.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h4>Partea 4: sursa de date<\/h4>\n<p>\nDin perspectiva Grafana, un datasource este un plugin exact ca toate celelalte: are un punct de intrare, module.js, \u0219i un fi\u0219ier cu metainforma\u021bii, plugin.json. C\u00e2nd dezvolt\u0103m un plugin de tip app, putem interac\u021biona at\u00e2t cu datasource-urile existente (de exemplu, prometheus-datasource), c\u00e2t \u0219i cu cele proprii, pe care le putem stoca direct \u00een directorul plugin-ului (dist\/datasource\/*) sau le putem instala ca dependen\u021b\u0103. \u00cen cazul nostru, datasource-ul vine \u00eempreun\u0103 cu codul plugin-ului. Este, de asemenea, esen\u021bial s\u0103 existe un \u0219ablon config.html \u0219i un controler ConfigCtrl, care vor fi utiliza\u021bi pentru pagina de configurare a instan\u021bei datasource-ului \u0219i controlerul Datasource, \u00een care se implementeaz\u0103 logica de func\u021bionare a datasource-ului.<\/p>\n<p>\u00cen pluginul KubeGraf, din perspectiva interfe\u021bei utilizatorului, un datasource reprezint\u0103 o instan\u021b\u0103 a clusterei kubernetes, \u00een care sunt implementate urm\u0103toarele func\u021bionalit\u0103\u021bi (codul surs\u0103 este disponibil <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/kubegraf\/tree\/master\/src\/datasource\">la link<\/a><\/noindex>):<\/p>\n<ul>\n<li>preluarea datelor din api-server-ul k8s (ob\u021binerea listei de namespace-uri, deployment-uri\u2026)<\/li>\n<li>proxisarea cererilor c\u0103tre prometheus-datasource (care este ales \u00een set\u0103rile plugin-ului pentru fiecare cluster specific) \u0219i formatarea r\u0103spunsurilor pentru utilizarea datelor at\u00e2t \u00een paginile statice, c\u00e2t \u0219i \u00een panourile de bord.<\/li>\n<li>actualizarea datelor pe paginile statice ale plugin-ului (cu un interval de timp stabilit pentru refresh rate).<\/li>\n<li>prelucrarea cererilor pentru generarea listei de template-uri \u00een grafana-dashboards (metoda .metriFindQuery())<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/18159bbb41144ebceb457df28b35e7b1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/a62665b4409566fbe24f56f88a376d5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/7f2d61fce623ce2a3cf62feb6d0447ac.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>testarea conexiunii cu clusterul k8s final.<\/li>\n<\/ul>\n<pre><code class=\"plaintext\">testDatasource(){\n   let url = '\/api\/v1\/namespaces';\n   let _url = this.url;\n   if(this.accessViaToken)\n       _url += '\/__proxy';\n   _url += url;\n   return this.backendSrv.datasourceRequest({\n       url: _url,\n       method: \"GET\",\n       headers: {\"Content-Type\": 'application\/json'}\n   })\n       .then(response =&gt; {\n           if (response.status === 200) {\n               return {status: \"success\", message: \"Sursa de date este OK\", title: \"Succes\"};\n           }else{\n               return {status: \"error\", message: \"Sursa de date nu este OK\", title: \"Eroare\"};\n           }\n       }, error =&gt; {\n           return {status: \"error\", message: \"Sursa de date nu este OK\", title: \"Eroare\"};\n       })\n}<\/code><\/pre>\n<p>\nUn aspect deosebit de interesant, din punctul nostru de vedere, este realizarea mecanismului de autentificare \u0219i autorizare pentru datasource. De regul\u0103, din cutie pentru configurarea accesului la sursa final\u0103 de date putem utiliza componenta \u00eencorporat\u0103 Grafana \u2014 datasourceHttpSettings. Cu ajutorul acestei componente putem configura accesul la sursa de date http, specific\u00e2nd url-ul \u0219i set\u0103rile de baz\u0103 pentru autentificare\/autorizare: nume utilizator-parol\u0103 sau client-cert\/client-key. Pentru a implementa posibilitatea configur\u0103rii accesului prin bearer-token (standard de facto pentru k8s), a fost necesar s\u0103 \u201emanipul\u0103m\u201d pu\u021bin.<\/p>\n<p>Pentru rezolvarea acestei probleme, putem utiliza mecanismul \u00eencorporat Grafana \u201ePlugin Routes\u201d (mai multe detalii pe <noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/docs\/plugins\/developing\/auth-for-datasources\/\">pagina oficial\u0103 de documenta\u021bie<\/a><\/noindex>). \u00cen set\u0103rile datasource-ului nostru putem declara un set de reguli de rutare, care vor fi procesate de serverul proxy grafana. De exemplu, pentru fiecare endpoint \u00een parte exist\u0103 posibilitatea de a seta antete sau url-uri cu op\u021biuni de \u0219ablonare, datele pentru care pot fi preluate din c\u00e2mpurile jsonData \u0219i secureJsonData (pentru stocarea parolelor sau tokenurilor \u00eentr-o form\u0103 criptat\u0103). \u00cen exemplul nostru, solicit\u0103rile de tip <i>\/__proxy\/api\/v1\/namespaces<\/i> vor fi proxificate la un url de tip<br \/>\n\/api\/v1\/namespaces cu setarea antetului Authorization: Bearer.<\/p>\n<p><img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/ca73ff0fef62fba3edab7907c83639b6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/9dab7537d7ccba90c9fb62dfa70b9fe2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDesigur, pentru a lucra cu serverul api k8s avem nevoie de un utilizator cu acces de tip readonly, manifeste pentru crearea c\u0103ruia le pute\u021bi g\u0103si de asemenea \u00een <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/kubegraf\/tree\/master\/kubernetes\/\">codul surs\u0103 al pluginului<\/a><\/noindex>.<\/p>\n<h4>Partea 5: lansare<\/h4>\n<p>\n<img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/3991a5d412f362770157fc567bb8009c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDup\u0103 ce ve\u021bi scrie propriul dvs. plugin pentru Grafana, v\u0103 ve\u021bi dori cu siguran\u021b\u0103 s\u0103 \u00eel publica\u021bi \u00een mod deschis. \u00cen Grafana exist\u0103 o bibliotec\u0103 de pluginuri, disponibil\u0103 la adresa <noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/grafana\/plugins\">grafana.com\/grafana\/plugins<\/a><\/noindex> <\/p>\n<p>Pentru ca pluginul dvs. s\u0103 fie disponibil \u00een magazinul oficial, trebuie s\u0103 face\u021bi un PR \u00een <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/grafana\/grafana-plugin-repository\">acest repository<\/a><\/noindex>, ad\u0103ug\u00e2nd \u00een fi\u0219ierul repo.json un con\u021binut de tip:<\/p>\n<p><img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/160650bf37f8f2f3e12ef7dd291e90eb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nunde version \u2014 versiunea pluginului dvs., url \u2014 linkul c\u0103tre repository, iar commit \u2014 hash-ul commit-ului, pe baza c\u0103ruia va fi disponibil\u0103 versiunea specific\u0103 a pluginului. <\/p>\n<p>\u0218i la final ve\u021bi vedea o imagine minunat\u0103 de tip:<\/p>\n<p><img decoding=\"async\" alt=\"Dezvoltarea pluginului pentru Grafana: istoria ghinionului acumulat\" src=\"\/wp-content\/uploads\/2019\/11\/ff906396596e9c4c15c59f8d53555f52.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDatele pentru aceasta vor fi extrase automat din Readme.md, Changelog.md \u0219i fi\u0219ierul plugin.json cu descrierea pluginului.<\/p>\n<h4>Partea 6: \u00een loc de concluzii<\/h4>\n<p>\nNu am oprit dezvoltarea pluginului nostru dup\u0103 lansare. Acum lucr\u0103m la monitorizarea corect\u0103 a utiliz\u0103rii resurselor nodurilor din cluster, implementarea de noi func\u021bionalit\u0103\u021bi pentru \u00eembun\u0103t\u0103\u021birea experien\u021bei utilizatorului \u0219i, de asemenea, ne ocup\u0103m de o cantitate mare de feedback primit dup\u0103 instalarea pluginului de la clien\u021bii no\u0219tri, precum \u0219i din problemele raportate pe GitHub (dac\u0103 ne l\u0103sa\u021bi o problem\u0103 sau un pull request, voi fi foarte fericit \ud83d\ude42 ).<\/p>\n<p>Sper\u0103m c\u0103 acest articol v\u0103 va ajuta s\u0103 \u00een\u021belege\u021bi un instrument minunat precum Grafana \u0219i, poate, s\u0103 scrie\u021bi propriul plugin. <\/p>\n<p>Mul\u021bumesc!)<br \/>\n<br \/>Sursa: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/itsumma\/blog\/474500\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u043d\u0430\u0437\u0430\u0434 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b\u0438 \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d \u043d\u0430\u0448 \u043d\u043e\u0432\u044b\u0439 open-source \u043f\u0440\u043e\u0435\u043a\u0442 \u2014 Grafana-\u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 kubernetes, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0437\u0432\u0430\u043b\u0438 DevOpsProdigy KubeGraf. \u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u043d\u0430 GitHub. \u0410 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0432\u0430\u043c\u0438 \u0438\u0441\u0442\u043e\u0440\u0438\u0435\u0439 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0438 \u043f\u043b\u0430\u0433\u0438\u043d, \u043a\u0430\u043a\u0438\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0438 \u0441 \u043a\u0430\u043a\u0438\u043c\u0438 \u043f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u043c\u0438 \u043a\u0430\u043c\u043d\u044f\u043c\u0438 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-52343","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442!\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \u0434\u043b\u044f Grafana: \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043d\u0430\u0431\u0438\u0442\u044b\u0445 \u0448\u0438\u0448\u0435\u043a | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442!\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-11-05T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:00:02+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Dezvoltarea pluginului pentru Grafana: povestea gre\u0219elilor \u00eenv\u0103\u021bate | ProHoster","description":"Salut tuturor!","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \u0434\u043b\u044f Grafana: \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043d\u0430\u0431\u0438\u0442\u044b\u0445 \u0448\u0438\u0448\u0435\u043a | ProHoster","og:description":"\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442!","og:url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-11-05T21:00:00+00:00","article:modified_time":"2020-02-18T11:00:02+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"52343","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-24 03:18:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 20:45:28","updated":"2026-01-24 03:18:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/52343","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=52343"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/52343\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=52343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=52343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=52343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}