1. 这不是“点几下就完事”的操作,而是监控系统里最关键的神经接口
你刚在服务器上跑起 Prometheus,看着http://localhost:9090/metrics里密密麻麻的process_cpu_seconds_total、go_memstats_heap_alloc_bytes指标,心里踏实了一半——数据有了。但下一秒打开 Grafana,面对空荡荡的“Create your first dashboard”提示,手却停住了:指标是活的,可它们不会自己长出图表来。这不是功能缺失,而是两个系统之间最核心的“神经接口”还没接通。Prometheus 是监控系统的心脏与血管,负责持续搏动、采集、存储时序数据;Grafana 则是它的视觉皮层与运动中枢,负责把原始脉冲翻译成可视化的血压曲线、心率热图,并驱动告警动作。而“添加 Prometheus Dashboard”这个动作,本质是给这套神经系统装上第一副能看清自身状态的眼镜——它不单是导入一个 JSON 文件,更是建立一套语义映射:告诉 Grafana,“node_cpu_seconds_total{mode="user"}”这个字符串,对应的是“CPU 用户态使用率”这条线,横轴是时间,纵轴是秒/秒(即百分比),采样间隔应为 30 秒,且需叠加过去 6 小时的数据。我第一次部署时,就是卡在这一步:Dashboard 导入后图表全为空,排查了两小时才发现,问题不在 JSON 文件本身,而在 Prometheus Data Source 的Scrape Interval 配置与 Dashboard 中 Panel 查询的时间范围不匹配——Grafana 默认查最近 5 分钟,而我的 Prometheus 只每 2 分钟抓一次,导致大量时间点无数据。这提醒我:Dashboard 不是静态快照,而是动态查询的实时视图,它的生命力完全依赖于底层数据源的配置精度。所以,这篇文章不会只告诉你“点击 + Import”,而是带你亲手拧紧每一颗螺丝:从 Data Source 的认证方式选择(Basic Auth 还是 Bearer Token?为什么在 Kubernetes 环境中后者几乎是唯一安全选项),到 Dashboard JSON 中datasource字段的精确匹配逻辑(它必须与 Grafana 中 Data Source 的Name 字段完全一致,包括大小写和空格),再到导入后如何用Explore视图反向验证查询是否真正生效。你将看到的,是一个运维工程师在真实生产环境里,如何把 Prometheus 和 Grafana 从两个独立模块,焊接成一个呼吸同步的有机体。
2. Data Source:Dashboard 能否“看见”数据的唯一决定者
所有 Dashboard 的失效,90% 的根因都藏在这里——Data Source 配置。它不是安装完 Grafana 后的一个可选步骤,而是 Dashboard 存在的先决条件。就像你要看一张地图,首先得确认 GPS 信号是否已接入,否则再精美的地图也只是张静态图片。我们来拆解这个“信号接入”过程的核心细节。
2.1 URL 配置:别被 localhost 欺骗了
在本地开发环境,你可能习惯性地填http://localhost:9090。这在单机 Docker Compose 部署时或许能工作,但在任何稍复杂的场景下,它必然失败。原因很简单:Grafana 容器内部的localhost指向的是它自己,而不是宿主机上的 Prometheus。我曾在一个客户现场遇到过这个问题,他们用docker run -p 3000:3000 grafana/grafana启动 Grafana,Prometheus 则是另一个容器,网络模式是默认的 bridge。结果 Dashboard 全部报Failed to fetch data。解决方案不是改 URL,而是改网络——让两个容器处于同一个自定义 bridge 网络中:
# 创建网络 docker network create monitoring-net # 启动 Prometheus,指定网络并分配别名 docker run -d \ --name prometheus \ --network monitoring-net \ -p 9090:9090 \ -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \ prom/prometheus # 启动 Grafana,同样加入该网络 docker run -d \ --name grafana \ --network monitoring-net \ -p 3000:3000 \ -e "GF_SECURITY_ADMIN_PASSWORD=admin" \ grafana/grafana此时,在 Grafana 的 Data Source 配置中,URL 应填写http://prometheus:9090。这里的prometheus是容器名,Docker 内置 DNS 会自动将其解析为对应容器的 IP。这是容器化部署的黄金法则:永远用服务名(Service Name)代替 localhost 或 IP 地址。如果你用 Kubernetes,道理一样,URL 应为http://prometheus-service.monitoring.svc.cluster.local:9090,其中prometheus-service是 Service 名,monitoring是命名空间,svc.cluster.local是集群内 DNS 后缀。
2.2 认证方式:安全与便利的平衡点
Prometheus 默认不启用认证,但这绝不意味着 Grafana 可以裸连。在生产环境,你必须考虑两点:一是防止 Grafana 的 Data Source 配置被未授权用户导出(里面可能包含敏感地址),二是防止 Prometheus 的 metrics 端点被外部扫描。因此,认证是必选项。Grafana 提供了三种主流方式:
| 认证类型 | 适用场景 | 关键配置项 | 我的经验 |
|---|---|---|---|
| No Auth | 仅限完全隔离的本地测试环境 | 无需配置 | 一旦离开本机,立刻禁用。我把它视为“临时创可贴”,贴完就得撕掉。 |
| Basic Auth | Prometheus 已配置 Nginx 反向代理并启用了 HTTP Basic 认证 | Username / Password | 配置简单,但密码明文存储在 Grafana 数据库中(虽经加密,但非绝对安全)。适合中小团队快速上线。 |
| Bearer Token | Prometheus 运行在 Kubernetes 中,且通过 ServiceAccount Token 认证 | Bearer Token 字段 | 强烈推荐。Token 由 K8s 自动签发,有生命周期,权限可精细控制(如只读metrics)。Grafana 配置中只需粘贴 Token,无密码泄露风险。 |
提示:如果你的 Prometheus 是通过
kube-prometheus套件部署的,其 Service 默认启用了serviceAccountToken认证。获取 Token 的命令是:kubectl -n monitoring get secret prometheus-k8s-token-xxxxx -o jsonpath='{.data.token}' | base64 -d。把这个输出的长字符串,完整粘贴到 Grafana Data Source 的 Bearer Token 字段即可。
2.3 查询设置:让 Dashboard “呼吸”起来的关键参数
很多新手导入 Dashboard 后发现图表是空的,或者只显示最近几分钟的数据,问题往往出在这里。Data Source 的Query Options并非可有可无的高级设置,而是直接影响 Dashboard 行为的底层开关。
- Min step: 这个值决定了 Grafana 向 Prometheus 请求数据时,最小的时间步长(即每个数据点之间的时间间隔)。如果设为
10s,而你的 Prometheusscrape_interval是60s,那么 Grafana 实际拿到的就是每 60 秒一个点,10s的设置毫无意义,反而可能增加查询压力。最佳实践是将其设为 Prometheus 的scrape_interval值。你可以在 Prometheus 的/status页面或prometheus.yml配置文件中找到它。 - HTTP Method: 默认是
GET,但某些高负载场景下,Prometheus 的/api/v1/query_range接口对 GET 请求的 URL 长度有限制(通常 2048 字节)。当你的 Dashboard 查询包含大量标签过滤器(如job=~"app1|app2|app3|...")时,URL 可能超长,导致 414 错误。此时,将 HTTP Method 改为POST即可解决。这是一个典型的“小配置,大效果”的案例。 - Time Range Auto Adjust: 勾选此项后,Grafana 会根据当前面板的时间范围(如 Last 6 hours)自动调整查询的
start和end参数。这是绝大多数 Dashboard 的预期行为,务必保持勾选。如果取消,查询将始终使用固定时间范围,Dashboard 就失去了“实时滚动”的能力。
3. Dashboard 导入:JSON 文件背后的三重校验逻辑
当你从 Grafana 官方仪表盘库(https://grafana.com/grafana/dashboards/)下载一个 JSON 文件,比如著名的 Node Exporter Full(ID: 1860),你以为导入就是“上传 → 确认 → 完成”?不,这背后有三道隐形的校验关卡,任何一道失败,Dashboard 都会变成一堆无法渲染的空白面板。
3.1 第一重校验:Datasource 名称的精确匹配
这是最常见、也最容易被忽略的错误。Dashboard JSON 文件中,每一个 Panel(图表)的查询都硬编码了一个datasource字段。例如,一个 CPU 使用率 Panel 的 JSON 片段可能是:
{ "targets": [ { "expr": "100 - (avg by(instance) (rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)", "legendFormat": "{{instance}}", "refId": "A" } ], "datasource": "Prometheus" }注意最后一行"datasource": "Prometheus"。这个字符串"Prometheus"必须与你在 Grafana 中创建的 Data Source 的Name 字段完全一致。如果你在创建 Data Source 时,Name 填的是My-Prometheus或prometheus(小写),那么这个 Panel 就会找不到数据源,直接报错Data source not found。我见过太多人因为复制粘贴时多了一个空格,或者大小写不一致,折腾半天。导入前,请务必打开 Grafana 的 Data Sources 页面,记下你那个 Prometheus Data Source 的精确 Name。导入时,在弹出的对话框里,有一个下拉菜单让你选择目标 Data Source,这里的选择,就是在覆盖 JSON 文件中硬编码的datasource值。所以,即使 JSON 里写的是"Prometheus",只要你在这里选择了My-Prometheus,Grafana 就会自动把所有 Panel 的datasource字段替换成My-Prometheus。这是最安全的做法。
3.2 第二重校验:变量(Variable)的依赖关系
一个成熟的 Dashboard 往往包含多个下拉变量(Variables),比如job、instance、node。这些变量不是装饰品,它们是 Dashboard 的“交互式神经元”。它们的值会动态注入到每个 Panel 的 PromQL 查询中,实现“选一个节点,看它的所有指标”。但变量本身需要数据源来填充其可选项列表。例如,job变量的查询可能是label_values(node_cpu_seconds_total, job)。这个查询,同样需要指向一个有效的 Prometheus Data Source。如果这个变量所依赖的 Data Source 在导入时没有被正确关联(比如你导入时选错了 Data Source),那么变量下拉框就会是空的,进而导致所有依赖它的 Panel 查询失败,因为job的值是空的。导入后,第一步不是看图表,而是打开 Dashboard 右上角的变量下拉框,检查它们是否能正常加载出选项。如果不能,说明变量的 Data Source 配置有问题,需要进入 Dashboard Settings → Variables → 编辑该变量,手动为其指定正确的 Data Source。
3.3 第三重校验:Panel 查询的语法与语义有效性
即使前两关都过了,Dashboard 仍可能显示“no data”。这时,你需要深入到单个 Panel 的编辑模式。点击 Panel 标题 →Edit→ 切换到Metrics标签页。这里你会看到完整的 PromQL 查询。不要只看表达式,要重点检查:
- 标签匹配是否合理?例如,
node_cpu_seconds_total{job="node-exporter"}。你的 Prometheus 里,job标签的值真的是node-exporter吗?还是prometheus或kubernetes-nodes?这取决于你部署 Node Exporter 的方式。用curl http://<prometheus-ip>:9090/api/v1/label/job/values可以列出所有job的值。 - 时间范围是否足够?查询中的
[5m]表示计算过去 5 分钟的速率。如果你的 Prometheus 才启动了 2 分钟,那自然查不到数据。可以临时把[5m]改成[1m]来测试。 - 函数使用是否正确?
rate()函数要求时间窗口至少是scrape_interval的 4 倍,否则会返回NaN。如果你的scrape_interval是15s,那么[1m]是安全的,但[30s]就很可能失败。
注意:在 Grafana 的 Explore 视图中,你可以直接粘贴并执行任意 PromQL 查询,这是验证查询有效性的最快方法。它绕过了 Dashboard 的所有中间环节,直连 Prometheus,是排错的终极武器。
4. 从零开始构建:一个可落地的 Node Exporter 监控 Dashboard 实战
与其依赖一个庞大的、可能包含你不关心指标的官方 Dashboard,不如亲手搭建一个最小可行的(MVP)Dashboard。这不仅能让你彻底理解每个组件的作用,还能确保它 100% 匹配你的环境。下面,我将带你从零开始,构建一个只监控服务器 CPU、内存、磁盘和网络的核心 Dashboard。整个过程,你只需要一个文本编辑器和 Grafana 的 Web UI。
4.1 步骤一:创建四个核心变量
Dashboard 的灵魂在于交互性。我们先创建四个变量,让 Dashboard 活起来。
instance变量:用于选择要监控的具体服务器。- Name:
instance - Label:
Instance - Type:
Query - Data Source: 选择你配置好的 Prometheus Data Source
- Query:
label_values(node_cpu_seconds_total, instance) - Refresh:
On Dashboard Load - Multi-value: ✅ (允许选择多个实例进行对比)
- Include All option: ✅ (添加一个
All选项)
- Name:
job变量:用于区分不同类型的 exporter(虽然我们目前只有 node-exporter,但为未来扩展留接口)。- Name:
job - Label:
Job - Type:
Query - Data Source: 同上
- Query:
label_values(node_cpu_seconds_total, job) - Refresh:
On Dashboard Load
- Name:
cpu_mode变量:用于选择 CPU 模式(user, system, idle 等),方便切换查看。- Name:
cpu_mode - Label:
CPU Mode - Type:
Custom - Custom all value:
.*(正则匹配所有) - Options:
user,system,idle,iowait,irq,softirq
- Name:
time_range变量:用于快速切换时间范围,替代右上角的全局时间选择器。- Name:
time_range - Label:
Time Range - Type:
Custom - Options:
1h,6h,24h,7d - Default:
6h
- Name:
提示:变量的
Refresh设置至关重要。On Dashboard Load意味着每次打开 Dashboard 时,变量选项都会重新从 Prometheus 拉取最新数据,确保你看到的是真实的、最新的服务器列表。如果设为Never,变量列表将永远停留在你第一次创建时的状态。
4.2 步骤二:添加第一个 Panel —— CPU 使用率
现在,我们添加第一个真正的监控图表:CPU 使用率。
- 点击
+ Add new panel。 - 在 Metrics 标签页,输入 PromQL:
这个表达式的意思是:对每个100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle", instance=~"$instance", job=~"$job"}[5m])) * 100)instance,计算过去 5 分钟内idle模式的 CPU 时间占比,然后用100减去它,得到实际使用率。$instance和$job是变量占位符,Grafana 会在查询时自动替换为用户在变量下拉框中选择的值。 - 在 Visualization 标签页,选择
Time series。 - 在 Display 标签页,勾选
Stack series,这样多个实例的曲线会堆叠显示,便于直观比较总量。 - 在 Panel Options 标签页,设置 Title 为
CPU Usage (%)。 - 点击右上角
Apply。
4.3 步骤三:添加第二个 Panel —— 内存使用率
- 再次点击
+ Add new panel。 - 输入 PromQL:
这里我们用(node_memory_MemTotal_bytes{instance=~"$instance", job=~"$job"} - node_memory_MemAvailable_bytes{instance=~"$instance", job=~"$job"}) / node_memory_MemTotal_bytes{instance=~"$instance", job=~"$job"} * 100MemAvailable(Linux 3.14+)而非MemFree,因为它更准确地反映了真正可用的内存(排除了可回收的缓存)。 - Visualization 选择
Time series。 - Title 设为
Memory Usage (%)。
4.4 步骤四:添加第三个 Panel —— 根分区磁盘使用率
- 新建 Panel。
- PromQL:
这里我们加了100 * (node_filesystem_size_bytes{mountpoint="/", fstype=~"ext4|xfs", instance=~"$instance", job=~"$job"} - node_filesystem_free_bytes{mountpoint="/", fstype=~"ext4|xfs", instance=~"$instance", job=~"$job"}) / node_filesystem_size_bytes{mountpoint="/", fstype=~"ext4|xfs", instance=~"$instance", job=~"$job"}fstype过滤,确保只监控 ext4 或 xfs 文件系统,避免因挂载了 NFS 或其他类型文件系统而引入噪音。 - Title:
Root FS Usage (%)。
4.5 步骤五:保存与分享
- 点击右上角
Save按钮。 - 给 Dashboard 命名为
My Server Monitor。 - 点击
Save确认。
现在,你拥有了一个完全属于自己的、轻量级、可定制的监控 Dashboard。它没有冗余的图表,每一个 Panel 都是你亲手写的、理解其含义的查询。更重要的是,它已经内置了变量交互,你可以轻松地在不同服务器、不同时间范围之间切换。这就是从“使用者”迈向“构建者”的关键一步。后续,你可以基于这个 MVP,逐步添加网络流量、进程数、温度等更多 Panel,让它成长为你的专属监控中心。
5. 故障排查全景图:从“图表为空”到“数据飞升”的完整链路
在 Grafana 世界里,“图表为空”是最常见的报错,但它背后的原因千差万别。与其大海捞针,不如按一个清晰的、自底向上的排查链路来系统性地诊断。这个链路,我称之为“三层漏斗模型”,从最底层的基础设施,逐层向上,直到最顶层的用户交互。
5.1 第一层漏斗:基础设施层(Is the data even there?)
这是最根本的问题。如果 Prometheus 本身就没有采集到数据,那么 Grafana 再怎么努力也是无米之炊。
- 检查 Prometheus Target 状态:访问
http://<prometheus-ip>:9090/targets。这里列出了所有被 Prometheus 主动抓取的目标(Targets)。找到你的node-exporter(或其他 exporter)那一行,观察其State列。如果是UP,说明抓取成功;如果是DOWN,则需要检查 exporter 是否在运行、网络是否通畅、Prometheus 的scrape_config是否配置正确。Last Scrape时间应该在几秒到几十秒内更新。 - 直接查询 Prometheus API:在浏览器中访问
http://<prometheus-ip>:9090/api/v1/query?query=node_cpu_seconds_total{mode="user"}。如果返回了类似{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"node_cpu_seconds_total","instance":"192.168.1.100:9100","job":"node-exporter","mode":"user"},"value":[1712345678.123,"12345.67"]}]}}的 JSON,说明数据存在且可访问。如果返回{"status":"error","errorType":"bad_data","error":"invalid parameter \"query\": empty query string"},说明你的查询语法有误;如果返回404,说明 Prometheus 服务本身不可达。
5.2 第二层漏斗:Grafana Data Source 层(Can Grafana talk to it?)
数据存在了,但 Grafana 能否顺利“对话”?
- Test & Save:回到 Grafana 的 Data Source 配置页面,点击右上角的
Save & test按钮。Grafana 会立即尝试连接 Prometheus 并执行一个简单的健康检查查询。如果这里报错,比如HTTP Error Bad Gateway (502),说明网络或认证配置有误;如果报Unauthorized,说明用户名/密码或 Token 错误。这是最快速的验证方式。 - 检查日志:如果
Save & test成功,但 Dashboard 仍为空,那就需要看 Grafana 的日志。在 Docker 环境中,执行docker logs grafana;在 systemd 环境中,执行journalctl -u grafana-server -f。查找包含prometheus或datasource关键字的 ERROR 或 WARN 日志。我曾经遇到过一个案例,日志里有一行Failed to execute query: context deadline exceeded,这明确指向了网络超时,最终发现是防火墙规则限制了 Grafana 容器到 Prometheus 容器的 9090 端口。
5.3 第三层漏斗:Dashboard 层(Is the query right?)
数据源通了,最后的障碍就是 Dashboard 本身的查询逻辑。
- Use Explore:这是最强大的工具。在 Grafana 左侧菜单,点击
Explore图标。在顶部选择你的 Prometheus Data Source。然后,把你 Dashboard 中某个 Panel 的 PromQL 完整粘贴进去,点击Run query。如果 Explore 能返回数据,而 Dashboard 不能,那问题 100% 出在 Dashboard 的配置上(比如变量没关联好,或者 Panel 的datasource字段写错了)。如果 Explore 也返回空,那就回到第二步,检查查询本身。 - 检查变量值:在 Dashboard 页面,把鼠标悬停在右上角的变量下拉框上,Grafana 会显示一个 tooltip,告诉你当前选中的值是什么。确保它不是
<no value>或All(如果你的查询不支持All,比如node_cpu_seconds_total{instance="All"}是非法的)。 - 检查时间范围:Grafana 右上角的时间选择器,其范围必须覆盖 Prometheus 中数据的时间戳。如果你的 Prometheus 只保留了 24 小时的数据,而你把时间范围设为
Last 7 days,那自然查不到东西。可以临时把时间范围调小到Last 5 minutes来测试。
最后一个经验:当你反复排查无果时,最有效的方法是“降级验证”。新建一个最简 Dashboard,只包含一个 Panel,只用一个最简单的查询,比如
count(node_cpu_seconds_total)。如果这个最简版能工作,说明你的基础环境是 OK 的,问题一定出在你原来那个复杂 Dashboard 的某个特定配置上。然后,你就可以像剥洋葱一样,一层层地添加回原来的变量、Panel 和查询,直到找到那个“引爆点”。这是一种极其高效、且能极大提升你对系统理解深度的排错哲学。