系列文章
概述
前文最后總結(jié)了我的工具選型:
- Grafana Terraform provider
- Jsonnet
我們今天先簡(jiǎn)單介紹 Grafana Terraform provider.
Grafana Terraform Provider
Grafana provider 為 Grafana 提供配置管理資源。是目前 Grafana 官方提供的系宜,覆蓋的 Grafana 資源最全的 IaC 工具照激。
Grafana Terraform Provider 的代碼是建立在 grafana-api-golang-client 之上的。
通過(guò) Grafana Terraform Provider, 我們可以管理:
- Alerting
- Resources
grafana_contact_point
grafana_message_template
grafana_mute_timing
grafana_notification_policy
grafana_rule_group
- Resources
- 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
- Resources
- Grafana Enterprise
- Resources
grafana_builtin_role_assignment
-
grafana_data_source_permission
(AWS Managed Grafana 也有這個(gè)功能) grafana_report
grafana_role
grafana_role_assignment
grafana_team_external_group
- Resources
- 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
- Resources
- OnCall
- 略
- SLO
- 略
- Synthetic Monitoring
- 略
實(shí)戰(zhàn)
因?yàn)?Grafana 資源相對(duì)比較清晰和獨(dú)立盹牧,不像 AWS 會(huì)有很多復(fù)雜的關(guān)聯(lián)關(guān)系俩垃。
所以關(guān)于 Grafana TF 代碼的組織形式可以簡(jiǎn)單點(diǎn):
- 可以使 AllInOne 的
.tf
文件 - 也可以根據(jù)資源類(lèi)型,簡(jiǎn)單拆分為如下即可:
├── dashboard.tf
├── datasource.tf
├── grafana-ds-info.auto.tfvars.json
├── jsonnet (jsonnet 文件夾汰寓,dashboard 相關(guān)內(nèi)容都在該文件夾下)
├── main.tf
├── outputs.tf
├── variables.tf
└── versions.tf
下面以第二種組織結(jié)構(gòu)來(lái)詳細(xì)介紹口柳。
創(chuàng)建 Grafana Provider
在 main.tf
中,創(chuàng)建 Grafana Provider:
provider "grafana" {
}
如果只有一套 Grafana, 那么如上的配置完全就夠用了有滑。
如果有多套 Grafana, 則可以通過(guò)指定 Grafana provider 的 alias
來(lái)實(shí)現(xiàn)跃闹。具體如下:
provider "grafana" {
alias = "aws-managed-grafana"
}
后續(xù)使用資源的時(shí)候,可以通過(guò)指定 provider
來(lái)區(qū)分,實(shí)例如下:
# provision folder
resource "grafana_folder" "play-grafana" {
provider = grafana.aws-managed-grafana
uid = "play-grafana"
title = "play-grafana"
}
??Notes:
后續(xù)為了演示代碼的簡(jiǎn)潔辣卒,不展示多 Grafana provider 的情況掷贾。
Resource 里也不會(huì)有provider
字段。
Grafana 通過(guò) Terraform 使用荣茫,是至少需要提供 url 和 apikey 2 類(lèi)信息的想帅。這 2 類(lèi)信息可以直接通過(guò)環(huán)境變量的形式提供,具體如下:
export GRAFANA_URL=https://<your-grafana-domain>/
export GRAFANA_AUTH=<your-grafana-apikey>
GRAFANA_AUTH
的值可以是一個(gè) Grafana API 密鑰啡莉,basic auth 就是 用戶(hù)名:密碼
港准,或可以點(diǎn)擊這個(gè)鏈接申請(qǐng) Grafana API 密鑰。
除此之外咧欣,Grafana Cloud/Synthetic Monitoring/Grafana Oncall 會(huì)有一些專(zhuān)用的 apikey 或 token, 這里就不詳細(xì)介紹了浅缸。
創(chuàng)建 Grafana 組織
??Notes:
因?yàn)槲抑饕玫氖?AWS Managed Grafana, 其只有一個(gè)默認(rèn)的 org 1. 也沒(méi)有開(kāi)放相關(guān)的創(chuàng)建多個(gè) org 的組織。所以我基本上不會(huì)用到該資源魄咕。
如果有用到該資源衩椒,可以創(chuàng)建一個(gè) org.tf
, 具體內(nèi)容是:
// 創(chuàng)建組織
resource "grafana_organization" "my_org" {
name = "my_org"
}
// 在組織內(nèi)創(chuàng)建資源
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"
}
創(chuàng)建 DataSource
該資源所需的參數(shù)根據(jù)所選擇的數(shù)據(jù)源類(lèi)型(通過(guò) type
參數(shù))而有所不同。
可以在 datasource.tf
下創(chuàng)建哮兰。
以下是創(chuàng)建:
- stackdriver
- influxdb
- cloudwatch
- zabbix
- ES
- Prometheus
- Jaeger
的簡(jiǎn)單示例毛萌。
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 的創(chuàng)建:
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) 的創(chuàng)建:
resource "grafana_data_source" "cloudwatch" {
type = "cloudwatch"
name = "example_cw"
json_data_encoded = jsonencode({
assumeRoleArn = "arn:aws:iam::<the-aws-id>:role/<...>"
authType = "ec2_iam_role"
defaultRegion = "us-east-1"
externalId = "<the-aws-id>"
})
}
Zabbix
resource "grafana_data_source" "zabbix" {
type = "alexanderzobnin-zabbix-datasource"
name = "Zabbix-example"
url = "http://<zabbix-domain>/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://<jaeger-domain>/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 使用。
當(dāng)然喝滞,如果你直接在創(chuàng)建 Jaeger Datasource 的時(shí)候指定了 uid, 如下所示阁将,那么后面在被其他 Datasource 引用時(shí)可以直接指定寫(xiě)死。
uid = "example_jaeger"
ES
resource "grafana_data_source" "elasticsearch-example" {
type = "elasticsearch"
name = "es_example"
uid = "es_example"
url = "http://<es_host>: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}"
}
]
})
}
這里右遭,有以下幾個(gè)需要注意的地方:
-
database_name = "[example.*-]YYYY.MM.DD"
在 type 為 es 的情況下做盅,database_name 就是 es 的索引名稱(chēng) -
dataLinks
這里通過(guò) data link 鏈接到 Jagger Datasource:datasourceUid = data.grafana_data_source.jaeger-example.uid
(Jaeger Datasource 就是上一節(jié)創(chuàng)建的) -
url = "${"$"}{__value.raw}"
這里要特別注意,實(shí)際上傳給 Grafana 的是:${__value.raw}
, 但是這個(gè)恰好也是 Terraform 的模板/變量替換語(yǔ)法窘哈,所以如果直接這樣寫(xiě)會(huì)將其解析為模板/變量吹榴,從而出現(xiàn)該變量不存在的報(bào)錯(cuò)。通過(guò)${"$"}
轉(zhuǎn)義為$
+{__value.raw}
拼成正確的${__value.raw}
傳給 Grafana.
Prometheus
基礎(chǔ)配置如下:
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 兼容實(shí)現(xiàn) - 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"
})
}
創(chuàng)建 Dashboard
在 dashboard.tf
中滚婉,創(chuàng)建 dashboard 示例如下:
resource "grafana_dashboard" "metrics" {
config_json = file("grafana-dashboard.json")
}
也可以通過(guò)如下方式創(chuàng)建:
resource "grafana_dashboard" "metrics" {
config_json = jsonencode({
title = "as-code dashboard"
uid = "ascode"
})
}
??注意:
config_json
是 String 類(lèi)型腊尚,具體是完整的 Dashboard model JSON。
可以直接通過(guò) file("grafana-dashboard.json")
獲取满哪。
如第二個(gè)實(shí)例,jsonencode
的作用就是使用 JSON 語(yǔ)法將一個(gè) Object 轉(zhuǎn)換為 String.
總結(jié)
好了劝篷,本次我們介紹了 Grafana Terraform Provider 的基礎(chǔ)知識(shí)哨鸭,還是比較簡(jiǎn)單的,我們使用其:
- 創(chuàng)建 Provider
- 創(chuàng)建組織
- 創(chuàng)建文件夾
- 創(chuàng)建各類(lèi)常見(jiàn)的 Datasources
- 創(chuàng)建 Dashboard
非常直白清晰娇妓。希望對(duì)各位有所幫助像鸡。
???參考文檔
- Docs overview | grafana/grafana | Terraform Registry
- grafana_folder | Resources | grafana/grafana | Terraform Registry
- grafana_data_source | Resources | grafana/grafana | Terraform Registry
- grafana_dashboard | Resources | grafana/grafana | Terraform Registry
- jsonencode - Functions - Configuration Language | Terraform | HashiCorp Developer
- Strings and Templates - Configuration Language | Terraform | HashiCorp Developer
三人行, 必有我?guī)? 知識(shí)共享, 天下為公. 本文由東風(fēng)微鳴技術(shù)博客 EWhisper.cn 編寫(xiě).