Grafana as Code实践指南

导读:本篇文章讲解 Grafana as Code实践指南,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

21f6683ef2de6b71ff62c62ddd2666a8.png

文章较长,建议关注后再读:

er

介绍

Grafana as Code的意思是将Grafana的所有的配置——包括Dashboard——都通过代码来声明。通过代码来声明的方式有如下好处:

  1. 所有的代码都可版本化。就意味着可以进行Code Review。也就是意味我们可以得到Code Review带来的所有的好处;

  2. 减少手工配置量。如果一个环境有30个Dashboard,存在3个环境,你就必须手工配置 30*3个Dashboard;

  3. 无痛重建。就是重建一套新的Grafana,对你的团队来说是毫无压力的。

  4. 方便与其它系统集成。比如根据业务系统,自动生成新的配置。

  5. 可对dashboard的代码进行单元测试。

本文是我们的一些实践经验的总结。

整体步骤

我们将Grafana的配置可以分成两部分来看:

  • 部署配置部分:部署Grafana应用过程的配置,如应用内存大小、使用的域名、插件安装等。说白了就是一个”空“的Grafana;

  • 应用配置部分:Grafana应用本身的配置,如包含的folder列表、dashboard、LDAP配置等等。

部署配置部分,很大一部分程度取决于你的部署方式。我们建议是通过docker的方式运行。如果你还没上线Kubernetes,那么,我们推荐你使用docker-compose的方式部署。而Kubernetes,我们推荐你使用Helm进行部署。Chart推荐官方的chart:https://github.com/grafana/helm-charts/tree/main/charts/grafana 。这两种方式都支持配置的方式部署。

使用Helm部署时,我们有以下建议:

  1. 指定Grafana的镜像的版本,而不是使用latest版本。使用latest的后果是,不知道哪天,你的Grafana就可能因为Grafana版本与插件版本不一致而不可用。

  2. 通过配置Values中的plugins字段,实现Grafana自动化下载依赖。如果你的部署环境有网络问题,可能需要你修改chart以实现从指定的地方下载插件。

  3. 虽然Values中有提供数据源和dashboard的配置,但是,我们建议把它放在应用配置部分。

而应用配置部分,Grafana应用本身的配置,我们建议通过Terraform实现。Terraform大多数时候被认为是基础设施的工具。其实,它是一款声明式的状态管理工具。本文使用它来管理Grafana的状态。

采用Terraform进行部署Grafana配置的步骤如下:

  1. 准备存储Terraform状态数据的后端。我们使用PostgreSQL作为后端;

  2. 在编辑器中,写Terraform配置代码;

  3. 通过Jsonnet编写Grafana的dashboard;

  4. 通过Jsonnet构建出main.tf.json文件;

  5. 通过terraform部署Grafana配置。

当然,执行以上的步骤的前提是:

  1. 必须安装Terraform、Jsonnet;

  2. 准备好PostgreSQL服务;

  3. VSCode或者其它你喜欢的代码编辑器;

  4. 一个提前部署好的Grafana服务。

准备存储Terraform状态数据的后端

Terraform支持多种后端存在状态数据,包括:artifactory、azurerm、consul、cos、etcd、gcs、oss、s3、pg。本文使用pg,也就是PostgreSQL。

在PostgreSQL创建中DB:

createdb terraform_backend

terraformbackend 是DB的名称。你可以根据不同的业务场景起不同的名称。而且,我们也可以针对不同的业务场景创建不同的DB。比如SIT环境的DB叫terraformbackendsit,生产环境的DB叫terraformbackend_prod。

编写Terraform代码

Terraform默认使用的是一种叫HCL的配置语言。同时,它还支持使用JSON进行配置。这里,我们建议使用JSON作为Terraform的配置语言。因为Jsonnet可以很轻松的生成JSON,但不能容易地生成HCL配置。

以下是使用Jsonnet写Terraform配置的框架,类似Helloword的作用。这个配置文件是Terraform的入口文件,文件名采用main.tf.jsonnet。

你可以在此框架上增加你的代码:

local grafanaDashboardJsonContent = import 'grafanaDashboardJsonContent.libsonnet';
{
    terraform: {
      required_providers: {
        // 指定Grafana的Provider的版本
        grafana: {
          source: 'grafana/grafana',
          version: '1.21.1',
        },
      },
       backend: {
         pg: {
           conn_str: 'postgres://postgres:postgres@127.0.0.1:5432/grafana_terraform_backend?sslmode=disable',
         },
       },
    },
    provider: {
      grafana: {
        // 你希望配置的grafana的地址
        url: 'grafanas url',
        // https://registry.terraform.io/providers/grafana/grafana/latest/docs#auth
        auth: '%(name)s:%(password)s' % { name: admin, password: adminpassword },
      },
    },
    resource: {
          grafana_folder: {
            abc_team: {
                title: 'abc Team'
            }
          },
          //定义数据源
          grafana_data_source: {
                influxdb1:{
                    type: "influxdb",
                      name:"myapp-metrics",
                      url:"http://influxdb.example.net:8086/",
                    username: "myapp",
                    password: "foobarbaz",
                    database_name = "dbname"
                }
                // other datasources can be defined below
          },
            // Jsonnet的语法,根据teams变量中的定义批量创建team。teams可以由其它Jsonnet文件提供
          grafana_team: {
            [t]: { name: teams[t].name }
            for t in std.objectFields(teams)
          },
          grafana_dashboard: {
            // jvm_dashboard 是dashboard在Jsonnet中的标识。接受的是一个对象。
            // grafanaDashboardJsonContent 定义在其它Jsonnet文件中,被import到此文件。
            jvm_dashboard: grafanaDashboardJsonContent
          }
    },
 }
}

通过Jsonnet编写Dashboard

通常我们一个Dashboard一个Jsonnet文件。然后通过import引入到main.tf.jsonnet入口文件中。引入方式如下:

local grafanaDashboardJsonContent = import 'grafanaDashboardJsonContent.libsonnet';

grafanaDashboardJsonContent.libsonnet的部分内容如下:

local grafana = import 'grafonnet/grafana.libsonnet';
grafana.dashboard.new(
    'JVM',
    refresh='1m',
    time_from='now-1h',
    tags=['java']
).addRow(
    row.new(
        title='Memory',
        height='250px',
    )
    .addPanel(
        graphPanel.new(
        'JVM Memory Heap',
        span=6,
        format='bytes',
        fill=0,
        min=0,
        decimals=2,
        datasource='-- Mixed --',
        legend_values=true,
        legend_min=true,
        legend_max=true,
        legend_current=true,
        legend_total=false,
        legend_avg=true,
        legend_alignAsTable=true,
        legend_sideWidth=200,
        )
    )
)

完成内容可以从官方样例找到:https://github.com/grafana/grafonnet-lib/blob/master/examples/jvm.jsonnet

Jsonnet具有非常好的模块化的能力。Grafana公司公开了自己用于写Grafana的Dashboard的Jsonnet库 https://github.com/grafana/grafonnet-lib。所以,在上面代码中,我们第一行,就是引入它:

local grafana = import 'grafonnet/grafana.libsonnet';

注意:import接的是相对路径。

到目前为此,整个工程的目录结构如下:

.
├── grafanaDashboardJsonContent.json
├── grafonnet
│   └── grafana.libsonnet
└── main.tf.json

你也可以创建一个dashboards文件夹存入所有的dashboard。以方便管理dashboard。

通过Jsonnet构建出main.tf.json文件

执行命令

jsonnet main.tf.jsonnet > main.tf.json

注意生成的文件必须以 。terraform命令会加载目录下所有的 .tf.json 为后缀的文件。

通过Terraform部署Grafana配置

Terraform提供一套标准的流程实现部署。步骤如下(都在工程的根目录执行):

  1. terraofm init :初始化工程,包括下载provider、backend存储;

  2. terraform plan:查看与远程配置(状态)的差异(可选)。比如本例就是查看你本地的配置与运行中的Grafana服务之间的差异;

  3. terraform apply:执行部署。

通过以上步骤,我们将Grafana的配置部署到Grafana服务上了。

自动化所有

以上只是介绍的是通过代码配置Grafana的流程。但是,它是半自动化的。我们至少要手工地执行jsonnet命令和terraform命令。至于,如何设计并实现自动化流水并不是本文的重点,就在不本文展开了。

如何避免从头写Grafana Dashboard

并不是所有的Grafana都是从零开始的。很多企业在Grafana as Code之前就已经存在Grafana了。这时,如果我们全部从头写Grafana的Dashboard,工作量会非常的大。

解决方案就是直接从现有的Grafana服务上拉取下所有的Dashboard的Json文件,然后改后缀名为Jsonnet,就可以被我们的main.tf.jsonnet文件引用。

这个过程,虽然,也是手工,但是比起从头写过,已经轻松很多。

具体步骤如下:

  1. 通过Grafana的API下载Dashboard的json文件。API文档:https://grafana.com/docs/grafana/latest/http_api/dashboard/#get-dashboard-by-uid ;

  2. 将json保存为jsonnet文件存放在目录中;

  3. main.tf.jsonnet引入这个jsonnet。

这里有一个坑,需要留意,即通过API下载的Dashboard的json文件与Dashboard的JSON model是两回事。你不可以使用JSON model作为参数传给的main.tf.jsonnet。Terraform的grafana provider的使用Grafana API对Grafana服务进行配置的。

下图展示的是一个Dashboard的JSON Model,它不能作为参数使用。

8895657b0afdd9649b1c537c6091548f.png

小结

Grafana as Code中的”Code“分成两部分:部署代码和配置代码。部署代码与部署方式有关,本文不介绍。

配置代码指的是通过代码配置Grafana服务。原理是通过Terraform对Grafana服务状态进行管理。而HCL作为Terraform的配置语言,与我们的Jsonnet语言不一致。所以,我们使用Jsonnet生成Terraform同样认识的json格式的配置。当然,你们也可以通过其它配置语言生成Terraform支持的格式的配置。

本文还有一个遗漏点:Grafana as Code的集成测试。就是开发人员提MR时,你如何判断提交人写的代码是否有问题,这个自动化验证的过程,本质上就是配置代码与Grafana的集成测试过程。如果集成成功,我们认为该代码技术上是没有问题。如果测试成功,我们认为添加的这段代码是没有影响原来的Dashboard的业务逻辑的。这部分内容留给将来写了。

往期好文:

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/70952.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!