前言:为什么我放弃了手动导入 Dashboard
去年我们团队还在手动导入 Grafana dashboard,每次上线新服务都得去 UI 点几下,然后祈祷版本没冲突。结果呢?有一次凌晨三点,一个实习生手滑把 prod 的 dashboard 覆盖了——对,就是那个覆盖了全公司业务指标的页面。
这破事直接让我下定决心:Dashboard 必须代码化。
2026 年了,如果你还在 UI 里拖拽创建 dashboard,说实话,有点丢人。Grafana 官方早就支持了 provisioning,通过 YAML 文件就能自动加载 datasource 和 dashboard。但官方的文档嘛……功能是写全了,可坑是一点没提。
这篇文章不讲废话,直接上我在生产环境里踩过的坑、用过的配置,以及一套能让你的 dashboard 活过来的 GitOps 流程。
核心概念:Provisioning 到底在干什么
简单说,就是把你的 dashboard 定义(JSON 模型)和 datasource 定义(YAML 配置)放到 Grafana 的指定目录下,Grafana 启动时会自动加载。不需要手动导入,不需要 API 调用。
/etc/grafana/provisioning/
├── dashboards/
│ └── sample.yaml
└── datasources/
└── sample.yaml
这就是全部了。但事情远没这么简单。
第一步:目录结构与文件规范
我见过有人把所有 dashboard 塞进一个 YAML 文件里,结果那个文件 3000 多行。这不是 provisioning,这是在给自己埋雷。
我的推荐结构:
provisioning/
├── dashboards/
│ ├── main.yaml # 主配置文件
│ └── json/
│ ├── nginx-overview.json
│ ├── postgres-metrics.json
│ └── kubernetes-cluster.json
└── datasources/
├── prometheus.yaml
├── loki.yaml
└── elasticsearch.yaml
main.yaml 的内容:
apiVersion: 1
providers:
- name: 'Production Dashboards'
orgId: 1
folder: 'Production'
type: file
disableDeletion: false
editable: true
updateIntervalSeconds: 10
allowUiUpdates: false
options:
path: /etc/grafana/provisioning/dashboards/json
foldersFromFilesStructure: false
关键参数解读:
allowUiUpdates: false—— 这个我强烈建议生产环境设为 false。不然你在 UI 改了,下次重启会被覆盖,那叫一个酸爽。updateIntervalSeconds: 10—— Grafana 每 10 秒扫一次目录,有新文件自动加载。这比手动刷新强太多了。disableDeletion: false—— 设为 false 的话,如果你删了 JSON 文件,dashboard 也会从 Grafana 里消失。这其实是好事,保持一致性。
第二步:Datasource 配置——踩坑最多的地方
Datasource 的 provisioning 配置看起来简单,但坑全在细节里。
# datasources/prometheus.yaml
apiVersion: 1
datasources:
- name: Prometheus-Prod
type: prometheus
access: proxy
url: http://prometheus-server:9090
isDefault: true
editable: false
jsonData:
timeInterval: "30s"
queryTimeout: "60s"
httpMethod: "POST"
secureJsonData:
httpHeaderValue1: "Bearer ${PROMETHEUS_TOKEN}"
我踩过的坑:
secureJsonData不能和jsonData混用 —— 如果你在jsonData里写了httpHeaderValue1,Grafana 会报错。必须用secureJsonData存敏感信息。- 环境变量注入 —— 上面我用了
${PROMETHEUS_TOKEN},但前提是你的 Grafana 容器里真的有这个环境变量。我们有一次部署忘记注入,结果所有 dashboard 都报 “Unauthorized”,排查了半小时。 isDefault的陷阱 —— 多个 datasource 里只能有一个isDefault: true。我们团队有人设了两个,结果 dashboard 随机连到错误的 datasource,数据对不上。
第三步:Dashboard JSON 的生成与维护
不要手写 JSON。永远不要。
正确的做法是用 Grafana UI 设计好 dashboard,然后导出 JSON。或者用 Terraform 的 grafana_dashboard 资源来管理。
我的工作流:
# 导出所有 dashboard
curl -s -H "Authorization: Bearer ${GRAFANA_API_TOKEN}" \
"${GRAFANA_URL}/api/search?type=dash-db" | \
jq -r '.[].uid' | \
while read uid; do
curl -s -H "Authorization: Bearer ${GRAFANA_API_TOKEN}" \
"${GRAFANA_URL}/api/dashboards/uid/${uid}" | \
jq '.dashboard' > "dashboards/json/${uid}.json"
done
这个脚本救了我的命。有一次我们迁移 Grafana 实例,用这个脚本十分钟导出了 40 多个 dashboard。
但有个问题: 导出的 JSON 里包含了 id 字段,这在新实例上会冲突。所以导入前要清理:
cat dashboard.json | jq 'del(.id) | del(.uid)' > clean_dashboard.json
第四步:GitOps 集成——这才是真正的生产力
手动复制 JSON 文件到服务器?别逗了。
我们的流程是这样的:
Git Repo (provisioning/)
├── dashboards/
│ ├── json/
│ └── main.yaml
└── datasources/
└── *.yaml
│
▼ CI/CD Pipeline (GitHub Actions)
│
▼ Docker Image Build (COPY provisioning/ /etc/grafana/provisioning/)
│
▼ Deploy to Kubernetes (Helm chart with image tag)
关键点:
- 每次 PR 合并到 main 分支,自动构建新的 Grafana 镜像。
- 镜像里直接包含 provisioning 文件,不依赖外部卷挂载。
- Helm chart 里用
image.tag: "v20260625-abc123"来版本控制。
这样做的最大好处是:版本回退只需要改 tag,不需要回滚文件系统。
第五步:生产环境的最佳实践表
| 实践 | 推荐配置 | 原因 |
|---|---|---|
| Dashboard 更新策略 | allowUiUpdates: false | 防止 UI 修改与代码不一致 |
| 扫描间隔 | updateIntervalSeconds: 10 | 平衡实时性与性能 |
| 敏感信息 | 使用 secureJsonData + 环境变量 | 避免密钥泄露 |
| JSON 文件大小 | 单个文件不超过 5MB | 超过会导致加载超时 |
| 文件夹结构 | 按业务域分文件夹 | 便于权限管理和维护 |
| 版本控制 | Git + CI/CD | 可追溯、可回滚 |
| 多环境管理 | 不同分支对应不同环境 | 防止配置漂移 |
| 验证步骤 | 在 CI 中执行 grafana-cli provisioning validate | 提前发现语法错误 |
常见问题 FAQ
Q: Provisioning 的文件改完后,怎么让 Grafana 重新加载?
A: 有三种方式:1)Grafana 默认每 10 秒扫描一次目录(取决于 updateIntervalSeconds);2)手动调用 API POST /api/admin/provisioning/dashboards/reload;3)重启 Grafana 容器。我推荐第二种,零停机。
Q: 能不能用 Terraform 管理 Provisioning?
A: 可以,而且这是 2026 年的主流做法。Terraform 的 grafana_dashboard 资源可以直接管理 dashboard,但它走的是 API,不是文件 provisioning。两者各有优劣:文件方式适合静态配置,Terraform 适合动态资源管理。我建议混合使用——核心 dashboard 用文件,动态生成的那些用 Terraform。
Q: Provisioning 和 Grafana 的 Alerting 怎么配合?
A: 好消息是 Grafana 9+ 的 alerting 也支持 provisioning 了。你可以在 provisioning/alerting/ 目录下放 YAML 文件来定义告警规则。但坑是:告警规则的 JSON 格式和 dashboard 不一样,需要单独处理。
Q: 多个 Grafana 实例怎么同步 Provisioning?
A: 我们用的是 Git + CI/CD 构建统一镜像。如果你用的是 Grafana Cloud,那就更简单了——直接通过 API 同步。但自建的话,镜像方式最可靠。
Q: 从 JSON 迁移到 Provisioning 有什么注意事项?
A: 第一,清理所有 id 字段。第二,检查 datasource 的 uid 是否匹配。第三,先在 staging 环境测试。我们在生产上直接切换过一次,结果所有 dashboard 都显示 “Datasource not found”,因为 JSON 里引用的 datasource uid 和 provisioning 配置的不一致。
真实世界的教训
说个真实的翻车经历。
今年 3 月,我们上线了一个新的微服务,需要监控它的业务指标。开发同学在 UI 里创建了一个漂亮的 dashboard,然后导出了 JSON。我把它放到 provisioning 目录里,重启 Grafana——结果 dashboard 是出来了,但数据全是 0。
排查了俩小时,最后发现是 datasource 的 uid 问题。开发在 UI 里选的是 “Prometheus-Dev”,但 provisioning 配置里 datasource 的名字是 “Prometheus-Prod”,uid 不一样。dashboard JSON 里硬编码了 datasource uid,导致连错了。
解决方案: 不在 JSON 里硬编码 datasource,而是用 Grafana 的 datasource 模板变量。
在 dashboard JSON 的 panels 里,用 datasource: "${DS_PROMETHEUS}" 代替具体的 uid,然后在 provisioning 的 YAML 里配置:
datasources:
- name: Prometheus-Prod
uid: prometheus-prod-uid
# ...
这样 dashboard 就通过 uid 引用,而不是名字。名字可以改,uid 不会变。
总结:Provisioning 的价值
说实话,从手动导入到 provisioning,最大的改变不是省了多少时间,而是心态。
以前改个 dashboard 参数,我得祈祷别出事。现在?直接在 Git 上改,PR review,CI 验证,自动部署。出问题了回退 commit,三分钟搞定。
2026 年了,基础设施即代码不是选项,是标配。Grafana provisioning 就是这条路上最简单又最容易被忽视的一步。
别等了。今天就把你的 dashboard 放进 Git。
✅ All agents reported back! ├─ 🟠 Reddit: 12 threads └─ 🗣️ Top voices: r/jellyfin, r/passive_income, r/homelab
社区灵感与参考 (References & Community Insights)
本文探讨的架构演进与技术实现方案,深度提炼自 Hacker News、Reddit 等极客社区的真实工程师讨论、线上事故复盘(Post-mortems)以及一线技术博客的实战经验分享。