文章较长,建议关注后再读:
er
介绍
Grafana as Code的意思是将Grafana的所有的配置——包括Dashboard——都通过代码来声明。通过代码来声明的方式有如下好处:
-
所有的代码都可版本化。就意味着可以进行Code Review。也就是意味我们可以得到Code Review带来的所有的好处;
-
减少手工配置量。如果一个环境有30个Dashboard,存在3个环境,你就必须手工配置 30*3个Dashboard;
-
无痛重建。就是重建一套新的Grafana,对你的团队来说是毫无压力的。
-
方便与其它系统集成。比如根据业务系统,自动生成新的配置。
-
可对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部署时,我们有以下建议:
-
指定Grafana的镜像的版本,而不是使用latest版本。使用latest的后果是,不知道哪天,你的Grafana就可能因为Grafana版本与插件版本不一致而不可用。
-
通过配置Values中的plugins字段,实现Grafana自动化下载依赖。如果你的部署环境有网络问题,可能需要你修改chart以实现从指定的地方下载插件。
-
虽然Values中有提供数据源和dashboard的配置,但是,我们建议把它放在应用配置部分。
而应用配置部分,Grafana应用本身的配置,我们建议通过Terraform实现。Terraform大多数时候被认为是基础设施的工具。其实,它是一款声明式的状态管理工具。本文使用它来管理Grafana的状态。
采用Terraform进行部署Grafana配置的步骤如下:
-
准备存储Terraform状态数据的后端。我们使用PostgreSQL作为后端;
-
在编辑器中,写Terraform配置代码;
-
通过Jsonnet编写Grafana的dashboard;
-
通过Jsonnet构建出main.tf.json文件;
-
通过terraform部署Grafana配置。
当然,执行以上的步骤的前提是:
-
必须安装Terraform、Jsonnet;
-
准备好PostgreSQL服务;
-
VSCode或者其它你喜欢的代码编辑器;
-
一个提前部署好的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提供一套标准的流程实现部署。步骤如下(都在工程的根目录执行):
-
terraofm init :初始化工程,包括下载provider、backend存储;
-
terraform plan:查看与远程配置(状态)的差异(可选)。比如本例就是查看你本地的配置与运行中的Grafana服务之间的差异;
-
terraform apply:执行部署。
通过以上步骤,我们将Grafana的配置部署到Grafana服务上了。
自动化所有
以上只是介绍的是通过代码配置Grafana的流程。但是,它是半自动化的。我们至少要手工地执行jsonnet命令和terraform命令。至于,如何设计并实现自动化流水并不是本文的重点,就在不本文展开了。
如何避免从头写Grafana Dashboard
并不是所有的Grafana都是从零开始的。很多企业在Grafana as Code之前就已经存在Grafana了。这时,如果我们全部从头写Grafana的Dashboard,工作量会非常的大。
解决方案就是直接从现有的Grafana服务上拉取下所有的Dashboard的Json文件,然后改后缀名为Jsonnet,就可以被我们的main.tf.jsonnet文件引用。
这个过程,虽然,也是手工,但是比起从头写过,已经轻松很多。
具体步骤如下:
-
通过Grafana的API下载Dashboard的json文件。API文档:https://grafana.com/docs/grafana/latest/http_api/dashboard/#get-dashboard-by-uid ;
-
将json保存为jsonnet文件存放在目录中;
-
main.tf.jsonnet引入这个jsonnet。
这里有一个坑,需要留意,即通过API下载的Dashboard的json文件与Dashboard的JSON model是两回事。你不可以使用JSON model作为参数传给的main.tf.jsonnet。Terraform的grafana provider的使用Grafana API对Grafana服务进行配置的。
下图展示的是一个Dashboard的JSON Model,它不能作为参数使用。
小结
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