news 2026/10/1 1:18:20

Prometheus + Grafana 监控栈搭建实战:从Docker Compose部署到告警接入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Prometheus + Grafana 监控栈搭建实战:从Docker Compose部署到告警接入

第一次真正把这套组合部署到生产环境,是在一个周五的晚上。当时团队用的还是老式监控方案,告警全靠邮件排队,服务器一多,面板就乱成一锅粥。我花了一个周末的时间,把Prometheus + Grafana 这套开源监控栈完整搭起来,从那以后就再也没换回去过。这篇文章打算把实际的监控搭建过程和 Grafana 界面基础配置完整记录下来——包括 Docker Compose 方案选型、Node Exporter 和 OpenTelemetry Collector 的数据采集链路、告警规则怎么写、Alertmanager 怎么接,以及我在使用中踩过的几个典型坑和对应的排查套路。无论是刚接触监控的新手,还是想从零搭建一套可靠监控体系的小团队,这篇都能给你一套可以直接抄作业的底子。

1. 为什么开源监控方案里偏偏是 Prometheus 和 Grafana

1.1 开源协议和生态位置,决定了这套组合的生命力

先说个很多人会问到的问题:Prometheus 是开源的吗?是的,而且不是那种"挂着开源名字、核心功能全收费"的开源。Prometheus 采用 Apache 2.0 协议,目前由云原生计算基金会(CNCF)维护,是继 Kubernetes 之后第二个从 CNCF 毕业的项目。这意味着它的代码你可以放心用,也意味着它的社区活跃度、版本迭代节奏、周边生态,都有大厂和大量开发者在持续贡献。

Grafana 走的是不一样的路线。Grafana 本身是开源的,遵循 AGPLv3 协议,核心功能完全免费,企业版则是额外的高级功能和服务。对我们大多数场景来说,开源版已经足够。

真正让 Prometheus 有优势的,是它的exporter 生态。几乎你能想到的每一种中间件、数据库、硬件设备,都有现成的 exporter 可以直接接入:Node Exporter 管主机,MySQL Exporter 管数据库,Redis Exporter 管缓存,SNMP Exporter 管网络设备。我在同一个监控面板里既看到 Kubernetes 集群的 Pod 状态,又看到几台老交换机的端口流量,靠的就是这套统一采集格式,整个监控体系不用造轮子,所有指标都长成一个样子。

1.2 Pull 模型:为什么监控端要主动去"抓"而不是等数据"送"

Prometheus 的数据采集模型是Pull(拉取)模型,也就是监控端主动向被监控对象的某个 HTTP 端点发起请求,周期性获取指标。这和传统的 Agent 主动上报(Push)模型有本质区别。

这个设计带来的好处,在实际运维里非常明显:

  • 被监控对象不需要知道监控端存在,只要暴露一个/metrics端点即可。
  • 监控端可以从自己的视角判断目标是否存活,up指标就是这个用途。
  • 数据采集行为是可控的,监控端可以随时调整抓取频率或不抓取某些目标。
  • 在 Kubernetes 场景下,新的 Pod 一创建,Prometheus 通过服务发现就能自动找到并开始采集。

Pull 模型也有它的缺点,最典型的是跨网络区域的场景。比如你要采集一个位于隔离网段的服务器的指标,监控端访问不到它,这时候就需要一个Pushgateway作为中间层,让被监控端主动把指标推送到 Pushgateway,再由 Prometheus 去抓取。我一般只在 cron 任务、批处理这类短命任务里用 Pushgateway,常驻服务还是直接暴露端点更干净。

1.3 什么场景下适合这套组合,什么场景不适合

按我自己的实践经验,Prometheus + Grafana 最适合这几类场景:

场景适配程度原因
单机或少量服务器的基础监控非常适合部署简单,Node Exporter + 一个面板就够
中小团队的应用和中间件监控非常适合exporter 生态丰富,Grafana 面板成熟可用
Kubernetes 集群监控当前事实标准服务发现、Pod 指标、容器监控天然契合
超大规模、超长期指标存储不太适合本地存储有容量上限,需要扩展 Thanos 或 Cortex

很多人上来就问"这套能不能替代 XX",我的回答是:得看你的数据规模和你愿意投入的运维成本。Prometheus 单实例本地存储默认只保留 15 天,即使你调大保留时间,单机磁盘和查询性能早晚会成为瓶颈。真到了那个量级,需要引入 Thanos 做对象存储归档,或者用 Cortex/Mimir 做多租户方案。但在绝大多数中小规模场景下,Prometheus + Grafana 就是性价比最高的答案。

2. Docker Compose 一条龙部署:从目录结构到验证监控

2.1 为什么选择 Docker Compose 而非直接装二进制

我当时做选型时对比过两种方案:直接下载二进制文件分别部署,或者用 Docker Compose 编排出整套环境。最终选了 Compose,原因是它把一个系统的多个组件封装成了统一的编排文件,启动、停止、重启都是同一条命令,升级时改镜像标签再up -d就行,回滚也快。

二进制部署的好处是性能损耗小、故障排查更直接,但代价是你要自行管理 systemd 服务、配置文件路径、日志轮转,四个组件下来重复劳动非常多。Docker Compose 比较适合中小环境,而且 Prometheus 官方镜像本身就是为容器场景打造的,配合数据目录挂载,完全能满足持久化要求。

还有一个很实际的问题:四个组件分别部署的话,端口、网络、依赖关系都要记在脑子里。用 Compose 后,所有服务都在同一个自定义网络里,Prometheus 可以直接通过服务名访问 Grafana 和 Alertmanager,不用记 IP 地址。

2.2 项目目录规划与镜像版本说明

我先建一个干净的目录,把每个组件的数据目录和配置分离,将来备份、迁移、排查都省事:

monitor-stack/ ├── docker-compose.yml ├── prometheus/ │ ├── prometheus.yml │ ├── rules/ │ │ └── node-alerts.yml │ └── data/ ├── grafana/ │ └── data/ └── alertmanager/ └── alertmanager.yml

镜像版本我也建议一开始就固定下来。踩过不少次"latest 镜像行为突变"的坑之后,我的习惯是明确到小版本。比如我用的是prom/prometheus:v2.53.0、grafana/grafana:11.1.0、prom/alertmanager:v0.27.0、prom/node-exporter:v1.8.2。拉镜像时如果下载速度不理想,可以给 Docker 配置镜像加速器,或者换用其他连接方式解决,不必在版本选择上将就。

2.3 Docker Compose 配置与端口规划

下面是完整的docker-compose.yml,里面包含了 Prometheus、Grafana、Alertmanager 和 Node Exporter 四个核心组件:

version: '3.8' networks: monitor: services: prometheus: image: prom/prometheus:v2.53.0 container_name: prometheus restart: always volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml - ./prometheus/rules:/etc/prometheus/rules - ./prometheus/data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--storage.tsdb.retention.time=30d' ports: - "9090:9090" networks: - monitor grafana: image: grafana/grafana:11.1.0 container_name: grafana restart: always volumes: - ./grafana/data:/var/lib/grafana ports: - "3000:3000" networks: - monitor alertmanager: image: prom/alertmanager:v0.27.0 container_name: alertmanager restart: always volumes: - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml ports: - "9093:9093" networks: - monitor node-exporter: image: prom/node-exporter:v1.8.2 container_name: node-exporter restart: always command: - '--path.rootfs=/host' volumes: - /:/host:ro,rslave ports: - "9100:9100" networks: - monitor

端口规划上,我习惯保持 Prometheus 的 9090、Grafana 的 3000、Alertmanager 的 9093 不变,因为这些是各组件默认端口,面板、API、文档里的默认写法都基于这些端口,硬要改反而会增加不必要的成本。Node Exporter 的 9100 在容器里映射出来后,宿主机上的指标也能被采集到。

注意node-exporter容器里挂载宿主机根目录的写法,这是为了让容器内看到宿主机真实的/proc和/sys文件系统信息,否则采集到的 CPU、内存、磁盘数据是容器自己那一套,参考价值不大。--path.rootfs=/host告诉 Node Exporter 从挂载位置读取宿主机底层的数据。

2.4 Prometheus 主配置文件解析与首次启动

prometheus/prometheus.yml是整个监控的数据入口,核心内容如下:

global: scrape_interval: 15s evaluation_interval: 15s rule_files: - /etc/prometheus/rules/*.yml scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] - job_name: 'node-exporter' static_configs: - targets: ['node-exporter:9100'] labels: host: 'monitor-server'

这里最关键的一个参数是scrape_interval,它决定 Prometheus 多久来采集一次数据。15 秒对绝大多数监控场景足够,既不会产生太大存储压力,也能及时感知故障。如果你监控的是核心支付链路,可能需要调到 5 秒,但这会直接放大磁盘写入量,我一般不轻易动全局配置。

启动时在monitor-stack目录下执行:

docker compose up -d

等几十秒,逐一验证:

# 查看容器状态 docker compose ps # 验证 Prometheus 自身指标端点 curl http://localhost:9090/metrics | head -20 # 验证 Node Exporter 是否提供了宿主机指标 curl http://localhost:9100/metrics | head -20

然后打开浏览器访问http://localhost:9090/targets,正常情况下能看到prometheus和node-exporter两个 target 的状态都是 UP。这个页面是整个 Prometheus 数据链路是否健康的晴雨表,后面排查问题时第一步一定会来这里。

3. 数据从哪来:从 Node Exporter 到 OpenTelemetry Collector 的采集链路

3.1 Node Exporter 是主机监控的地基

部署完之后的第一个数据源,绝大多数是我们自己的主机。Node Exporter 通过读取操作系统的/proc、/sys等虚拟文件系统,把 CPU、内存、磁盘、网络、文件系统等指标暴露出来,Prometheus 每 15 秒抓取一次,形成时间序列。

常用的指标我列几个,刚上手的人可以拿这些去 Grafana 里练手:

指标名含义常见用途
up目标抓取状态判断被监控对象是否存活
node_cpu_seconds_totalCPU 累计使用秒数计算 CPU 使用率
node_memory_MemTotal_bytes内存总量内存使用率
node_filesystem_avail_bytes文件系统可用空间磁盘容量告警
node_network_receive_bytes_total网卡累计接收字节网卡流量

看这几个指标名你会发现一个规律:Prometheus 的指标名后缀常常是_total,代表它是一个计数器(Counter),只增不减。CPU 累计时间、网卡累计流量这些指标本身没有直接意义,要在查询里用rate()函数计算出每秒的变化速率,才是有意义的使用率。这是 Prometheus 查询和传统监控区别最大的一点,后面写查询表达式时会反复遇到。

3.2 OpenTelemetry Collector 和 Prometheus 是怎么对接的

现在很多应用都在接入 OpenTelemetry 进行链路追踪和指标采集,随之而来一个问题:Prometheus 是如何从 otel-collector 收取数据的?

这里的关键是 OpenTelemetry Collector 的prometheus exporter。它的作用是,把 Collector 从各种应用那里收集来的指标,转换成 Prometheus 格式,然后暴露一个/metrics端点。Prometheus 端只需要把这个端点当成一个普通的 target 来抓取即可。

一个最小的 otel-collector 配置片段如下:

receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 processors: batch: exporters: prometheus: endpoint: 0.0.0.0:9464 namespace: app service: pipelines: metrics: receivers: [otlp] processors: [batch] exporters: [prometheus]

在这个配置里,应用通过 OTLP 协议把指标数据推到 Collector 的 4317 端口,Collector 经过 batch 处理后,通过 prometheus exporter 在 9464 端口把指标暴露出去。后续在 Prometheus 的scrape_configs里增加这一段:

- job_name: 'otel-collector' static_configs: - targets: ['otel-collector:9464'] labels: service: 'otel-demo'

数据链路就是:应用 → otel-collector → Prometheus → Grafana。

这里有个容易混淆的点:Prometheus 也能通过 remote write 协议把数据推送给其他后端,或者让其他采集器以 remote write 方式写入它。但在"Prometheus 从 otel-collector 收数据"这个方向,正式的对接方式就是上面这种——otel-collector 通过 prometheus exporter 暴露端点,Prometheus 主动拉取。把这个关系理清楚,排查"Collector 收到了数据但 Prometheus 里查不到"这类问题时,就知道该去哪一端查。

3.3 特殊情况:交换机、数据库等不在默认采集范围内的设备

服务器监控靠 Node Exporter,应用监控靠 otel-collector,那交换机、路由器这类网络设备怎么办?答案是SNMP Exporter。

SNMP Exporter 需要一份生成好的snmp.yml配置文件,告诉它设备上每个 OID 对应什么指标。官方仓库里已经内置了常用设备厂商的配置模板,比如思科、华为、H3C 等。实际使用时,用snmp_exporter的 generator 工具根据设备的 MIB 库生成自定义配置,然后把 Prometheus 的 target 指向网络设备的 IP 和 SNMP 端口,端口流量、CPU 利用率、温度传感器都能采集上来。

数据库和中间件也是同样的套路:MySQL 用mysqld_exporter,Redis 用redis_exporter,Kafka 用kafka_exporter。你会发现这套监控体系的扩展方式出奇一致——跑一个 exporter,暴露一个端口,Prometheus 里加一个 job。这也是它的生态能滚雪球一样壮大的核心原因。

3.4 搞懂数据模型,查询表达式才写得出来

用 Grafana 画图前,一定要先理解 Prometheus 的数据模型。它本质上是把每个指标组织成一条条带标签的时间序列:

metric_name{label1="value1", label2="value2"} value timestamp

标签的作用是维度。比如up{job="node-exporter", instance="node-exporter:9100"},这个job和instance不是写在指标里的,是 Prometheus 在抓取时自动附加的标签,用来标识数据的来源。你在 Grafana 里最常见到的下拉筛选,本质就是对标签的过滤。

PromQL 的核心逻辑可以浓缩成三步:先选指标,再过滤标签,最后用函数计算。比如查询"某个主机的 CPU 使用率",表达式长这样:

100 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100

先用rate()算出 CPU 空闲状态的每秒变化量,求平均后转成百分比,再用 100 减去它,得到的就是过去 5 分钟的 CPU 使用率。刚开始写复杂表达式时容易懵,我的建议是从单指标、单函数的简单查询开始,先在 Prometheus 的 Graph 页面里看结果,确认没问题再搬到 Grafana 面板里。

4. Grafana 界面基础配置:数据源、导入面板与变量联动

4.1 添加 Prometheus 数据源的三个易错点

打开 Grafana,默认账号密码是admin/admin,首次登录会让你修改密码,这个不难。真正容易出错的是添加数据源这一步。

路径是Connections -> Data sources -> Add data source,选择 Prometheus,在 HTTP URL 一栏填http://prometheus:9090。注意这里填的一定是容器网络内的服务名prometheus,而不是localhost。如果填localhost:9090,Grafana 容器内访问的是它自己的回环地址,那里并没有 Prometheus 在监听,结果必然是 Connection refused。

填完后点Save & test,看到绿色提示才算配好。我见过不少人在这一步卡住,多半是网络配置或者 URL 填错,进容器的docker exec -it grafana sh里用wget测一下就能定位。

4.2 导入仪表盘和"拷贝整个面板"的正确姿势

Grafana 里最爽的一点是海量的现成仪表盘。打开 Dashboards 页,点New -> Import,输入一个面板 ID 就能从 Grafana.com 拉取。比如 Node Exporter 的常用面板 ID 是1860,输入后选择数据源,导入就能看到一张很完整的主机监控面板。

那"拷贝整个面板"是怎么回事?我遇到过这样的场景:在一个环境里精心调好了一张面板,想原封不动搬到另一个 Grafana 实例。直接拖拽显然不行,标准做法是:

  1. 在源面板右上角Share -> Export,选择Save to file,拿到一个 JSON 文件。
  2. 在目标 Grafana 里New -> Import -> Upload dashboard JSON file,上传这个文件。

这里有个隐藏问题:面板 JSON 里会记录源实例的datasource信息,包括数据源的 UID。如果目标实例的数据源 UID 不一样,导入后图表会显示"Data source not found"或找不到数据。解决办法有两个:导入时注意选择目标数据源,或者直接编辑 JSON 文件,把datasource字段里的uid替换成目标数据源的真实 UID。后者处理几十个面板的批量迁移时效率高得多。

4.3 模板变量:让一张面板管所有机器

一次性监控一台主机很容易,但生产环境往往有几十台机器。如果每台机器都建一张独立面板,你会发现维护成本直线上升,加一台新机器就要复制改一遍。

Grafana 的模板变量(Template Variables)就是用来解决这个问题的。在面板右上角Settings -> Variables里新增一个变量,类型选 Query,查询语句写成:

label_values(up, instance)

这个变量会把当前 Prometheus 里所有up指标的instance标签值拉出来,形成下拉框选项。然后在面板所有查询里把写死的 instance 替换成$instance,比如:

100 - avg(rate(node_cpu_seconds_total{instance="$instance", mode="idle"}[5m])) * 100

这样一张面板就能同时服务所有机器,下拉框选谁就显示谁的监控。新机器加入后,只要在 Prometheus 配置里加了 target,面板下拉框自动就会多出这个实例,不需要任何额外操作。

4.4 Grafana 升级后的老大难:legacy queries 报错

用 Grafana 的人应该都见过这类报错:

failed to upgrade legacy queries datasource im7_otuvz was not found

这个错误通常在从 Grafana 9.x 升级到更高版本后出现。老版本面板里的查询是旧格式,升级后 Grafana 会把它们自动迁移到新格式,但迁移时找不到原本引用的数据源。报错信息里的im7_otuvz是老数据源的 UID,而这个数据源在升级后被重建或删除了,于是查询就无法完成迁移。

碰到这个问题,最直接的解决方法是重新指定数据源:进入面板编辑模式,把每个查询面板的数据源重新选一遍。如果面板数量多,可以在面板 JSON 里全局替换uid字段,把旧 UID 全部改成当前实际使用的数据源 UID,再重新导入。这算是一个经验教训:大规模升级 Grafana 前,最好先把所有面板 JSON 备份,升级后在测试环境先验证一遍。

5. 告警别再只看面板:Prometheus 规则与 Alertmanager 接入

5.1 告警规则配置详解:从一条规则看透核心字段

Grafana 面板解决的是"看得见"问题,但监控真正有价值的是"看得早"。这里的核心是告警规则。

Prometheus 的规则文件放在prometheus/rules/目录下,格式是 YAML。一个典型的实例存活告警如下:

groups: - name: host_alerts rules: - alert: InstanceDown expr: up == 0 for: 1m labels: severity: critical annotations: summary: "实例 {{ $labels.instance }} 已下线" description: "{{ $labels.job }} 的实例 {{ $labels.instance }} 已不可达超过1分钟"

四个核心字段分别负责不同的事:

  • expr:告警触发的条件表达式,up == 0表示 Prometheus 抓取不到目标。
  • for:该条件需要持续多久才触发告警,这里设置 1 分钟。它的价值是过滤抖动机短期波动,避免网络抖动导致告警轰炸。
  • labels:给告警附加的标签,常用于标记严重级别、所属团队,后续 Alertmanager 路由也依赖这些标签。
  • annotations:告警的具体描述,模板里可以使用{{ $labels.xxx }}动态带入实例名、job 名,让告警消息可读性大幅提高。

for字段是我特别想强调的。新手容易忽略它,结果系统刚重启时到处都是"InstanceDown"的误报;设置合理的for时间后,这类问题明显少很多。它不会让告警变慢,只是让告警更可靠。

磁盘空间告警也是常用的例子,注意过滤掉 tmpfs 等临时文件系统:

- alert: DiskSpaceWarning expr: (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} * 100) < 10 for: 10m labels: severity: warning annotations: summary: "磁盘剩余空间不足10%" description: "实例 {{ $labels.instance }} 挂载点 {{ $labels.mountpoint }} 剩余空间已不足10%"

写好之后,在主配置prometheus.yml的rule_files里引入规则文件,然后执行docker compose restart prometheus。修改任何 Prometheus 配置后都建议用promtool先做一次静态检查:

docker exec prometheus promtool check config /etc/prometheus/prometheus.yml

这个习惯能帮我拦截掉一大半语法错误,尤其是 YAML 缩进问题。

5.2 Alertmanager 接入:路由、分组与接收

Prometheus 负责生成告警,但真正把告警发出去给相关人,是 Alertmanager 的工作。它接收 Prometheus 推送来的告警,然后根据路由规则决定发到哪个接收者。

一份基础alertmanager.yml:

global: resolve_timeout: 5m route: receiver: 'ops-notify' group_by: ['alertname', 'instance'] group_wait: 30s group_interval: 5m repeat_interval: 4h receivers: - name: 'ops-notify' email_configs: - to: 'ops@example.com' from: 'monitor@example.com' smarthost: 'smtp.example.com:465' auth_username: 'monitor@example.com' auth_password: 'xxxxxxxx'

这里的核心机制是路由和分组。group_by按告警标签分组,同一组内的多条告警会合并通知,避免"一个实例挂了,所有相关告警同时刷屏"。repeat_interval: 4h控制同一告警的重发频率,防止半夜持续骚扰。group_wait是分组后等待的时间,保证同一组的多条告警能聚成一条消息。

配置好后,需要在 Prometheus 主配置文件里指定 Alertmanager 地址:

alerting: alertmanagers: - static_configs: - targets: - 'alertmanager:9093'

之后可以在 Alertmanager 的 9093 端口 Web UI 里直接看到收到的告警、当前是否分组、发往哪个接收者。

5.3 Grafana 侧怎么接入 Alertmanager 查看告警

热词里有个"grafana 接入 alertmanager 告警",很多人的理解有偏差。Grafana 自己的统一告警系统和 Prometheus 的 Alertmanager 是两个独立体系,它们的接入方式主要有两种理解维度。

第一种是 Grafana 把 Alertmanager 作为数据源添加,从而在 Grafana 里统一查看来自 Prometheus 的告警和静默状态。添加方式是在 Grafana 的Connections -> Data sources -> Add data source里选 Alertmanager,填入它的地址。配好后,可以在 Grafana 的 Alerting 页面查看告警列表、创建静默。

第二种是只使用 Grafana 自己的告警规则功能,它可以直接查询 Prometheus 数据源生成告警,并通过 Contact Points 发通知,完全绕过 Alertmanager。团队如果已经习惯了 Grafana 的操作界面,直接用它内置告警也挺顺手。两种方案都可行,我个人在大多数场景偏好保留 Prometheus + Alertmanager 这套链路,因为规则用文件管理更清晰,也方便用 Git 做版本管理;Grafana 内置告警则适合更偏可视化操作的团队。

5.4 告警状态流转:从 pending 到 firing

Prometheus 里告警有三种状态:inactive(未触发)、pending(条件满足但还在等待for时间)、firing(确认触发并推送给 Alertmanager)。

在 Prometheus 的Alerts页面可以看到这些状态,这是排障时的重要参考。测试告警最简单的方式是直接把某个 node-exporter 容器停掉:

docker stop node-exporter

等一两分钟,刷新 Prometheus Alerts 页,应该能看到InstanceDown先进入 pending,再变成 firing。此时 Alertmanager 的 UI 里也应该出现一条通知记录。测试完把容器启动起来,验证恢复逻辑是否正常——告警恢复后,Prometheus 会向 Alertmanager 发送一个 resolve 通知,消息会以 resolved 的状态出现。

6. 部署和使用中踩过的坑:完整的排查链路与操作经验

6.1 告警不触发:从规则到路由的逐层排查思路

"配置了告警但一直不响"应该排在监控运维问题榜第一位。我的排查路径基本固定,每次都能快速收敛到问题所在。

第一步看Prometheus Alerts 页面。如果一条规则都没显示,说明规则文件没有被加载,检查主配置里的rule_files路径是否正确,用promtool check config验证。如果规则显示为灰色且状态是 inactive,说明条件本身不满足,点击规则展开详情,可以看到当前计算结果和标签。

第二步看Targets 页面。拿up == 0这条规则举例,如果 Targets 里显示的状态是 UP,表达式结果自然是 0,告警不会触发。这种情况要么真的是目标在线没有问题,要么是配置的抓取地址错了——比如填成了localhost:9100,但 Prometheus 在容器里访问不到宿主机的 9100。地址错误时 Targets 页会显示 DOWN,原因一清二楚。

第三步看Alertmanager UI。Prometheus 已经 firing,但 Alertmanager 没收到,需要检查alerting.alertmanagers配置中的地址,以及docker compose logs alertmanager里的日志。Alertmanager 收到了但没通知出去,要检查路由是否匹配:rule 里labels打的标签能否匹配上 route 里的match或 receiver,以及 SMTP 配置是否有误。最基础的配置里,所有告警都走默认 route,这是最简单的兜底。

6.2 面板显示无数据:最常见的三个原因

Grafana 面板一片空白,这是新手上路最打击信心的事。按出现频率排序,原因通常是这三个。

一是数据源 URL 填错。最典型的就是写了localhost,前面说过,改成容器网络内的prometheus或者宿主机可达的 IP 就行。

二是时间范围问题。刚建好的面板默认显示最近 15 分钟,如果你的 Prometheus 里确实没有这个时间段的指标,图表自然为空。把右上角时间调整到"Last 6 hours"或者"Last 24 hours",常常就能看到数据了。

三是查询表达式错误或标签筛选过严。比如 Node Exporter 面板里查询条件写了instance="192.168.1.10:9100",但实际指标文本里 instance 可能是node-exporter:9100,筛选结果就为空。不熟悉的话可以先去 Prometheus 的 Graph 页面用浏览器自动补全功能输入指标名,确认有哪些标签和值存在,再回 Grafana 里调整筛选条件。

6.3 存储、性能和保留周期的现实问题

Prometheus 默认只在本地磁盘保留 15 天数据,这个参数由启动命令里的--storage.tsdb.retention.time控制。如果你需要保留更长时间,改大它,但要注意磁盘空间,因为 Prometheus 的存储算是"写多读少"的重负载类型,尤其在高采集频率下,一天的写入量可能有几 GB。

查看当前数据目录占用,最直接的方式:

du -sh prometheus/data/

如果数据持续增长导致磁盘吃紧,除了缩短保留时间外,还可以考虑配置远程存储,比如 Thanos 的 sidecar 模式把历史数据上传到对象存储,但我自己的建议是:在单实例阶段,30 天保留期足够绝大多数场景,超过这个量级再去考虑扩展,不要一开始就背上高成本架构。

还有一个容易忽略的点是容器的内存和打开文件数限制。Prometheus 在做大量查询时内存占用会明显上升,节点资源紧张时甚至会被 OOM Killer 干掉,导致监控自己先挂了。我通常会设置容器资源限制,并给 Prometheus 单独预留资源:

deploy: resources: limits: memory: 2G

这不奢求一次配到位,但你至少要知道 Prometheus 在什么情况下资源占用会飙升,心里才有个底。

6.4 我现在的固定习惯:让这套监控可维护、可治理

用过一段时间后,我沉淀了几个固定的配置习惯,全部是为了降低日后的维护成本。

第一,所有静态 target 都用file_sd_configs替代直接写在主配置里。主配置保持精简,target 列表放在独立的 YAML 文件里,这样 Prometheus 配置改 target 时不需要重启,它会自动监听文件变更并加载。对于经常上下线的测试环境或新服务,这个机制简直是救命的。

scrape_configs: - job_name: 'node-exporter' file_sd_configs: - files: - /etc/prometheus/targets/node-exporter.yml refresh_interval: 30s

第二,每个 exporter 都打上清晰的标签,统一命名规范。标签是 Prometheus 数据模型的核心,规范混乱会直接导致告警路由和面板变量的失效。我常用env、service、team这类自定义标签来区分环境归属,查询时按标签过滤比按 instance 过滤可靠得多。

第三,所有面板和规则文件都放进目录做版本管理。面板 JSON 导出后放进仓库,规则文件本身就是 YAML,Git 管起来之后,谁能改了什么、回滚到哪一版,都清清楚楚。监控配置的管理标准和代码一样严格,长期协作时才不会变成没人敢动的"黑盒"。

第四,Grafana 里按团队或项目分文件夹,数据源和面板做好命名分区。多人协作时避免互相覆盖配置,权限也能分开控制。虽然一个人维护监控系统时不需要很严格,但团队变大的第一天就会感谢这个习惯。

这套组合我已经在多个环境里跑了一两年,从最初几台服务器的小集群,到后来包含几十个节点、几十个 exporter 的中型环境,它的稳定性和扩展性经受住了考验。配置过程中踩过的每一个坑,最后都成了排查手册里最实用的一页。监控搭建的门槛并不高,真正有价值的是你对自己系统数据流的理解——知道指标从哪来、去了哪、如何变成通知,这套体系才算真正跑通了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 1:18:10

TensorFlow工程化本质:从安装到生产部署的四大核心断点

1. 这不是“又一个深度学习框架”——TensorFlow的本质是工程化AI生产流水线你打开终端敲下pip install tensorflow的那一刻&#xff0c;真正安装的远不止是一组Python包。它是一整套为大规模机器学习模型从实验室走向真实业务系统而设计的工业级基础设施。很多人把它和PyTorch…

作者头像 李华
网站建设 2026/10/1 1:18:01

RK3588双路视觉线程池优化实战:YOLOv5s+FP16高实时部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 1:17:33

Windows UAC原理与4种安全提权方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 1:16:02

Zephyr与FreeRTOS线程优先级设计差异深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华