{"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\/de\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek","title":{"rendered":"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Hallo zusammen! Vor einigen Monaten haben wir unser neues Open-Source-Projekt in die Produktion gebracht \u2013 ein Grafana-Plugin zur \u00dcberwachung von Kubernetes, das wir <b><noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/grafana\/plugins\/devopsprodigy-kubegraf-app\">DevOpsProdigy KubeGraf<\/a><\/noindex><\/b>genannt haben. Der Quellcode des Plugins ist in einem <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/kubegraf\">\u00f6ffentlichen Repository auf GitHub<\/a><\/noindex>verf\u00fcgbar. In diesem Artikel m\u00f6chten wir unsere Geschichte dar\u00fcber teilen, wie wir das Plugin erstellt haben, welche Werkzeuge wir verwendet haben und auf welche Stolpersteine wir w\u00e4hrend der Entwicklung gesto\u00dfen sind. Legen wir los!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h4>Teil 0 \u2013 Einleitung: Wie sind wir dazu gekommen?<\/h4>\n<p>\nDie Idee, unser eigenes Plugin f\u00fcr Grafana zu entwickeln, kam uns ganz zuf\u00e4llig. Unser Unternehmen besch\u00e4ftigt sich seit \u00fcber 10 Jahren mit der \u00dcberwachung von Webprojekten unterschiedlicher Komplexit\u00e4t. In dieser Zeit haben wir ein gro\u00dfes Ma\u00df an Expertise, interessante F\u00e4lle und Erfahrungen mit verschiedenen \u00dcberwachungssystemen gesammelt. Und irgendwann stellten wir uns die Frage: \u201eGibt es ein magisches Werkzeug zur \u00dcberwachung von Kubernetes, das man, wie man so sch\u00f6n sagt, \u201aeinmal aufstellt und vergisst\u2018?\u201c Der Standard f\u00fcr die \u00dcberwachung von k8s ist seit langem die Kombination Prometheus + Grafana. F\u00fcr diesen Stack gibt es eine gro\u00dfe Auswahl an verschiedenen Tools: prometheus-operator, eine Sammlung von Dashboards kubernetes-mixin, grafana-kubernetes-app. <\/p>\n<p>Die interessanteste Variante f\u00fcr uns schien das Plugin grafana-kubernetes-app zu sein, aber es wird seit \u00fcber einem Jahr nicht mehr unterst\u00fctzt und kann zudem nicht mit den neuen Versionen von node-exporter und kube-state-metrics arbeiten. Irgendwann entschieden wir uns: \u201eWarum nicht unser eigenes L\u00f6sung entwickeln?\u201c<\/p>\n<p>Welche Ideen wollten wir in unserem Plugin umsetzen:<\/p>\n<ul>\n<li>Visualisierung der \u201aAnwendungskarte\u2018: eine bequeme Darstellung der Anwendungen im Cluster, gruppiert nach Namespaces, Deployments\u2026;<\/li>\n<li>Visualisierung von Beziehungen wie \u201aDeployment \u2013 Service (+Ports)\u2018.<\/li>\n<li>Visualisierung der Verteilung von Anwendungen im Cluster auf den Knoten des Clusters.<\/li>\n<li>Sammeln von Metriken und Informationen aus mehreren Quellen: Prometheus und k8s API-Server.<\/li>\n<li>\u00dcberwachung sowohl des infrastrukturellen Anteils (Nutzung von CPU-Zeit, Speicher, Speichersystem, Netzwerk) als auch der Anwendungslogik \u2013 health-status der Pods, Anzahl der verf\u00fcgbaren Replikate, Informationen \u00fcber das Bestehen von Liveness-\/Readyness-Checks.<\/li>\n<\/ul>\n<p><\/p>\n<h4>Teil 1: Was ist ein \u201aPlugin f\u00fcr Grafana\u2018?<\/h4>\n<p>\nAus technischer Sicht ist ein Plugin f\u00fcr Grafana ein Angular-Controller, der im data-Verzeichnis von Grafana gespeichert wird (<i>\/var\/grafana\/plugins\/&lt;your_plugin_name&gt;\/dist\/module.js<\/i>) und kann als SystemJS-Modul geladen werden. Au\u00dferdem sollte in diesem Verzeichnis eine Datei plugin.json vorhanden sein, die alle Metainformationen \u00fcber Ihr Plugin enth\u00e4lt: Name, Version, Typ des Plugins, Links zu Repository\/Site\/Lizenz, Abh\u00e4ngigkeiten usw.<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" 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=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/1e5b780837e5a9385e5e22a27d83f567.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>plugin.json<\/i><\/p>\n<p>Wie auf dem Screenshot zu sehen, haben wir plugin.type = app angegeben. Plugins f\u00fcr Grafana k\u00f6nnen drei Arten haben:<\/p>\n<p><b>panel<\/b>: Der am weitesten verbreitete Plugintyp \u2013 stellt ein Panel zur Visualisierung von Metriken dar, das zur Erstellung verschiedener Dashboards verwendet wird.<br \/>\n<b>Datenquelle<\/b>: Ein Connector-Plugin zu einer Datenquelle (z. B. Prometheus-Datenquelle, ClickHouse-Datenquelle, ElasticSearch-Datenquelle).<br \/>\n<b>App<\/b>: Ein Plugin, das es Ihnen erm\u00f6glicht, Ihre eigene Frontend-Anwendung innerhalb von Grafana zu erstellen, eigene HTML-Seiten zu erstellen und manuell auf die Datenquelle zuzugreifen, um verschiedene Daten zu visualisieren. Zudem k\u00f6nnen als Abh\u00e4ngigkeiten Plugins anderer Typen (Datenquelle, Panel) und verschiedene Dashboards verwendet werden.<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/3cd53c7c3a2635f3f20831d52198b5f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Beispiel f\u00fcr Plugin-Abh\u00e4ngigkeiten mit type = app<\/i>.<\/p>\n<p>Als Programmiersprache k\u00f6nnen sowohl JavaScript als auch TypeScript verwendet werden (wir haben uns f\u00fcr Letzteres entschieden). Vorlagen f\u00fcr Hello-World-Plugins jeglicher Art k\u00f6nnen Sie <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CorpGlory\">unter dem folgenden Link finden<\/a><\/noindex>: In diesem Repository sind viele Starter-Packs vorhanden (es gibt sogar ein experimentelles Plugin-Beispiel auf React) mit vorinstallierten und konfigurierten Build-Tools. <\/p>\n<h4>Teil 2: Vorbereitung der lokalen Umgebung<\/h4>\n<p>\nF\u00fcr die Arbeit an dem Plugin ben\u00f6tigen wir nat\u00fcrlich einen Kubernetes-Cluster mit allen vorinstallierten Tools: Prometheus, Node-Exporter, Kube-State-Metrics, Grafana. Die Umgebung sollte schnell, einfach und unkompliziert eingerichtet werden k\u00f6nnen, und f\u00fcr die Gew\u00e4hrleistung von Hot-Reload sollte das Datenverzeichnis von Grafana direkt vom Entwicklungsrechner gemountet werden.<\/p>\n<p>Die bequemste lokale Arbeitsweise mit Kubernetes ist unserer Meinung nach <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-minikube\/\">minikube<\/a><\/noindex>. Im n\u00e4chsten Schritt installieren wir das Bundle Prometheus + Grafana mit Hilfe des Prometheus-Operators. In <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/faun\/trying-prometheus-operator-with-helm-minikube-b617a2dccfa3\">diesem Artikel<\/a><\/noindex> ist der Prozess zur Installation des Prometheus-Operators auf Minikube ausf\u00fchrlich beschrieben. Um Persistenz zu aktivieren, muss der Parameter <i>persistence: true<\/i> in der Datei charts\/grafana\/values.yaml festgelegt werden, ebenso m\u00fcssen Sie Ihren eigenen PV und PVC hinzuf\u00fcgen und diese im Parameter persistence.existingClaim angeben.<\/p>\n<p>Das endg\u00fcltige Skript zum Starten von Minikube sieht folgenderma\u00dfen aus:<\/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>Teil 3: Entwicklung<\/h4>\n<p>\n<b>Objektmodell<\/b><\/p>\n<p>Als Vorbereitung f\u00fcr die Implementierung des Plugins haben wir beschlossen, alle grundlegenden Kubernetes-Einheiten, mit denen wir arbeiten werden, in Form von TypeScript-Klassen zu beschreiben: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Jede dieser Klassen erbt von der gemeinsamen Klasse BaseModel, in der der Konstruktor, Destruktor und Methoden zur Aktualisierung und Sichtbarkeitswechsel beschrieben sind. In jeder der Klassen sind die eingebetteten Beziehungen zu anderen Entit\u00e4ten beschrieben, zum Beispiel die Liste der Pods bei der Entit\u00e4t des Typs 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>\nMit Hilfe von Getter und Setter k\u00f6nnen wir die ben\u00f6tigten Metriken der Entit\u00e4ten in einem praktischen und lesbaren Format ausgeben oder setzen. Zum Beispiel die formatierte Ausgabe des allocatable CPU der Node:<\/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>Seiten<\/b><\/p>\n<p>Die Liste aller Seiten unseres Plugins wird urspr\u00fcnglich in unserer pluing.json im Abschnitt Abh\u00e4ngigkeiten beschrieben:<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/b86c74839ad0d9c64b97ffc3f2a84bdf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIm Block f\u00fcr jede Seite m\u00fcssen wir den NAME DER SEITE angeben (dieser wird dann in einen Slug umgewandelt, \u00fcber den diese Seite verf\u00fcgbar sein wird); den Namen der Komponente, die f\u00fcr die Arbeit mit dieser Seite verantwortlich ist (Liste der Komponenten wird in module.ts exportiert); die Rolle des Benutzers, f\u00fcr den die Arbeit mit dieser Seite verf\u00fcgbar ist, und Einstellungen f\u00fcr die Navigation in der Seitenleiste. <\/p>\n<p>In der Komponente, die f\u00fcr die Arbeit mit der Seite verantwortlich ist, m\u00fcssen wir templateUrl festlegen und den Pfad zur html-Datei mit dem Markup \u00fcbergeben. Innerhalb des Controllers k\u00f6nnen wir durch Dependency Injection auf zwei wichtige Angular-Dienste zugreifen:<\/p>\n<ul>\n<li>backendSrv \u2014 Dienst, der die Interaktion mit dem API-Server von Grafana gew\u00e4hrleistet;<\/li>\n<li>datasourceSrv \u2014 Dienst, der die lokale Interaktion mit allen in Ihrer Grafana installierten Datenquellen erm\u00f6glicht (z. B. gibt die Methode .getAll() eine Liste aller installierten Datenquellen zur\u00fcck; .get() gibt das Objekt-Instanz einer bestimmten Datenquelle zur\u00fcck).<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/e616e74c2e31ca3a81b7ed91ca333208.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/5e1d45f570dda50774088405abb41c9f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/c072867623824e799518984c7b1bee93.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h4>Teil 4: Datenquelle<\/h4>\n<p>\nAus Sicht von Grafana stellt die Datenquelle ein Plugin dar, das genau wie alle anderen Plugins funktioniert: Es hat einen eigenen Einstiegspunkt module.js und eine Datei mit Metainformationen plugin.json. Bei der Entwicklung eines Plugins mit type = app k\u00f6nnen wir sowohl mit bestehenden Datenquellen (z.B. prometheus-datasource) als auch mit eigenen arbeiten, die wir direkt im Plugin-Verzeichnis (dist\/datasource\/*) speichern oder als Abh\u00e4ngigkeit installieren k\u00f6nnen. In unserem Fall wird die Datenquelle zusammen mit dem Plugin-Code bereitgestellt. Es ist auch erforderlich, ein Template config.html und den Controller ConfigCtrl zu haben, die f\u00fcr die Konfigurationsseite der Instanz der Datenquelle und den Controller Datasource verwendet werden, in dem die Logik f\u00fcr die Funktionsweise Ihrer Datenquelle implementiert ist.<\/p>\n<p>Im KubeGraf-Plugin stellt die Datenquelle aus Sicht der Benutzeroberfl\u00e4che eine Instanz eines Kubernetes-Clusters dar, in dem folgende Funktionen implementiert sind (der Quellcode ist verf\u00fcgbar <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/kubegraf\/tree\/master\/src\/datasource\">unter diesem Link<\/a><\/noindex>):<\/p>\n<ul>\n<li>Abrufen von Daten vom API-Server von k8s (Abrufen der Liste der Namespace, Deployments\u2026)<\/li>\n<li>Proxying von Anfragen an die prometheus-datasource (die in den Plugin-Einstellungen f\u00fcr jeden bestimmten Cluster ausgew\u00e4hlt wird) und das Formatieren von Antworten f\u00fcr die Verwendung der Daten sowohl in statischen Seiten als auch in Dashboards.<\/li>\n<li>Aktualisierung von Daten auf den statischen Seiten des Plugins (mit festgelegtem Refresh-Intervall).<\/li>\n<li>Verarbeitung von Anfragen zur Erstellung einer Template-Liste in Grafana-Dashboards (Methode .metriFindQuery())<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/18159bbb41144ebceb457df28b35e7b1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/a62665b4409566fbe24f56f88a376d5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/7f2d61fce623ce2a3cf62feb6d0447ac.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>Test der Verbindung mit dem endg\u00fcltigen k8s-Cluster.<\/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: \"Datenquelle ist OK\", title: \"Erfolg\"};\n           }else{\n               return {status: \"error\", message: \"Datenquelle ist nicht OK\", title: \"Fehler\"};\n           }\n       }, error =&gt; {\n           return {status: \"error\", message: \"Datenquelle ist nicht OK\", title: \"Fehler\"};\n       })\n}<\/code><\/pre>\n<p>\nEin interessanter Punkt ist unserer Meinung nach die Implementierung des Authentifizierungs- und Autorisierungsmechanismus f\u00fcr die Datenquelle. In der Regel k\u00f6nnen wir f\u00fcr die Konfiguration des Zugriffs auf die endg\u00fcltige Datenquelle das integrierte Grafana-Komponenten datasourceHttpSettings verwenden. Mit dieser Komponente k\u00f6nnen wir den Zugang zu einer HTTP-Datenquelle einrichten, indem wir die URL und die grundlegenden Authentifizierungs-\/Autorisierungseinstellungen angeben: Benutzername-Passwort oder client-cert\/client-key. Um die M\u00f6glichkeit zu realisieren, den Zugang \u00fcber ein Bearer-Token (de facto Standard f\u00fcr k8s) zu konfigurieren, musste man etwas \u201eherumexperimentieren\u201c.<\/p>\n<p>Zur L\u00f6sung dieser Aufgabe kann der integrierte Grafana-Mechanismus \u201ePlugin Routes\u201c verwendet werden (mehr dazu auf der <noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/docs\/plugins\/developing\/auth-for-datasources\/\">offiziellen Dokumentationsseite<\/a><\/noindex>). In den Einstellungen unserer Datenquelle k\u00f6nnen wir eine Reihe von Routing-Regeln deklarieren, die vom Proxy-Server Grafana verarbeitet werden. Beispielsweise besteht f\u00fcr jeden einzelnen Endpunkt die M\u00f6glichkeit, Header oder URLs mit der M\u00f6glichkeit zur Vorlagenbearbeitung festzulegen, wobei die Daten aus den Feldern jsonData und secureJsonData (zur Speicherung von Passw\u00f6rtern oder Tokens in verschl\u00fcsselter Form). In unserem Beispiel werden Anfragen in der Form <i>\/__proxy\/api\/v1\/namespaces<\/i> an URLs der Form<br \/>\n\/api\/v1\/namespaces mit dem Header Authorization: Bearer angeh\u00e4ngt.<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/ca73ff0fef62fba3edab7907c83639b6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/9dab7537d7ccba90c9fb62dfa70b9fe2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSelbstverst\u00e4ndlich ben\u00f6tigen wir f\u00fcr die Arbeit mit dem k8s-API-Server einen Benutzer mit Lesezugriff, dessen Manifestdateien Sie ebenfalls im <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/kubegraf\/tree\/master\/kubernetes\/\">Quellcode des Plugins<\/a><\/noindex>.<\/p>\n<h4>Teil 5: Ver\u00f6ffentlichung<\/h4>\n<p>\n<img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/3991a5d412f362770157fc567bb8009c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNachdem Sie Ihr eigenes Plugin f\u00fcr Grafana erstellt haben, m\u00f6chten Sie es nat\u00fcrlich der \u00d6ffentlichkeit zug\u00e4nglich machen. In Grafana gibt es eine Plugin-Bibliothek, die unter der URL <noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/grafana\/plugins\">grafana.com\/grafana\/plugins<\/a><\/noindex> <\/p>\n<p>verf\u00fcgbar ist. Damit Ihr Plugin im offiziellen Store verf\u00fcgbar ist, m\u00fcssen Sie einen PR in <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/grafana\/grafana-plugin-repository\">dieses Repository<\/a><\/noindex>, hinzuf\u00fcgen Sie den Inhalt in die Datei repo.json in der Form:<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/160650bf37f8f2f3e12ef7dd291e90eb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nwobei version die Version Ihres Plugins, url der Link zum Repository und commit der Hash des Commits ist, unter dem eine bestimmte Version des Plugins verf\u00fcgbar ist. <\/p>\n<p>Und am Ende sehen Sie ein wunderbares Bild wie folgt:<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte der gesammelten Erfahrungen\" src=\"\/wp-content\/uploads\/2019\/11\/ff906396596e9c4c15c59f8d53555f52.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDie Daten hierf\u00fcr werden automatisch aus Ihrer Readme.md, Changelog.md und der Datei plugin.json mit der Beschreibung des Plugins extrahiert.<\/p>\n<h4>Teil 6: anstelle von Schlussfolgerungen<\/h4>\n<p>\nWir haben die Entwicklung unseres Plugins nach dem Release nicht eingestellt. Momentan arbeiten wir an einer korrekten \u00dcberwachung der Ressourcennutzung der Clusterknoten, der Einf\u00fchrung neuer Funktionen zur Verbesserung der Benutzererfahrung sowie der Bearbeitung des umfangreichen Feedbacks, das wir nach den Installationen des Plugins von unseren Kunden und aus Issues auf GitHub erhalten haben (wenn Sie Ihr Issue oder Ihren Pull Request hinterlassen, w\u00e4re ich sehr gl\u00fccklich \ud83d\ude42 ).<\/p>\n<p>Wir hoffen, dass Ihnen dieser Artikel hilft, sich in diesem wunderbaren Tool wie Grafana zurechtzufinden und vielleicht sogar Ihr eigenes Plugin zu schreiben. <\/p>\n<p>Danke!)<br \/>\n<br \/>Quelle: <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.1.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\/de\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\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\/de\/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\udd47Entwicklung eines Plugins f\u00fcr Grafana: die Geschichte der gesammelten Erfahrungen | ProHoster","description":"Hallo zusammen!","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","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\/de\/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\/de\/wp-json\/wp\/v2\/posts\/52343","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=52343"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/52343\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=52343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=52343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=52343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}