• Grafana 系列-GaC-2-Grafana Terraform Provider 基础


    系列文章

    概述

    前文最后总结了我的工具选型:

    • Grafana Terraform provider
    • Jsonnet

    我们今天先简单介绍 Grafana Terraform provider.

    Grafana Terraform Provider

    Grafana provider 为 Grafana 提供配置管理资源。是目前 Grafana 官方提供的,覆盖的 Grafana 资源最全的 IaC 工具。

    Grafana Terraform Provider 的代码是建立在 grafana-api-golang-client 之上的。

    通过 Grafana Terraform Provider, 我们可以管理:

    • Alerting
      • Resources
        • grafana_contact_point
        • grafana_message_template
        • grafana_mute_timing
        • grafana_notification_policy
        • grafana_rule_group
    • Cloud
      • Resources
        • grafana_cloud_access_policy
        • grafana_cloud_access_policy_token
        • grafana_cloud_api_key
        • grafana_cloud_plugin_installation
        • grafana_cloud_stack
        • grafana_cloud_stack_api_key
        • grafana_cloud_stack_service_account
        • grafana_cloud_stack_service_account_token
        • grafana_machine_learning_holiday
        • grafana_machine_learning_job
        • grafana_machine_learning_outlier_detector
      • DataSources
        • grafana_cloud_ips
        • grafana_cloud_organization
        • grafana_cloud_stack
    • Grafana Enterprise
      • Resources
        • grafana_builtin_role_assignment
        • grafana_data_source_permission (AWS Managed Grafana 也有这个功能)
        • grafana_report
        • grafana_role
        • grafana_role_assignment
        • grafana_team_external_group
    • Grafana OSS
      • Resources
        • grafana_annotation
        • grafana_api_key
        • grafana_dashboard
        • grafana_dashboard_permission
        • grafana_data_source
        • grafana_folder
        • grafana_folder_permission
        • grafana_library_panel
        • grafana_organization
        • grafana_organization_preferences
        • grafana_playlist
        • grafana_service_account
        • grafana_service_account_permission
        • grafana_service_account_token
        • grafana_team
        • grafana_team_preferences
        • grafana_user
      • DataSources
        • grafana_dashboard
        • grafana_dashboards
        • grafana_data_source
        • grafana_folder
        • grafana_folders
        • grafana_library_panel
        • grafana_organization
        • grafana_organization_preferences
        • grafana_team
        • grafana_user
        • grafana_users
    • OnCall
    • SLO
    • Synthetic Monitoring

    实战

    因为 Grafana 资源相对比较清晰和独立,不像 AWS 会有很多复杂的关联关系。

    所以关于 Grafana TF 代码的组织形式可以简单点:

    • 可以使 AllInOne 的 .tf 文件
    • 也可以根据资源类型,简单拆分为如下即可:
    ├── dashboard.tf
    ├── datasource.tf
    ├── grafana-ds-info.auto.tfvars.json
    ├── jsonnet (jsonnet 文件夹,dashboard 相关内容都在该文件夹下)
    ├── main.tf
    ├── outputs.tf
    ├── variables.tf
    └── versions.tf
    

    下面以第二种组织结构来详细介绍。

    创建 Grafana Provider

    main.tf 中,创建 Grafana Provider:

    provider "grafana" {
    }
    

    如果只有一套 Grafana, 那么如上的配置完全就够用了。

    如果有多套 Grafana, 则可以通过指定 Grafana provider 的 alias 来实现。具体如下:

    provider "grafana" {
      alias = "aws-managed-grafana"
    }
    

    后续使用资源的时候,可以通过指定 provider 来区分,实例如下:

    # provision folder
    resource "grafana_folder" "play-grafana" {
      provider = grafana.aws-managed-grafana
      uid   = "play-grafana"
      title = "play-grafana"
    }
    

    📝Notes:
    后续为了演示代码的简洁,不展示多 Grafana provider 的情况。
    Resource 里也不会有 provider 字段。

    Grafana 通过 Terraform 使用,是至少需要提供 url 和 apikey 2 类信息的。这 2 类信息可以直接通过环境变量的形式提供,具体如下:

    export GRAFANA_URL=https:///
    export GRAFANA_AUTH=
    

    GRAFANA_AUTH 的值可以是一个 Grafana API 密钥,basic auth 就是 用户名:密码,或可以点击这个链接申请 Grafana API 密钥

    除此之外,Grafana Cloud/Synthetic Monitoring/Grafana Oncall 会有一些专用的 apikey 或 token, 这里就不详细介绍了。

    创建 Grafana 组织

    📝Notes:

    因为我主要用的是 AWS Managed Grafana, 其只有一个默认的 org 1. 也没有开放相关的创建多个 org 的组织。所以我基本上不会用到该资源。

    如果有用到该资源,可以创建一个 org.tf, 具体内容是:

    // 创建组织
    resource "grafana_organization" "my_org" {
      name     = "my_org"
    }
    
    // 在组织内创建资源
    provider "grafana" {
      alias  = "my_org"
      org_id = grafana_organization.my_org.org_id
    }
    
    resource "grafana_folder" "my_folder" {
      provider = grafana.my_org
    
      title = "Test Folder"
    }
    

    创建 DataSource

    该资源所需的参数根据所选择的数据源类型(通过 type 参数)而有所不同。

    可以在 datasource.tf 下创建。

    以下是创建:

    • stackdriver
    • influxdb
    • cloudwatch
    • zabbix
    • ES
    • Prometheus
    • Jaeger

    的简单示例。

    Stackdriver

    resource "grafana_data_source" "arbitrary-data" {
      type = "stackdriver"
      name = "sd-arbitrary-data"
    
      json_data_encoded = jsonencode({
        "tokenUri"           = "https://oauth2.googleapis.com/token"
        "authenticationType" = "jwt"
        "defaultProject"     = "default-project"
        "clientEmail"        = "client-email@default-project.iam.gserviceaccount.com"
      })
    
      secure_json_data_encoded = jsonencode({
        "privateKey" = "-----BEGIN PRIVATE KEY-----\nprivate-key\n-----END PRIVATE KEY-----\n"
      })
    }
    

    Influxdb

    resource "grafana_data_source" "influxdb" {
      type                = "influxdb"
      name                = "myapp-metrics"
      url                 = "http://influxdb.example.net:8086/"
      basic_auth_enabled  = true
      basic_auth_username = "username"
      database_name       = influxdb_database.metrics.name
    
      json_data_encoded = jsonencode({
        authType          = "default"
        basicAuthPassword = "mypassword"
      })
    }
    

    Cloudwatch

    基于 AKSK 的创建:

    resource "grafana_data_source" "cloudwatch" {
      type = "cloudwatch"
      name = "cw-example"
    
      json_data_encoded = jsonencode({
        defaultRegion = "us-east-1"
        authType      = "keys"
      })
    
      secure_json_data_encoded = jsonencode({
        accessKey = "123"
        secretKey = "456"
      })
    }
    

    这是基于 role (external) 的创建:

    resource "grafana_data_source" "cloudwatch" {
      type = "cloudwatch"
      name = "example_cw"
    
      json_data_encoded = jsonencode({
        assumeRoleArn = "arn:aws:iam:::role/<...>"
        authType      = "ec2_iam_role"
        defaultRegion = "us-east-1"
        externalId = ""
      })
    }
    

    Zabbix

    resource "grafana_data_source" "zabbix" {
      type = "alexanderzobnin-zabbix-datasource"
      name = "Zabbix-example"
      url  = "http:///api_jsonrpc.php"
    
      json_data_encoded = jsonencode({
        trends   = true
        username = "Admin"
      })
    
      secure_json_data_encoded = jsonencode({
        password = "Password"
      })
    }
    

    🐾 注意:

    Zabbix 的 type 是 alexanderzobnin-zabbix-datasource
    使用的前提是安装 Zabbix Grafana 插件.

    Jaeger

    resource "grafana_data_source" "jaeger-example" {
      type = "jaeger"
      name = "example_jaeger"
      uid  = "example_jaeger"
      url  = "http:///trace/"
    
      json_data_encoded = jsonencode({
        "nodeGraph" : {
          "enabled" : true
        }
      })
    }
    
    data "grafana_data_source" "jaeger-example" {
      name = grafana_data_source.jaeger-example.name
      uid  = grafana_data_source.jaeger-example.uid
    }
    

    📝上面的 data "grafana_data_source" "jaeger-example" 是将 Jaeger Datasource 的 uid 提供给 ES 使用。

    当然,如果你直接在创建 Jaeger Datasource 的时候指定了 uid, 如下所示,那么后面在被其他 Datasource 引用时可以直接指定写死。

    uid  = "example_jaeger"
    

    ES

    resource "grafana_data_source" "elasticsearch-example" {
      type          = "elasticsearch"
      name          = "es_example"
      uid           = "es_example"
      url           = "http://:9200"
      // 就是 es index
      database_name = "[example.*-]YYYY.MM.DD"
    
      json_data_encoded = jsonencode({
        esVersion = "6.0.0"
    
        interval = "Daily"
        includeFrozen              = false
        maxConcurrentShardRequests = 256
        timeField                  = "@timestamp"
    
        logLevelField   = "level"
        logMessageField = "_source"
        dataLinks = [
          {
            datasourceUid = data.grafana_data_source.jaeger-example.uid
            // 或 datasourceUid = "example_jaeger"
            field         = "trace_id",
            url           = "${"$"}{__value.raw}"
          }
        ]
      })
    }
    

    这里,有以下几个需要注意的地方:

    • database_name = "[example.*-]YYYY.MM.DD" 在 type 为 es 的情况下,database_name 就是 es 的索引名称
    • dataLinks 这里通过 data link 链接到 Jagger Datasource: datasourceUid = data.grafana_data_source.jaeger-example.uid (Jaeger Datasource 就是上一节创建的)
    • url = "${"$"}{__value.raw}" 这里要特别注意,实际上传给 Grafana 的是:${__value.raw}, 但是这个恰好也是 Terraform 的模板/变量替换语法,所以如果直接这样写会将其解析为模板/变量,从而出现该变量不存在的报错。通过${"$"} 转义为 $ + {__value.raw} 拼成正确的 ${__value.raw} 传给 Grafana.

    Prometheus

    基础配置如下:

    resource "grafana_data_source" "prometheus" {
      type = "prometheus"
      name = "example_prom"
      uid  = "example_prom"
      url  = "http://my-instances.com"
    
      json_data_encoded = jsonencode({
        httpMethod = "POST"
      })
    }
    

    官方提供的 Prometheus 兼容实现 - Mimir 的配置如下:

    resource "grafana_data_source" "prometheus" {
      type                = "prometheus"
      name                = "mimir"
      url                 = "https://my-instances.com"
      basic_auth_enabled  = true
      basic_auth_username = "username"
    
      json_data_encoded = jsonencode({
        httpMethod        = "POST"
        prometheusType    = "Mimir"
        prometheusVersion = "2.4.0"
      })
    
      secure_json_data_encoded = jsonencode({
        basicAuthPassword = "password"
      })
    }
    

    创建 Dashboard

    dashboard.tf 中,创建 dashboard 示例如下:

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

    也可以通过如下方式创建:

    resource "grafana_dashboard" "metrics" {
      config_json = jsonencode({
        title   = "as-code dashboard"
        uid     = "ascode"
      })
    }
    

    🐾注意:

    config_json 是 String 类型,具体是完整的 Dashboard model JSON。

    可以直接通过 file("grafana-dashboard.json") 获取。

    如第二个实例,jsonencode 的作用就是使用 JSON 语法将一个 Object 转换为 String.

    总结

    好了,本次我们介绍了 Grafana Terraform Provider 的基础知识,还是比较简单的,我们使用其:

    • 创建 Provider
    • 创建组织
    • 创建文件夹
    • 创建各类常见的 Datasources
    • 创建 Dashboard

    非常直白清晰。希望对各位有所帮助。

    📚️参考文档

  • 相关阅读:
    Matlab:工作区变量
    Android7.x 通过Recovery保留特定文件实现恢复出厂设置后保留系统语言设置
    【C语言】通讯录系统实现 (保姆级教程,附源码)
    运维07:堡垒机
    RabbitMQ学习笔记
    Kafka事务「原理剖析」
    WorkPlus AI助理,基于ChatGPT的企业级知识问答机器人
    【云原生】Docker数据卷学习
    Angular8升级到Angular11
    配置静态ip,主机名,centos安装jdk,hadoop等
  • 原文地址:https://www.cnblogs.com/east4ming/p/17490940.html