{"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 von Fehlschl\u00e4gen","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 \u00fcber die Entwicklung des Plugins teilen, welche Werkzeuge wir verwendet haben und auf welche Stolpersteine wir w\u00e4hrend der Entwicklung gesto\u00dfen sind. Los geht's!<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, ein eigenes Plugin f\u00fcr Grafana zu entwickeln, entstand bei 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 umfangreiches Fachwissen, interessante Fallstudien und Erfahrungen mit verschiedenen \u00dcberwachungssystemen gesammelt. Irgendwann stellten wir uns die Frage: \u201eGibt es ein magisches Werkzeug zur \u00dcberwachung von Kubernetes, das, wie man so sch\u00f6n sagt, \u201aeinfach eingerichtet und vergessen\u2018 werden kann?\u201c Der Standard f\u00fcr die \u00dcberwachung von k8s ist seit langem die Kombination aus Prometheus und Grafana. F\u00fcr dieses Stack gibt es bereits eine Vielzahl von Werkzeugen, wie den prometheus-operator, eine Sammlung von Dashboards aus kubernetes-mixin und die grafana-kubernetes-app. <\/p>\n<p>Die interessanteste Option f\u00fcr uns schien das Plugin grafana-kubernetes-app zu sein, allerdings wird es seit mehr als einem Jahr nicht mehr unterst\u00fctzt und kann zudem nicht mit den neuen Versionen von node-exporter und kube-state-metrics arbeiten. Irgendwann beschlossen wir: \u201eWarum nicht eine eigene L\u00f6sung entwickeln?\u201c<\/p>\n<p>Welche Ideen haben wir in unserem Plugin umgesetzt:<\/p>\n<ul>\n<li>Visualisierung der \u201eAnwendungskarte\u201c: eine benutzerfreundliche Darstellung von Anwendungen im Cluster, gruppiert nach Namespaces, Deployments\u2026;<\/li>\n<li>Visualisierung von Verbindungen zwischen \u201eDeployment \u2013 Service (+Ports)\u201c.<\/li>\n<li>Visualisierung der Verteilung der Clusteranwendungen auf die Cluster-Nodes.<\/li>\n<li>Sammlung von Metriken und Informationen aus mehreren Quellen: Prometheus und der K8s API-Server.<\/li>\n<li>\u00dcberwachung sowohl des Infrastrukturteils (Nutzung von CPU-Zeit, RAM, Speichersystem, Netzwerk) als auch der Anwendungslogik \u2013 Health-Status von Pods, Anzahl der verf\u00fcgbaren Replikate, Informationen \u00fcber das Durchlaufen von Liveness-\/Readyness-Checks.<\/li>\n<\/ul>\n<p><\/p>\n<h4>Teil 1: Was ist ein \u201eGrafana-Plugin\u201c?<\/h4>\n<p>\nTechnisch gesehen ist ein Grafana-Plugin ein Angular-Controller, der im Datenverzeichnis von Grafana gespeichert wird (<i>\/var\/grafana\/plugins\/&lt;your_plugin_name&gt;\/dist\/module.js<\/i>) und als SystemJS-Modul geladen werden kann. Ebenso sollte sich in diesem Verzeichnis eine Datei plugin.json befinden, die alle Meta-Informationen \u00fcber Ihr Plugin enth\u00e4lt: Name, Version, Plugin-Typ, Links zu Repository\/Website\/Lizenz, Abh\u00e4ngigkeiten usw.<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte von Fehlschl\u00e4gen\" 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 von Fehlschl\u00e4gen\" src=\"\/wp-content\/uploads\/2019\/11\/1e5b780837e5a9385e5e22a27d83f567.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>plugin.json<\/i><\/p>\n<p>Wie im Screenshot zu sehen ist, 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 Plug-in-Typ ist ein Dashboard-Panel zur Visualisierung von Metriken und wird f\u00fcr die Erstellung verschiedener Dashboards verwendet.<br \/>\n<b>Datenquelle<\/b>: Ein Plug-in-Connector zu einer Datenquelle (z. B. Prometheus-Datenquelle, ClickHouse-Datenquelle, ElasticSearch-Datenquelle).<br \/>\n<b>app<\/b>: Ein Plug-in, mit dem Sie Ihre eigene Frontend-Anwendung innerhalb von Grafana erstellen, eigene HTML-Seiten generieren und manuell auf die Datenquelle zugreifen k\u00f6nnen, um verschiedene Daten zu visualisieren. Auch andere Plug-in-Typen (Datenquelle, Panel) und verschiedene Dashboards k\u00f6nnen als Abh\u00e4ngigkeiten genutzt werden.<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte von Fehlschl\u00e4gen\" src=\"\/wp-content\/uploads\/2019\/11\/3cd53c7c3a2635f3f20831d52198b5f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Beispiel f\u00fcr Plug-in-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 finden Sie <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CorpGlory\">unter dem Link<\/a><\/noindex>: In diesem Repository finden Sie eine Vielzahl von Starter-Packs (es gibt sogar ein experimentelles Beispiel f\u00fcr ein Plug-in auf React) mit vorinstallierten und konfigurierten Build-Tools. <\/p>\n<h4>Teil 2: Vorbereitung der lokalen Umgebung<\/h4>\n<p>\nUm mit dem Plugin zu arbeiten, ben\u00f6tigen wir selbstverst\u00e4ndlich ein Kubernetes-Cluster mit allen vorinstallierten Tools: Prometheus, Node-Exporter, Kube-State-Metrics, Grafana. Die Umgebung sollte schnell, einfach und unproblematisch eingerichtet werden, und um Hot-Reload zu gew\u00e4hrleisten, muss das Datenverzeichnis von Grafana direkt vom Entwicklerger\u00e4t gemountet werden.<\/p>\n<p>Nach unserer Auffassung ist der bequemste Weg, lokal mit Kubernetes zu arbeiten, <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-minikube\/\">minikube<\/a><\/noindex>. Der n\u00e4chste Schritt besteht darin, das Prometheus + Grafana-B\u00fcndel mithilfe des Prometheus-Operators zu installieren. In <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/faun\/trying-prometheus-operator-with-helm-minikube-b617a2dccfa3\">diesem Artikel<\/a><\/noindex> wird der Installationsprozess 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 gesetzt werden, ein eigenes PV und PVC hinzugef\u00fcgt und diese im Parameter persistence.existingClaim angegeben werden.<\/p>\n<p>Das finale Skript zum Starten von Minikube sieht so 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: direkte Entwicklung<\/h4>\n<p>\n<b>Objektmodell<\/b><\/p>\n<p>Zur Vorbereitung der Implementierung des Plugins haben wir entschieden, alle grundlegenden Entit\u00e4ten von Kubernetes in Form von TypeScript-Klassen zu beschreiben: Pod, Deployment, DaemonSet, StatefulSet, Job, CronJob, Service, Node, Namespace. Jede dieser Klassen erbt von der \u00fcbergeordneten Klasse BaseModel, in der Konstruktor, Destruktor sowie Methoden zum Aktualisieren und Wechseln der Sichtbarkeit beschrieben sind. In jeder Klasse werden die eingebetteten Beziehungen zu anderen Entit\u00e4ten, wie zum Beispiel die Liste der Pods bei der Entit\u00e4t vom Typ Deployment, beschrieben.<\/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-Methoden k\u00f6nnen wir die ben\u00f6tigten Metriken der Entit\u00e4ten in einem \u00fcbersichtlichen und lesbaren Format ausgeben oder setzen. Zum Beispiel die formatierte Ausgabe des allocatable CPU eines Nodes:<\/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 anf\u00e4nglich in unserer pluing.json im Abschnitt Abh\u00e4ngigkeiten beschrieben:<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte von Fehlschl\u00e4gen\" src=\"\/wp-content\/uploads\/2019\/11\/b86c74839ad0d9c64b97ffc3f2a84bdf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nF\u00fcr jeden Seite m\u00fcssen wir den SEITENNAME angeben (dies wird dann in einen Slug umgewandelt, unter dem die Seite erreichbar ist); den Namen der Komponente, die f\u00fcr diese Seite zust\u00e4ndig ist (die Liste der Komponenten wird in module.ts exportiert); die Benutzerrolle angeben, f\u00fcr die die Arbeit mit dieser Seite zug\u00e4nglich ist, sowie die Navigationseinstellungen f\u00fcr die Seitenleiste. <\/p>\n<p>In der Komponente, die f\u00fcr die Seite zust\u00e4ndig ist, m\u00fcssen wir templateUrl festlegen und den Pfad zur HTML-Datei mit dem Markup \u00fcbergeben. Innerhalb des Controllers k\u00f6nnen wir \u00fcber Dependency Injection auf zwei wichtige Angular-Dienste zugreifen:<\/p>\n<ul>\n<li>backendSrv \u2014 der Dienst, der die Interaktion mit dem API-Server von Grafana erm\u00f6glicht;<\/li>\n<li>datasourceSrv \u2014 der Dienst, der die lokale Interaktion mit allen in Ihrer Grafana installierten Datenquellen erm\u00f6glicht (zum Beispiel gibt die Methode .getAll() eine Liste aller installierten Datenquellen zur\u00fcck; .get() gibt das Objekt-Instance einer bestimmten Datenquelle zur\u00fcck.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte von Fehlschl\u00e4gen\" 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 von Fehlschl\u00e4gen\" 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 von Fehlschl\u00e4gen\" 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 der Perspektive von Grafana ist die Datenquelle ein Plugin wie jedes andere: Sie hat ihren eigenen Einstiegspunkt module.js und eine Meta-Informationsdatei plugin.json. Bei der Entwicklung eines Plugins mit type = app k\u00f6nnen wir sowohl mit bereits bestehenden Datenquellen (wie z.B. prometheus-datasource) als auch mit unseren eigenen interagieren, die wir direkt im Verzeichnis des Plugins (dist\/datasource\/*) speichern oder als Abh\u00e4ngigkeit installieren k\u00f6nnen. In unserem Fall wird die Datenquelle zusammen mit dem Code des Plugins geliefert. Au\u00dferdem sind das Template config.html und der Controller ConfigCtrl erforderlich, die f\u00fcr die Konfigurationsseite der Datenquelleninstanz und den Controller Datasource verwendet werden, in dem die Logik Ihrer Datenquelle implementiert ist.<\/p>\n<p>Im KubeGraf-Plugin stellt die Datenquelle aus der Sicht der Benutzeroberfl\u00e4che eine Instanz des 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\">\u00fcber den Link<\/a><\/noindex>):<\/p>\n<ul>\n<li>Abrufen von Daten vom API-Server k8s (Abrufen der Liste von Namespaces, Deployments\u2026)<\/li>\n<li>Proxy-Anfragen an die Prometheus-Datenquelle (die in den Plugin-Einstellungen f\u00fcr jeden bestimmten Cluster ausgew\u00e4hlt wird) und Formatierung der Antworten zur Nutzung der Daten sowohl auf statischen Seiten als auch in Dashboards.<\/li>\n<li>Aktualisierung der Daten auf statischen Seiten des Plugins (mit festgelegtem Aktualisierungsintervall).<\/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 von Fehlschl\u00e4gen\" 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 von Fehlschl\u00e4gen\" 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 von Fehlschl\u00e4gen\" src=\"\/wp-content\/uploads\/2019\/11\/7f2d61fce623ce2a3cf62feb6d0447ac.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>Test der Verbindung zum 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 besonders interessantes Thema ist f\u00fcr uns die Implementierung des Authentifizierungs- und Autorisierungsmechanismus f\u00fcr Datasources. In der Regel k\u00f6nnen wir f\u00fcr die Konfiguration des Zugangs zu einer Datenquelle das integrierte Grafana-Komponenten datasourceHttpSettings verwenden. Mit dieser Komponente k\u00f6nnen wir den Zugang zu http-Datenquellen konfigurieren, indem wir die URL und die grundlegenden Authentifizierungs-\/Autorisierungseinstellungen angeben: Benutzername-Passwort oder client-cert\/client-key. Um die M\u00f6glichkeit zur Zugangskonfiguration mit einem Bearer-Token (de-facto Standard f\u00fcr k8s) zu implementieren, war jedoch ein wenig \u201eT\u00fcftelei\u201c erforderlich.<\/p>\n<p>Zur L\u00f6sung dieser Aufgabe kann der integrierte Grafana-Mechanismus \u201ePlugin-Routen\u201c verwendet werden (siehe auch <noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/docs\/plugins\/developing\/auth-for-datasources\/\">offizielle Dokumentationsseite<\/a><\/noindex>). In den Einstellungen unseres Datasources k\u00f6nnen wir eine Reihe von Routing-Regeln definieren, die vom Grafana-Proxy-Server verarbeitet werden. F\u00fcr jeden einzelnen Endpoint besteht die M\u00f6glichkeit, Headers oder URLs mit Template-Funktionalit\u00e4t zu vergeben, wobei die Daten aus den Feldern jsonData und secureJsonData (zur Speicherung von Passw\u00f6rtern oder Tokens in verschl\u00fcsselter Form) stammen k\u00f6nnen. In unserem Beispiel enthalten Anfragen der Art <i>\/__proxy\/api\/v1\/namespaces<\/i> werden auf eine URL wie<br \/>\n\/api\/v1\/namespaces mit dem Header Authorization: Bearer.<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte von Fehlschl\u00e4gen\" 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 von Fehlschl\u00e4gen\" src=\"\/wp-content\/uploads\/2019\/11\/9dab7537d7ccba90c9fb62dfa70b9fe2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNat\u00fcrlich ben\u00f6tigen wir f\u00fcr die Arbeit mit dem k8s-APIServer einen Benutzer mit Readonly-Rechten, dessen Manifest Sie ebenfalls finden k\u00f6nnen in <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/kubegraf\/tree\/master\/kubernetes\/\">dem 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 von Fehlschl\u00e4gen\" 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 geschrieben haben, m\u00f6chten Sie es nat\u00fcrlich \u00f6ffentlich zug\u00e4nglich machen. In Grafana gibt es eine Plugin-Bibliothek, die \u00fcber folgende Link zug\u00e4nglich ist: <noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/grafana\/plugins\">grafana.com\/grafana\/plugins<\/a><\/noindex> <\/p>\n<p>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 erstellen,<\/a><\/noindex>indem Sie den Inhalt folgenderma\u00dfen in die Datei repo.json hinzuf\u00fcgen:<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte von Fehlschl\u00e4gen\" src=\"\/wp-content\/uploads\/2019\/11\/160650bf37f8f2f3e12ef7dd291e90eb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nwobei version \u2014 die Version Ihres Plugins, url \u2014 der Link zum Repository und commit \u2014 der Hash des Commits ist, unter dem die spezifische Version des Plugins verf\u00fcgbar ist. <\/p>\n<p>Und am Ende sehen Sie ein sch\u00f6nes Bild in dieser Form:<\/p>\n<p><img decoding=\"async\" alt=\"Entwicklung eines Plugins f\u00fcr Grafana: Die Geschichte von Fehlschl\u00e4gen\" src=\"\/wp-content\/uploads\/2019\/11\/ff906396596e9c4c15c59f8d53555f52.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDie Daten hierf\u00fcr werden automatisch von Ihrem Readme.md, Changelog.md und der Datei plugin.json mit der Beschreibung des Plugins gesammelt.<\/p>\n<h4>Teil 6: anstelle von Schlussfolgerungen<\/h4>\n<p>\nWir haben die Entwicklung unseres Plugins nach dem Release nicht eingestellt. Derzeit arbeiten wir an einem pr\u00e4zisen Monitoring der Ressourcennutzung der Clusterknoten, implementieren neue Funktionen zur Verbesserung der Benutzererfahrung und bearbeiten ein gro\u00dfes Feedback, das wir nach den Installationen des Plugins sowohl von unseren Kunden als auch aus Issues auf GitHub erhalten haben (wenn Sie Ihr Issue oder Pull-Request hinterlassen, w\u00fcrde ich mich sehr freuen \ud83d\ude42 ).<\/p>\n<p>Wir hoffen, dass dieser Artikel Ihnen hilft, sich in diesem gro\u00dfartigen Werkzeug namens Grafana zurechtzufinden und m\u00f6glicherweise 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 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\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\" \/>\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) 4.9.10\" \/>\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! \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\" \/>\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\udd47 Entwicklung des Plugins f\u00fcr Grafana: die Geschichte unserer Erfahrungen | ProHoster","description":"Hallo zusammen! Vor einigen Monaten haben wir unser neues Open-Source-Projekt in Produktion genommen \u2014 ein Grafana-Plugin zur \u00dcberwachung von Kubernetes, das wir DevOpsProdigy KubeGraf genannt haben. Der Quellcode des Plugins ist im \u00f6ffentlichen Repository auf GitHub 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 mit welchen Herausforderungen wir konfrontiert waren.","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! \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","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"},"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}]}}