Grafana 插件的开发:大人物的历史

大家好! 几个月前,我们将新的开源项目投入生产——用于监控 kubernetes 的 Grafana 插件,我们称之为 DevOpsProdigy KubeGraf。 插件源代码位于 GitHub 上的公共存储库。 在这篇文章中,我们想与大家分享我们如何创建这个插件、使用了哪些工具以及在开发过程中遇到了哪些陷阱。 我们走吧!

第 0 部分 - 介绍:我们是如何走到这一步的?

为 Grafan 编写自己的插件的想法是偶然产生的。 我们公司十多年来一直监控各种复杂程度的网络项目。 在这段时间里,我们积累了大量的专业知识、有趣的案例以及使用各种监控系统的经验。 在某些时候,我们问自己:“是否有一个神奇的工具来监控 Kubernetes,以便像他们所说的那样,“设置好后就忘记它”?”.. 当然,监控 k10s 的行业标准长期以来一直是Prometheus + Grafana 组合。 作为该堆栈的现成解决方案,有大量各种工具:prometheus-operator、一组 kubernetes-mixin 仪表板、grafana-kubernetes-app。

grafana-kubernetes-app 插件似乎是我们最有趣的选择,但它已经一年多没有得到支持,而且无法与新版本的 node-exporter 和 kube-state-metrics 一起使用。 在某个时刻,我们决定:“我们不应该自己做决定吗?”

我们决定在插件中实现哪些想法:

  • “应用程序地图”的可视化:方便地呈现集群中的应用程序,按名称空间、部署进行分组……;
  • 连接的可视化,例如“部署 - 服务(+端口)”。
  • 集群应用程序跨集群节点的分布的可视化。
  • 从多个来源收集指标和信息:Prometheus 和 k8s api 服务器。
  • 监控基础设施部分(CPU 时间、内存、磁盘子系统、网络的使用)和应用程序逻辑 - 健康状态 Pod、可用副本数量、有关通过活性/就绪性测试的信息。

第 1 部分:什么是“Grafana 插件”?

从技术角度来看,Grafana的插件是一个角度控制器,它存储在Grafana数据目录中(/var/grafana/插件/ /dist/module.js)并且可以作为 SystemJS 模块加载。 另外,在此目录中应该有一个plugin.json 文件,其中包含有关插件的所有元信息:名称、版本、插件类型、存储库/站点/许可证的链接、依赖项等。

Grafana 插件的开发:大人物的历史
模块.ts

Grafana 插件的开发:大人物的历史
插件.json

正如您在屏幕截图中看到的,我们指定了plugin.type = app。 因为 Grafana 的插件可以分为三种类型:

面板:最常见的插件类型 - 它是一个用于可视化任何指标的面板,用于构建各种仪表板。
资料来源:连接到某些数据源的插件连接器(例如,Prometheus-datasource、ClickHouse-datasource、ElasticSearch-datasource)。
应用:一个插件,允许您在 Grafana 中构建自己的前端应用程序,创建自己的 html 页面并手动访问数据源以可视化各种数据。 此外,其他类型的插件(数据源、面板)和各种仪表板也可以用作依赖项。

Grafana 插件的开发:大人物的历史
type=app 的示例插件依赖项.

您可以使用 JavaScript 和 TypeScript 作为编程语言(我们选择了它)。 准备任何类型的 hello-world 插件 通过链接查找:这个存储库包含大量带有预安装和配置构建器的入门包(甚至有一个 React 插件的实验示例)。

第2部分:准备本地环境

要使用该插件,我们自然需要一个带有所有预装工具的 kubernetes 集群:prometheus、node-exporter、kube-state-metrics、grafana。 环境应该快速、轻松、自然地设置,并且为了确保热重载,Grafana 数据目录应该直接从开发人员的机器上挂载。

我们认为,在本地使用 kubernetes 的最方便的方法是 迷你酷。 下一步是使用 prometheus-operator 安装 Prometheus + Grafana 组合。 在 这篇文章 详细介绍了minikube上安装prometheus-operator的过程。 要启用持久性,必须设置参数 持久性:真实 在charts/grafana/values.yaml文件中,添加自己的PV和PVC,并在persistence.existingClaim参数中指定它们

我们最终的 minikube 启动脚本如下所示:

minikube start --kubernetes-version=v1.13.4 --memory=4096 --bootstrapper=kubeadm --extra-config=scheduler.address=0.0.0.0 --extra-config=controller-manager.address=0.0.0.0
minikube mount 
/home/sergeisporyshev/Projects/Grafana:/var/grafana --gid=472 --uid=472 --9p-version=9p2000.L

第三部分:实际开发

对象模型

为了准备实现该插件,我们决定以 TypeScript 类的形式描述我们将使用的所有基本 Kubernetes 实体:pod、deployment、daemonset、statefulset、job、cronjob、service、node、namespace。 这些类中的每一个都继承自公共的 BaseModel 类,该类描述了构造函数、析构函数、更新和切换可见性的方法。 每个类都描述与其他实体的嵌套关系,例如部署类型实体的 Pod 列表。

import {Pod} from "./pod";
import {Service} from "./service";
import {BaseModel} from './traits/baseModel';

export class Deployment extends BaseModel{
   pods: Array<Pod>;
   services: Array<Service>;

   constructor(data: any){
       super(data);
       this.pods = [];
       this.services = [];
   }
}

在 getter 和 setter 的帮助下,我们可以以方便且可读的形式显示或设置我们需要的实体指标。 例如,可分配 cpu 节点的格式化输出:

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

前往

我们所有插件页面的列表最初在依赖项部分的 pluing.json 中描述:

Grafana 插件的开发:大人物的历史

在每个页面的块中,我们必须指示页面名称(然后它将被转换为可访问该页面的slug); 负责本页面操作的组件名称(组件列表导出到module.ts); 指示可使用此页面的用户角色以及侧边栏的导航设置。

在负责页面操作的组件中,我们必须设置 templateUrl,将带有标记的 html 文件的路径传递到那里。 在控制器内部,通过依赖注入,我们可以访问最多 2 个重要的 Angular 服务:

  • backendSrv - 提供与 Grafana API 服务器交互的服务;
  • datasourceSrv - 提供与 Grafana 中安装的所有数据源的本地交互的服务(例如 .getAll() 方法 - 返回所有已安装数据源的列表;.get( ) - 返回特定数据源的实例对象。

Grafana 插件的开发:大人物的历史

Grafana 插件的开发:大人物的历史

Grafana 插件的开发:大人物的历史

第四部分:数据源

从 Grafana 的角度来看,数据源与其他插件完全相同:它有自己的入口点 module.js,有一个包含元信息的文件 plugin.json。 当使用 type = app 开发插件时,我们可以与现有的数据源(例如 prometheus-datasource)和我们自己的数据源进行交互,我们可以将其直接存储在插件目录(dist/datasource/*)中或作为依赖项安装。 在我们的例子中,数据源附带插件代码。 还需要有一个 config.html 模板和一个 ConfigCtrl 控制器,它将用于数据源实例配置页面和数据源控制器,它实现数据源的逻辑。

在KubeGraf插件中,从用户界面的角度来看,数据源是一个kubernetes集群的实例,它实现了以下功能(源码可获取) 链接):

  • 从 k8s api 服务器收集数据(获取命名空间、部署的列表...)
  • 代理对 prometheus-datasource 的请求(在每个特定集群的插件设置中选择)并格式化响应以在静态页面和仪表板中使用数据。
  • 更新静态插件页面上的数据(具有设定的刷新率)。
  • 处理查询以在 grafana-dashboards 中生成模板表(metriFindQuery() 方法)

Grafana 插件的开发:大人物的历史

Grafana 插件的开发:大人物的历史

Grafana 插件的开发:大人物的历史

  • 与最终 k8s 集群的连接测试。
testDatasource(){
   let url = '/api/v1/namespaces';
   let _url = this.url;
   if(this.accessViaToken)
       _url += '/__proxy';
   _url += url;
   return this.backendSrv.datasourceRequest({
       url: _url,
       method: "GET",
       headers: {"Content-Type": 'application/json'}
   })
       .then(response => {
           if (response.status === 200) {
               return {status: "success", message: "Data source is OK", title: "Success"};
           }else{
               return {status: "error", message: "Data source is not OK", title: "Error"};
           }
       }, error => {
           return {status: "error", message: "Data source is not OK", title: "Error"};
       })
}

我们认为,一个单独的有趣点是数据源的身份验证和授权机制的实现。 通常,我们可以直接使用内置的 Grafana 组件 datasourceHttpSettings 来配置对最终数据源的访问。 使用此组件,我们可以通过指定 url 和基本身份验证/授权设置(登录密码或客户端证书/客户端密钥)来配置对 http 数据源的访问。 为了实现使用不记名令牌(k8s 的事实上的标准)配置访问的能力,我们必须做一些调整。

为了解决这个问题,您可以使用 Grafana 内置的“Plugin Routes”机制(更多详细信息请参见 官方文档页面)。 在数据源的设置中,我们可以声明一组将由grafana代理服务器处理的路由规则。 例如,对于每个单独的端点,可以设置带有模板可能性的标头或 url,其数据可以从 jsonData 和 secureJsonData 字段中获取(用于以加密形式存储密码或令牌)。 在我们的示例中,查询如下 /__proxy/api/v1/命名空间 将被代理到表单的 url
/api/v8/namespaces 带有 Authorization: Bearer 标头。

Grafana 插件的开发:大人物的历史

Grafana 插件的开发:大人物的历史

当然,要使用 k8s api 服务器,我们需要一个具有只读访问权限的用户,您也可以在中找到用于创建的清单 插件源代码.

第 5 部分:发布

Grafana 插件的开发:大人物的历史

一旦您编写了自己的 Grafana 插件,您自然会希望将其公开。 在 Grafana 中,这是一个可用的插件库 grafana.com/grafana/plugins

为了让您的插件在官方商店上可用,您需要在 这个存储库将这样的内容添加到 repo.json 文件中:

Grafana 插件的开发:大人物的历史

其中 version 是插件的版本,url 是存储库的链接,commit 是可用的特定版本插件的提交的哈希值。

在输出中你会看到一张精彩的图片,如下所示:

Grafana 插件的开发:大人物的历史

它的数据将自动从您的 Readme.md、Changelog.md 和带有插件描述的plugin.json 文件中获取。

第六部分:代替结论

发布后我们并没有停止开发插件。 现在,我们正在努力正确监控集群节点资源的使用情况,引入新功能来改进用户体验,并收集我们的客户和 GitHub 上的人员在安装插件后收到的大量反馈(如果您离开)您的问题或拉取请求,我会很高兴:)

我们希望本文能够帮助您了解 Grafana 这样一个出色的工具,或许还能帮助您编写自己的插件。

谢谢!)

来源: habr.com

添加评论