{"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\/es\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek","title":{"rendered":"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>\u00a1Hola a todos! Hace unos meses lanzamos a producci\u00f3n nuestro nuevo proyecto open-source: un plugin de Grafana para monitorear Kubernetes, que llamamos <b><noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/grafana\/plugins\/devopsprodigy-kubegraf-app\">DevOpsProdigy KubeGraf<\/a><\/noindex><\/b>. El c\u00f3digo fuente del plugin est\u00e1 disponible en <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/kubegraf\">el repositorio p\u00fablico en GitHub<\/a><\/noindex>. En este art\u00edculo queremos compartir con ustedes la historia de c\u00f3mo creamos el plugin, qu\u00e9 herramientas utilizamos y con qu\u00e9 obst\u00e1culos nos encontramos en el proceso de desarrollo. \u00a1Empecemos!<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h4>Parte 0 \u2014 Introducci\u00f3n: \u00bfc\u00f3mo llegamos hasta aqu\u00ed?<\/h4>\n<p>\nLa idea de crear nuestro propio plugin para Grafana surgi\u00f3 de manera completamente casual. Nuestra empresa lleva m\u00e1s de 10 a\u00f1os monitoreando proyectos web de diferentes niveles de complejidad. Durante este tiempo hemos acumulado una gran cantidad de experiencia, casos interesantes y conocimientos en el uso de diversos sistemas de monitoreo. Y en alg\u00fan momento nos hicimos la pregunta: \"\u00bfExiste alguna herramienta m\u00e1gica para monitorear Kubernetes que, como se dice, 'la instalas y te olvidas'?\". El est\u00e1ndar para monitorear k8s es, por supuesto, la combinaci\u00f3n de Prometheus + Grafana. Y para este stack existen muchas soluciones listas: prometheus-operator, un conjunto de dashboards kubernetes-mixin, grafana-kubernetes-app. <\/p>\n<p>La opci\u00f3n m\u00e1s interesante para nosotros fue el plugin grafana-kubernetes-app, pero no ha recibido soporte en m\u00e1s de un a\u00f1o y, adem\u00e1s, no es compatible con las nuevas versiones de node-exporter y kube-state-metrics. En alg\u00fan momento decidimos: \"\u00bfY si hacemos nuestra propia soluci\u00f3n?\"<\/p>\n<p>Las ideas que decidimos implementar en nuestro plugin son:<\/p>\n<ul>\n<li>visualizaci\u00f3n de un 'mapa de aplicaciones': una representaci\u00f3n conveniente de las aplicaciones en el cl\u00faster, agrupadas por namespaces, deployments\u2026;<\/li>\n<li>visualizaci\u00f3n de relaciones tipo 'deployment \u2014 service (+ports)'.<\/li>\n<li>visualizaci\u00f3n de la distribuci\u00f3n de aplicaciones en el cl\u00faster seg\u00fan los nodos del cl\u00faster.<\/li>\n<li>recopilaci\u00f3n de m\u00e9tricas e informaci\u00f3n de varias fuentes: Prometheus y el servidor API de k8s.<\/li>\n<li>monitoreo tanto de la infraestructura (uso de CPU, memoria, subsistemas de disco, red), como de la l\u00f3gica de las aplicaciones: estado de salud de los pods, n\u00famero de r\u00e9plicas disponibles, informaci\u00f3n sobre las pruebas de liveness\/readyness.<\/li>\n<\/ul>\n<p><\/p>\n<h4>Parte 1: \u00bfQu\u00e9 es un 'plugin para Grafana'?<\/h4>\n<p>\nDesde un punto de vista t\u00e9cnico, un plugin para Grafana es un controlador angular que se almacena en el directorio de datos de Grafana (<i>\/var\/grafana\/plugins\/&lt;your_plugin_name&gt;\/dist\/module.js<\/i>) y puede ser cargado como un m\u00f3dulo SystemJS. Tambi\u00e9n en este directorio debe haber un archivo plugin.json que contenga toda la metainformaci\u00f3n sobre su plugin: nombre, versi\u00f3n, tipo de plugin, enlaces al repositorio\/sitio\/licencia, dependencias, etc.<\/p>\n<p><img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" 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=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/1e5b780837e5a9385e5e22a27d83f567.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>plugin.json<\/i><\/p>\n<p>Como se puede ver en la captura de pantalla, hemos indicado plugin.type = app. Ya que los plugins para Grafana pueden ser de tres tipos:<\/p>\n<p><b>panel<\/b>: el tipo de plugin m\u00e1s com\u00fan \u2014 representa un panel para visualizar m\u00e9tricas, utilizado para construir varios dashboards.<br \/>\n<b>datasource<\/b>: plugin-conector a alguna fuente de datos (por ejemplo, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).<br \/>\n<b>app<\/b>: plugin que le permite construir su propia aplicaci\u00f3n frontend dentro de Grafana, crear sus propias p\u00e1ginas html y acceder manualmente a la fuente de datos para visualizar diferentes datos. Tambi\u00e9n se pueden utilizar como dependencias otros tipos de plugins (datasource, panel) y varios dashboards.<\/p>\n<p><img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/3cd53c7c3a2635f3f20831d52198b5f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Ejemplo de dependencias de un plugin con type = app<\/i>.<\/p>\n<p>Como lenguaje de programaci\u00f3n se puede utilizar tanto JavaScript como TypeScript (nuestra elecci\u00f3n se detuvo en este \u00faltimo). Las plantillas para plugins hello-world de cualquier tipo pueden <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CorpGlory\">encontrarse en el enlace<\/a><\/noindex>: en este repositorio se presenta una gran cantidad de starter-packs (incluso hay un ejemplo experimental de un plugin en React) con ensambladores preinstalados y configurados. <\/p>\n<h4>Parte 2: preparaci\u00f3n del entorno local<\/h4>\n<p>\nPara trabajar en el plugin, necesitamos, por supuesto, un cl\u00faster de kubernetes con todas las herramientas preinstaladas: prometheus, node-exporter, kube-state-metrics, grafana. El entorno debe configurarse de forma r\u00e1pida, sencilla y sin complicaciones, y para garantizar el hot-reload, el directorio de datos de Grafana debe montarse directamente desde la m\u00e1quina del desarrollador.<\/p>\n<p>El m\u00e9todo m\u00e1s conveniente, en nuestra opini\u00f3n, para trabajar localmente con kubernetes es <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-minikube\/\">minikube<\/a><\/noindex>. El siguiente paso es instalar la combinaci\u00f3n Prometheus + Grafana utilizando prometheus-operator. En <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/faun\/trying-prometheus-operator-with-helm-minikube-b617a2dccfa3\">este art\u00edculo<\/a><\/noindex> se describe detalladamente el proceso de instalaci\u00f3n de prometheus-operator en minikube. Para habilitar la persistencia, es necesario establecer el par\u00e1metro <i>persistence: true<\/i> en el archivo charts\/grafana\/values.yaml, agregar su propio PV y PVC y especificarlos en el par\u00e1metro persistence.existingClaim<\/p>\n<p>El script final para ejecutar minikube se ve as\u00ed:<\/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>Parte 3: desarrollo propiamente dicho<\/h4>\n<p>\n<b>Modelo de objeto<\/b><\/p>\n<p>Como preparaci\u00f3n para la implementaci\u00f3n del complemento, decidimos describir todas las entidades b\u00e1sicas de Kubernetes con las que trabajaremos en forma de clases de TypeScript: pod, deployment, daemonset, statefulset, job, cronjob, service, node, namespace. Cada una de estas clases hereda de una clase base com\u00fan llamada BaseModel, en la que se describen el constructor, el destructor y m\u00e9todos para actualizar y alternar la visibilidad. En cada una de las clases se describen las relaciones anidadas con otras entidades, por ejemplo, la lista de pods en la entidad de tipo 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>\nCon getters y setters, podemos mostrar o establecer las m\u00e9tricas necesarias de las entidades de manera conveniente y legible. Por ejemplo, la salida formateada de los CPU allocatables de un nodo:<\/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>P\u00e1ginas<\/b><\/p>\n<p>La lista de todas las p\u00e1ginas de nuestro complemento se describe inicialmente en nuestro pluing.json en la secci\u00f3n de dependencias:<\/p>\n<p><img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/b86c74839ad0d9c64b97ffc3f2a84bdf.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEn el bloque para cada p\u00e1gina, debemos especificar el NOMBRE DE LA P\u00c1GINA (que luego se convertir\u00e1 en slug, a trav\u00e9s del cual estar\u00e1 disponible esta p\u00e1gina); el nombre del componente que se encarga de la operaci\u00f3n de esta p\u00e1gina (la lista de componentes se exporta en module.ts); la indicaci\u00f3n del rol de usuario que tiene acceso a trabajar con esta p\u00e1gina y la configuraci\u00f3n de la navegaci\u00f3n para la barra lateral. <\/p>\n<p>En el componente responsable de la operaci\u00f3n de la p\u00e1gina, debemos establecer templateUrl, pasando la ruta al archivo html con la estructura. Dentro del controlador, a trav\u00e9s de la inyecci\u00f3n de dependencias, podemos acceder a 2 servicios importantes de Angular:<\/p>\n<ul>\n<li>backendSrv \u2014 servicio que proporciona la interacci\u00f3n con el servidor API de Grafana;<\/li>\n<li>datasourceSrv \u2014 servicio que proporciona la interacci\u00f3n local con todas las fuentes de datos instaladas en tu Grafana (por ejemplo, el m\u00e9todo .getAll() \u2014 devuelve la lista de todas las fuentes de datos instaladas; .get() \u2014 devuelve el objeto instancia de una fuente de datos espec\u00edfica.<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/e616e74c2e31ca3a81b7ed91ca333208.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/5e1d45f570dda50774088405abb41c9f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/c072867623824e799518984c7b1bee93.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h4>Parte 4: fuente de datos<\/h4>\n<p>\nDesde la perspectiva de Grafana, un datasource es un plugin como cualquier otro: tiene su punto de entrada module.js y un archivo de metainformaci\u00f3n llamado plugin.json. Al desarrollar un plugin de tipo app, podemos interactuar tanto con datasources ya existentes (por ejemplo, prometheus-datasource) como con los nuestros, que podemos almacenar directamente en el directorio del plugin (dist\/datasource\/*) o instalar como dependencia. En nuestro caso, el datasource se entrega junto con el c\u00f3digo del plugin. Tambi\u00e9n es fundamental contar con una plantilla config.html y un controlador ConfigCtrl que se utilizar\u00e1n para la p\u00e1gina de configuraci\u00f3n de la instancia del datasource y el controlador Datasource, donde se implementa la l\u00f3gica de funcionamiento de tu datasource.<\/p>\n<p>En el plugin KubeGraf, desde la perspectiva de la interfaz de usuario, el datasource es una instancia del cl\u00faster de Kubernetes, que incluye las siguientes capacidades (el c\u00f3digo fuente est\u00e1 disponible <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/kubegraf\/tree\/master\/src\/datasource\">en el enlace<\/a><\/noindex>):<\/p>\n<ul>\n<li>recopilaci\u00f3n de datos desde el api-server de k8s (obteniendo la lista de namespaces, deployments...)<\/li>\n<li>proxy de solicitudes al prometheus-datasource (que se selecciona en los ajustes del plugin para cada cl\u00faster espec\u00edfico) y formateo de respuestas para utilizar los datos tanto en p\u00e1ginas est\u00e1ticas como en dashboards.<\/li>\n<li>actualizaci\u00f3n de datos en p\u00e1ginas est\u00e1ticas del plugin (con un tiempo de refresh rate establecido).<\/li>\n<li>procesamiento de solicitudes para formar una lista de plantillas en grafana-dashboards (m\u00e9todo .metriFindQuery())<\/li>\n<\/ul>\n<p>\n<img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/18159bbb41144ebceb457df28b35e7b1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/a62665b4409566fbe24f56f88a376d5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/7f2d61fce623ce2a3cf62feb6d0447ac.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ul>\n<li>prueba de conexi\u00f3n con el cl\u00faster 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: \"El datasource est\u00e1 OK\", title: \"\u00c9xito\"};\n           }else{\n               return {status: \"error\", message: \"El datasource no est\u00e1 OK\", title: \"Error\"};\n           }\n       }, error =&gt; {\n           return {status: \"error\", message: \"El datasource no est\u00e1 OK\", title: \"Error\"};\n       })\n}<\/code><\/pre>\n<p>\nUn aspecto interesante, en nuestra opini\u00f3n, es la implementaci\u00f3n del mecanismo de autenticaci\u00f3n y autorizaci\u00f3n para el datasource. Por lo general, para configurar el acceso al origen de datos final, podemos utilizar el componente integrado de Grafana: datasourceHttpSettings. Con este componente, podemos configurar el acceso a la fuente de datos http, especificando la url y las configuraciones b\u00e1sicas de autenticaci\u00f3n\/autorizaci\u00f3n: usuario-contrase\u00f1a, o client-cert\/client-key. Para implementar la posibilidad de configurar el acceso mediante un bearer token (el est\u00e1ndar de facto para k8s), fue necesario hacer algunos ajustes.<\/p>\n<p>Para abordar esta tarea, se puede utilizar el mecanismo integrado de Grafana \"Plugin Routes\" (m\u00e1s detalles en <noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/docs\/plugins\/developing\/auth-for-datasources\/\">la p\u00e1gina oficial de documentaci\u00f3n<\/a><\/noindex>). En la configuraci\u00f3n de nuestro datasource, podemos declarar un conjunto de reglas de enrutamiento que ser\u00e1n procesadas por el servidor proxy de Grafana. Por ejemplo, para cada endpoint existe la posibilidad de establecer encabezados o url con opci\u00f3n de plantilla, cuyos datos pueden tomarse de los campos jsonData y secureJsonData (para almacenar contrase\u00f1as o tokens encriptados). En nuestro ejemplo, las solicitudes de tipo <i>\/__proxy\/api\/v1\/namespaces<\/i> se proxificar\u00e1n a una url de tipo<br \/>\n\/api\/v1\/namespaces con el encabezado Authorization: Bearer.<\/p>\n<p><img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/ca73ff0fef62fba3edab7907c83639b6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/9dab7537d7ccba90c9fb62dfa70b9fe2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNaturalmente, para trabajar con el servidor api de k8s, necesitamos un usuario con permisos de solo lectura; los manifiestos para su creaci\u00f3n tambi\u00e9n pueden encontrarse en <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devopsprodigy\/kubegraf\/tree\/master\/kubernetes\/\">el c\u00f3digo fuente del plugin<\/a><\/noindex>.<\/p>\n<h4>Parte 5: lanzamiento<\/h4>\n<p>\n<img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/3991a5d412f362770157fc567bb8009c.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDespu\u00e9s de escribir tu propio plugin para Grafana, naturalmente querr\u00e1s publicarlo en acceso abierto. En Grafana hay una biblioteca de plugins disponible en <noindex><a rel=\"nofollow\" href=\"https:\/\/grafana.com\/grafana\/plugins\">grafana.com\/grafana\/plugins<\/a><\/noindex> <\/p>\n<p>Para que tu plugin est\u00e9 disponible en la tienda oficial, debes hacer un PR en <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/grafana\/grafana-plugin-repository\">este repositorio<\/a><\/noindex>, a\u00f1adiendo en el archivo repo.json el contenido de tipo:<\/p>\n<p><img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/160650bf37f8f2f3e12ef7dd291e90eb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\ndonde version es la versi\u00f3n de tu plugin, url es el enlace al repositorio, y commit es el hash del commit mediante el cual se podr\u00e1 acceder a esa versi\u00f3n espec\u00edfica del plugin. <\/p>\n<p>Y al final ver\u00e1s una imagen maravillosa de tipo:<\/p>\n<p><img decoding=\"async\" alt=\"Desarrollo de un plugin para Grafana: historia de las lecciones aprendidas\" src=\"\/wp-content\/uploads\/2019\/11\/ff906396596e9c4c15c59f8d53555f52.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLos datos para ella se recopilar\u00e1n autom\u00e1ticamente de tu Readme.md, Changelog.md y del archivo plugin.json con la descripci\u00f3n del plugin.<\/p>\n<h4>Parte 6: en lugar de conclusiones<\/h4>\n<p>\nNo hemos detenido el desarrollo de nuestro plugin despu\u00e9s del lanzamiento. Actualmente estamos trabajando en un monitoreo correcto del uso de recursos de los nodos del cl\u00faster, implementando nuevas funciones para mejorar la experiencia del usuario, y tambi\u00e9n estamos revisando una gran cantidad de comentarios recibidos tras las instalaciones del plugin tanto de nuestros clientes como de los 'issues' en GitHub (si dejas tu 'issue' o 'pull request', estar\u00e9 muy feliz \ud83d\ude42 ).<\/p>\n<p>Esperamos que este art\u00edculo te ayude a entender esta maravillosa herramienta que es Grafana y, tal vez, te inspire a escribir tu propio plugin. <\/p>\n<p>\u00a1Gracias!)<br \/>\n<br \/>Fuente: <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 - 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\/es\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\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\/es\/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\udd47Desarrollo de un plugin para Grafana: historia de los tropiezos | ProHoster","description":"\u00a1Hola a todos!","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/razrabotka-plagina-dlya-grafana-istoriya-nabityh-shishek","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","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\/es\/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\/es\/wp-json\/wp\/v2\/posts\/52343","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=52343"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/52343\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=52343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=52343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=52343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}