Grafana使用指南:自动化常用的Grafana操作

image.png

Grafana是可能是最受欢迎的可视化软件,Hosted Grafana 是由 MetricFire提供的。用户每天需要执行特定的操作,其中大部分是重复性的。例如,可能希望自动创建包含不同文件夹的仪表板。本教程将介绍如何使用在DevOps社区非常受欢迎的Terraform来实现这一目标,并展示如何使用客户端库进一步自动化此过程。

如果你使用MetricFire的托管Grafana,你可以在几分钟内开始使用Grafana。你可以在这里检查免费试用版或预定演示会议直接向团队咨询。现在让我们更详细地了解自动化。

Terraform介绍

由于使用Terraform已经提供的[文档](https://www.terraform.io/docs/configuration/index.html)作为基础有些困难,因此我们将使用链接来查找更多帮助,并以简单的方式介绍最基本的信息。

Terraform的基本模块是资源。资源声明表示需要在哪个配置中创建什么。 Terraform背后的主要理念之一是,无论应用多少次相同的配置,最终结果都是相同的。

如果软件产品不同,那么可以创建和管理的对象也会不同。希望能够将这些软件产品理解为资源的命名空间。在Terraform术语中,称之为提供者。Grafana提供者是其中之一,并将在本教程中使用。

Terraform的代码都被写在以.tf结尾的文件中。当然,关于如何组织所有的代码,有各种不同的指南。你可以将代码分组为称为模块的单独单位。Terraform注册表中有一些公共模块。请查看其他不同的术语。

在Terraform中,还有诸如Terragrunt和Atlantis等自动化产品,可以帮助您实现更多的功能。由于本次涉及的内容过多,我们假设您已经熟悉Terraform语法和简单配置的应用方法,并在此基础上进行解释。

Grafana供应商

Grafana提供商允许管理仪表板、数据源、文件夹、组织和警报通知通道等资源。若要使用它,必须向提供商提供对Grafana的管理访问权限。请将以下提供商代码块添加到.tf文件中。

provider "grafana" {
  url  = "http://grafana.example.com/"
  auth = "eyJrIjoicEXAMPLEEXAMPLEEXAMPLEEXAMPLEk15T2VBbkFCdTYiLCJuIjoidGVycmFmb3JtX3R1dG9yaWFsIiwiaWQiOjF9"
}

Auth可以是从Grafana获取的令牌,也可以是以冒号字符“:”分隔的用户名和密码组合之一。

当您进入个人设定菜单中的[API Key]部分时,您可以获得令牌。

image.png

点击[新 API 密钥],以管理员角色创建一个新的密钥。

image.png

接下来,获取一次性显示的关键字,需要将其保存在安全的地方。

image.png

这是一个必须粘贴到auth参数中,就像上面代码片段所示的密钥。但是,请不要担心。这只是本地Grafana生成的密钥示例。一旦更改了URL以指向Grafana实例,您就可以自由地探索各种Grafana提供者的资源。本文将总结所有资源的概述。

实践案例

这些示例已经在Terraform 0.12和Grafana 6.7.2中进行了测试。

文件夹

创建一个文件夹非常简单。

resource "grafana_folder" "collection" {
  title = "Monitoring Systems"
}

当使用terraform apply应用此配置时,将会产生以下输出结果。

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # grafana_folder.collection will be created
  + resource "grafana_folder" "collection" {
    + id    = (known after apply)
    + title = "Monitoring Systems"
    + uid   = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

grafana_folder.collection: Creating...
grafana_folder.collection: Creation complete after 0s [id=1]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

然后会产生以下的结果。

image.png

数据源

在将仪表板导入到该文件夹之前,您需要创建一些用于这些仪表板的数据源。使用Grafana提供程序可以方便地完成。

根据所创建的数据源类型,所需传递的准确参数将不同。请查看此处的所有选项。本教程将展示如何创建Prometheus数据源。

resource "grafana_data_source" "metrics" {
  type          = "prometheus"
  name          = "metricfire"
  url           = "http://127.0.0.1:12345/"
}

image.png

仪表盘

有了文件夹和数据源之后,您可以导入一个可视化仪表盘,以展示来自该数据源的数据。您可以在内联中指定仪表盘的JSON对象,或者像以下示例那样使用文件函数。

resource "grafana_dashboard" "metrics" {
  config_json = file("metricfire-dashboard.json")
}

很遗憾,Grafana仪表板资源不支持将仪表板导入到文件夹中,因此无法将仪表板导入到之前创建的文件夹中。运行前面的代码片段将会得到以下结果。

image.png

那个文件里只包含一些链接的简单仪表板。

image.png

警报通知渠道

此资源引用Grafana的本机警报机制所使用的通道。所需参数仅为名称和类型。所有其他设置都在配置键下。您可以在此处找到它们。

因此,您可以使用以下代码片段创建Grafana向Alertmanager返回警报通知的警报通知渠道。

resource "grafana_alert_notification" "am_integration" {
  name = "Alertmanager"
  type = "prometheus-alertmanager"
  is_default = true

  settings = {
    url = "http://myalertmanager.com:1234"
    basicAuthUser = "mybasicuser"
    basicAuthPassword = "supersecret"
  }
}

结果如下。

image.png
image.png

组织

最后,让我们来看一下Grafana提供程序目前支持的最后一个资源。组织是将仪表板和其他所有内容分离到单独的单元中的方法。这些可以按团队、服务或公司内有意义的抽象级别进行创建。

创建新的组织并添加用户非常容易。您可以使用以下代码片段:

resource "grafana_organization" "CoolProduct" {
    name        = "My Cool Product"
    admin_user   = "admin"
    create_users = false
    admins      = [
            "admin@localhost"
    ]
    editors     = [
            "foobar@foobar.com"
    ]
    viewers     = [
            "bazbaz@bazbaz.com"
    ]
}

如果create_users为true,则会创建占位符用户,但只会添加已经存在且符合指定角色的用户,若为false则不会创建。

应用以上的代码后,会变成如下:

image.png

请注意

使用Terraform和其Grafana供应商,您可以执行所有这些操作,但是有一些重要的注意事项。例如,您不能在不同的组织中创建文件夹、数据源或其他资源。您只能在主要组织中执行此操作。这是因为Grafana没有提供用于在这些组织之间导航的非常出色的RESTful API。换句话说,Grafana会将服务器端状态(如当前选择的组织)保存到用户中。这意味着没有很好的方法将其与Terraform的理念集成起来。虽然有一些尝试来实现这一点,但官方尚未提供。

所以,要在Grafana中完全自動化所有操作,需要切换到Go等通用编程语言。

用Go语言实现自动化动作。

有一个非常受欢迎的SDK,可以用于自动化Go中的Grafana操作。这个SDK被称为grafana-tools/sdk。本文介绍了可以用作基线的最低限度的程序,并展示了一些简单的测试,以增强自动化功能的可信度。

根据作者观点,Go语言相对容易理解与使用,制作Go应用程序也比较简单。此外,由于本文不是语言教程,需要有一定的经验基础。

裸奔程序

原始程序中有一些代码,可以连接到Grafana实例并执行各种操作。这与使用Terraform代码开始的方法相同,使用Grafana提供程序块。

要使用SDK来实现这一点,需要调用sdk.NewClient方法来创建一个新的客户端。在这里,可以使用基本认证或API密钥之一。在这种情况下,我们将使用基本认证。

package main

import (
   "github.com/grafana-tools/sdk"
)

func main() {
   client := sdk.NewClient("http://localhost:3000", "admin:admin", sdk.DefaultHTTPClient)
   var _ = client
}

由于Go语言中未使用的变量会导致编译错误,因此添加了var _ = client部分。现在,您可以使用客户端来实现在Grafana中想要做的任何事情。例如,让我们创建以下三个组织。

    • Metric

 

    • Fire

 

    IsAwesome
package main

import (
   "context"
   "fmt"

   "github.com/grafana-tools/sdk"
)

func main() {
   client := sdk.NewClient("http://localhost:3000", "admin:admin", sdk.DefaultHTTPClient)
   for _, org := range []string{"Metric", "Fire", "IsAwesome"} {
       sm, err := client.CreateOrg(context.Background(), sdk.Org{Name: org})
       // TODO: add proper error handling.
       fmt.Println(sm, err)
   }
}

然后,会产生以下结果。

image.png

此外,即使多次执行Grafana的API,也不会引发错误。相反,将返回成功,因为已存在且最终结果相同。

$ ./sdk_test
{<nil> <nil> 0xc000184110 <nil> <nil> <nil> <nil> <nil>} <nil>
{<nil> <nil> 0xc0001841f0 <nil> <nil> <nil> <nil> <nil>} <nil>
{<nil> <nil> 0xc000012ee0 <nil> <nil> <nil> <nil> <nil>} <nil>

程序通过fmt.Println输出一些诊断信息。如您所见,第二列始终是,并且表示没有发生错误。

自动化测试

使用通用的编程语言具有巨大的能力,也伴随着巨大的责任。对代码进行不断地测试是必要的。让我们来编写一些自动化程序的单元测试。

通过将代码分离到各种函数和模块中,可以对它们进行单独的测试。我们来执行它们以用于我们的程序。当然,实际的程序会更加复杂。这只是一个简单的例子。代码如下:

package main

import (
   "context"
   "fmt"

   "github.com/grafana-tools/sdk"
)

// Preparator is a struct for holding state related to our Grafana
// automation.
type Preparator struct {
   c *sdk.Client
}

// PrepareOrg prepares an organization for our use with the given name.
func (p *Preparator) PrepareOrg(ctx context.Context, orgName string) error {
   _, err := p.c.CreateOrg(ctx, sdk.Org{Name: orgName})
   return err
}

func main() {
   client := sdk.NewClient("http://localhost:3000", "admin:admin", sdk.DefaultHTTPClient)
   prep := &amp;Preparator{c: client}
   for _, org := range []string{"Metric", "Fire", "IsAwesome"} {
       // TODO: add proper error handling.
       fmt.Printf("creating org %s: %v\n", org, prep.PrepareOrg(context.TODO(), org))
   }
}

现在,您可以创建一个简单的测试案例来检查PrepareOrg函数是否正常工作。目前,我们只需要确保组织存在而无需进行其他操作。这就是我们要检查的内容。

以下是简单的测试代码旧你参考:

package main

import (
   "context"
   "testing"

   "github.com/grafana-tools/sdk"
)

// Tests whether preparator prepares a given organization properly.
func TestPreparatorPrepareOrg(t *testing.T) {
   testcases := []string{"a", "b", "c", "d", "e", "f"}

   // TODO: refactor this into a separate place.
   client := sdk.NewClient("http://localhost:3000", "admin:admin", sdk.DefaultHTTPClient)
   prep := &amp;Preparator{c: client}
   for _, org := range testcases {
       if err := prep.PrepareOrg(context.TODO(), org); err != nil {
           t.Fatalf("preparing org %v: %v", org, err)
       }

       // Now let's check if it has been created successfully.
       if _, err := client.GetOrgByOrgName(context.TODO(), org); err != nil {
           t.Fatalf("getting org %v: %v", org, err)
       }
   }
}

当你执行它时,

go test -v ./...
=== RUN   TestPreparatorPrepareOrg
--- PASS: TestPreparatorPrepareOrg (0.28s)
PASS
ok      sdk_test        0.286s

在阅读完SDK文档后,请尝试自动化所需的操作。

广告
将在 10 秒后关闭
bannerAds