
搞运维的同学对 Prometheus 这个名字应该不陌生尤其是这几年云原生和容器化铺开之后几乎每个稍微像样一点的技术团队都会把它和 Grafana 放在一起提。我最初接手监控系统时踩了不少坑从“能在页面上看到一个绿色状态”到“指标真正能说明问题、告警真正能送到人”中间隔着一大堆细节。这篇东西不是官方文档的复读而是我把自己从零搭普罗米修斯平台、接服务器资源监控、配告警、甚至接 OpenTelemetry Collector 数据的过程完整捋一遍把关键选择背后的道理讲清楚。先回答一个很多人刚接触时都会问的问题Prometheus 是开源的吗是的它不仅开源而且是云原生计算基金会CNCF里和 Kubernetes 并列的明星项目。它解决的问题非常具体采集各种机器、服务、中间件的指标数据存成带时间戳的序列支持灵活查询并且在指标异常时触发告警。配合 Grafana 做可视化之后监控体系才算真正可用。如果你正在做服务器资源监控、容器集群监控、微服务指标监控或者只是想把网络交换机、防火墙这类设备纳入统一监控这篇内容基本够用。1. 普罗米修斯到底是个什么平台1.1 一说到监控就想到它的原因普罗米修斯最核心的设计是“拉取模型”。大多数传统监控系统比如 Zabbix、Nagios都是 agent 或者服务器主动把数据推给中心端而 Prometheus 反着来它定期去各个被监控目标暴露的 HTTP 接口拉数据。这套设计的优势非常明显目标只需要暴露一个/metrics接口不需要关心监控端是否在监听监控端也能通过up这个内置指标快速判断目标是否活着。配合多维标签label一条指标可以带instance、job、cpu等维度查询时随意过滤聚合比传统树形结构的监控数据灵活太多。再看它的存储模型。Prometheus 会把采集到的数据写成高压缩比的时序块TSDB block适合做短期高密度存储。默认本地存储会保留 15 天可配置数据量大了之后还可以对接远端存储比如 Thanos 或 VictoriaMetrics。很多团队选择它是因为生态过于丰富官方提供了 node_exporter、mysqld_exporter、redis_exporter、snmp_exporter 等一堆现成采集器基本覆盖了日常服务器资源、中间件和网络设备。1.2 Prometheus 生态里到底有哪些组件一开始接触 Prometheus很容易被一堆名词绕晕。我常把它拆成四块Prometheus Server核心服务负责拉取、存储、查询和告警规则计算。Exporter被监控对象上的“翻译官”把各种非 Prometheus 格式的数据转成指标接口。比如 node_exporter 采集 CPU、内存、磁盘SNMP exporter 采集交换机。Alertmanager独立组件负责处理告警的收敛、去重和发送支持邮件、Webhook、企业微信、钉钉等。Grafana可视化平台不监控数据本身但可以连接 Prometheus 查询数据并展示漂亮的大盘。这套组合里Prometheus 本身是开源软件许可证是 Apache License 2.0Grafana 也有开源版。商用组件更多是把可观测性平台化但底层核心仍然是这些开源工具。如果只是搭建一套内部监控环境完全可以用纯开源方案搞定。1.3 什么场景适合什么场景要慎重Prometheus 最强的地方是应用和基础设施指标尤其是 Kubernetes 环境它可以自动发现 Pod、Service、Node 等资源。微服务架构下服务通过 client library 暴露指标Prometheus 按服务名字自动发现并拉取这套机制是传统监控很难做的。但它不是万能的。日志采集不是它的活分布式链路追踪也需要 Tempo、Jaeger 之类的专门工具。如果企业要求监控数据长期归档一年以上把海量时序数据全部压在 Prometheus 本地并不明智。我的经验是Prometheus 负责近期动态监控和告警历史数据通过remote write写到对象存储或者专用时序库。对自己的业务场景先做取舍后面选型时才不会被“开源免费”冲昏头脑。2. 部署 Prometheus 前的设计思路2.1 环境规划和目标确认部署前最应该做的事不是急着敲命令而是想清楚监控对象是谁、需要哪些指标、数据保留多久、告警发给谁。以最常见的“监控服务器资源”为例通常目标包括节点在线状态CPU 使用率、Load Average内存使用率、可用量磁盘空间、inode 使用率网络流量和错误包如果还要监控交换机就要提前确认交换机支持的协议。多数网络设备支持 SNMP 协议那就需要走 snmp_exporter 路线而不是在设备上装 node_exporter。这个决定会影响后面的采集配置所以必须先规划。我建议小团队先采用单机部署 Docker Compose把 Prometheus、Grafana、Alertmanager、exporter 用容器编排跑起来。节点规模几百台以内、数据量不大时完全够用。这套方案最容易上手后面量大了再迁移到 Kubernetes 或 Thanos 也不难。2.2 镜像版本选型与下载Prometheus 的镜像通常放在 Docker Hub 和 quay.io 上。以 Docker Hub 为例官方镜像名是prom/prometheus、prom/node-exporter、prom/alertmanagerGrafana 是grafana/grafana。选镜像时注意 tag 不要用latest否则每次拉取结果不可控版本升级也可能带来配置兼容问题。我一般会固定到具体的 minor 版本比如prom/prometheus:v2.47.0、grafana/grafana:10.2.0。国内网络环境下直接从 Docker Hub 拉取镜像有时很慢或者超时解决办法是给 Docker 配置镜像加速器。修改/etc/docker/daemon.json加入registry-mirrors: [https://docker.mirrors.ustc.edu.cn]然后重启 Docker。注意镜像加速只是在拉取时更快不影响最终镜像内容和运行行为。提示下载完镜像后最好执行docker images和docker inspect简单确认镜像大小、创建时间是否正常。生产环境建议按需执行docker pull不要一次性拉一堆不用的镜像。2.3 配置文件的基础结构Prometheus 默认配置文件是prometheus.yml。第一次看到它的时候重点理解四个关键段global全局配置比如scrape_interval抓取间隔和evaluation_interval规则评估间隔。rule_files加载告警规则文件的位置。scrape_configs定义要拉取的目标列表每个 job 下可以指定静态目标或者服务发现。alertingAlertmanager 的地址以及告警规则如何匹配。其中最重要的是scrape_configs它决定了数据源。比如监控 node_exporter配置大概长这样scrape_configs: - job_name: node static_configs: - targets: [node-exporter:9100] labels: env: prod这里targets的地址是容器内可达地址后面排错时经常遇到网络地址写错的问题。配置里还可以加relabel_configs在抓取前修改标签这是服务发现场景下必备技能。2.4 监控目标发现的取舍目标少时静态配置最简单。但服务器数量很多或者容器调度频繁变化时手工维护 targets 就是灾难。Prometheus 支持多种服务发现机制文件发现监控端定时读取 JSON/YAML 文件文件里由外部系统动态更新。Consul、ZooKeeper适合传统注册中心。Kubernetes自动发现 Pod、Service、Endpoints。我最初用静态配置管理几百台 Node 节点靠脚本生成 prometheus.yml也能跑。但所有机器都部署在 Kubernetes 后节点重启 IP 变化静态配置就非常痛苦于是逐步切换到 K8s 服务发现。初学者建议先从静态配置理解流程再扩展到服务发现不要一上来就把所有机制都堆上。3. 一步步搭起 Prometheus Grafana 监控环境3.1 用 Docker Compose 快速拉起基础环境假设你已经在一台 Linux 服务器上安装好了 Docker 和 Docker Compose 插件。创建目录prometheus-setup里面放docker-compose.yml。我最常用的最小版本是version: 3.8 services: prometheus: image: prom/prometheus:v2.47.0 container_name: prometheus restart: always ports: - 9090:9090 volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prom_data:/prometheus grafana: image: grafana/grafana:10.2.0 container_name: grafana restart: always ports: - 3000:3000 environment: - GF_SECURITY_ADMIN_PASSWORDadmin123 volumes: - grafana_data:/var/lib/grafana node-exporter: image: prom/node-exporter:v1.6.1 container_name: node-exporter restart: always ports: - 9100:9100 command: - --path.rootfs/host pid: host volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/rootfs:ro volumes: prom_data: grafana_data:这个编排把 Prometheus、Grafana、node-exporter 一次拉起来。node-exporter 使用 host PID 模式挂载宿主机的/proc、/sys才能采集到宿主机真实的 CPU 内存磁盘数据。如果你只想让 node-exporter 在容器里跑着玩不带这些挂载那它采集的是容器自身的数据不是宿主机数据。启动命令是docker compose up -d。启动后访问http://服务器IP:9090能看到 Prometheus 自带的 UI访问http://服务器IP:3000能打开 Grafana。首次登录 Grafana 默认账号是admin/ admin这里我在环境变量里改成了admin123生产环境千万别用这种弱口令。3.2 监控服务器资源的核心配置接着要保证 Prometheus 能抓到 node-exporter 的数据。修改prometheus.yml加上如下 jobscrape_configs: - job_name: linux-node scrape_interval: 30s static_configs: - targets: [node-exporter:9100] labels: host_group: linuxscrape_interval我一般不会小于 15 秒除非业务对指标敏感度要求极高否则会带来不必要的存储和网络开销。配置改完执行docker compose restart prometheus或者执行curl -X POST http://localhost:9090/-/reload热加载。这里有个提示Prometheus 配置文件支持热加载但规则文件也建议用同样的方式刷新。然后去 Prometheus UI 的 Status - Targets 页面能看到linux-node这个 job 的状态。如果显示UP说明采集成功。这时可以在 Graph 页面执行一个最简单的查询比如输入node_cpu_seconds_totalCPU 累计时间点 Execute就能看到一组时序。看到数据的那一瞬间你的监控链路已经通了。3.3 监控交换机和网络设备的方法服务器能用 node-exporter但交换机、路由器、防火墙很难在上面装 agent。普罗米修斯监控网络设备的通用做法是使用 snmp_exporter。snmp_exporter 本身不是一个采集数据的程序而是把 SNMP 数据转换成 Prometheus 指标的翻译层。它加载一个模块文件snmp.yml里面定义了如何把 OID 映射成指标。实际操作分三步部署 snmp_exporter 容器挂载生成好的 snmp.yml。在 Prometheus 中为每个交换机添加一个target并通过params指定 module比如module: if_mib。在 snmp.yml 中按需配置 OID 映射。如果只是快速看一下 CPU、内存、接口流量可以直接用官方提供的if_mib模块。但不同厂商的 OID 差异很大最好先用 snmpwalk 确认设备支持的 MIB。我在配置中通常会让 snmp_exporter 的端口保持 9116然后用带标签的静态配置区分每个设备- job_name: snmp-switch scrape_interval: 60s static_configs: - targets: - 192.168.1.10 - 192.168.1.11 metrics_path: /snmp params: module: [if_mib] relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: snmp-exporter:9116这段配置的关键是让 Prometheus “把请求发到 snmp-exporter但实际目标改成交换机 IP”。不熟悉 relabel 的人经常在这里卡住原理也可以很简单Prometheus 出于安全因素默认抓取地址就是 target 地址所以要改成 snmp-exporter 的地址同时把原交换机的地址作为__param_target传给 snmp-exporter。3.4 Grafana 数据源配置和导入大盘Grafana 起来之后第一步是配置数据源。选择Prometheus类型URL 填http://prometheus:9090保存并测试显示“Successfully queried the Prometheus API”就说明连接成功。接下来不需要从零画图可以直接导入现成 Dashboard。Grafana 官网有很多社区面板服务器资源监控我常用的是 “Node Exporter Full”Dashboard ID 1860网络设备常用 “SNMP device overview”Dashboard ID 10708。在 Grafana 左侧选择Dashboards → Import输入 ID 后会提示选择数据源选刚才配好的 Prometheus 即可。导入后你会看到 CPU、内存、磁盘、网络、负载等面板。需要提醒的是不同 node_exporter 版本的指标名可能略有差异如果某些面板显示No data查看面板里的 PromQL 表达式把不存在的指标名替换成当前版本实际存在的指标。比如早期版本有node_cpu新版本变成了node_cpu_seconds_total直接在查询编辑器里调整函数即可。注意Grafana Dashboard 只要有一两个关键面板就够不要追求一百个图表。监控平台的价值是被需要时能被信任而不是把页面堆满。3.5 Prometheus 图形界面使用窍门Prometheus 自带 UI 虽然不华丽但非常适合排查数据。在 Graph 页面输入up可以看到所有被抓目标的状态值为 1 表示正常0 表示异常。输入node_load1可以看到 1 分钟负载。用{}支撑标签过滤比如up{joblinux-node}或者node_memory_Active_bytes{instancenode-exporter:9100}。Grafana 的 Explore 功能相当于一个加强版查询界面左边选择 Prometheus 数据源输入 PromQL 后可以直接展示折线图。日常排查时我习惯先在 Prometheus UI 确认“数据存在”再去 Grafana 调整面板这样能避免把数据源问题和面板问题混在一起。PromQL 建议先记几个常用函数rate()计算每秒增长率increase()计算区间增量sum()、avg()做聚合topk()取出最大值predict_linear()可以做简单的趋势预测。这些学明白后自己改面板也不慌。4. 告警规则配置详解4.1 从零写一个告警规则文件告警规则的作用是让 Prometheus 周期计算表达式如果结果为真就产生一条告警。配置文件名随意比如rules.yml但必须被rule_files加载。我在prometheus.yml里加一句rule_files: - /etc/prometheus/rules.yml一个简单的 CPU 使用率告警规则如下groups: - name: server-alerts rules: - alert: HighCpuUsage expr: 100 - (avg(rate(node_cpu_seconds_total{modeidle}[5m])) by (instance) * 100) 85 for: 5m labels: severity: warning annotations: summary: Instance {{ $labels.instance }} CPU usage is above 85% description: The instance has been above 85% for more than 5 minutes.这里expr表达的是 CPU 使用率for: 5m表示需要持续触发 5 分钟才产生告警防止瞬时峰值造成误报。按这个思路内存告警可以写为(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 90磁盘告警写为(1 - (node_filesystem_avail_bytes{mountpoint/} / node_filesystem_size_bytes{mountpoint/})) * 100 80。写完规则后建议用promtool校验docker exec prometheus promtool check rules /etc/prometheus/rules.yml只有语法通过后再在 Prometheus UI 的 Alerts 页面查看规则状态。没有数据时规则会显示no data这通常表示表达式有问题而不是规则没生效。我在踩坑时发现最常见的问题是磁盘告警忽略了mountpoint标签把虚拟文件系统也算了进去导致告警阈值很难看。4.2 Alertmanager 部署和告警接收Prometheus 本身不负责发送告警它只计算出一个“需要告知别人”的信号后面交给 Alertmanager 处理。Alertmanager 的配置涉及两个层面路由树和接收器。提前规划好路由树很重要。先写一个最小alertmanager.ymlroute: group_by: [alertname, instance] group_wait: 10s group_interval: 2m repeat_interval: 4h receiver: default-webhook receivers: - name: default-webhook webhook_configs: - url: http://内部服务/webhook/prometheus send_resolved: true然后docker-compose.yml增加 Alertmanager 服务并在 Prometheus 的配置里声明 Alertmanager 地址alerting: alertmanagers: - static_configs: - targets: [alertmanager:9093]部署完成后触发一次告警可以在 Alertmanager UI9093端口看到告警分组。分组机制的意义是合并相似告警避免一瞬间把几十条消息发给接收人。repeat_interval控制在告警未恢复时多久重复发送一次我一般设置成 4 小时防止“告警疲劳”。4.3 告警自测和避免告警风暴很多团队在告警上线前没有自测结果一遇到故障告警消息像洪水一样涌过来最后大家只能静默拉群。规避问题的几个关键点所有规则都写for至少 3 到 5 分钟把瞬时抖动过滤掉。分组时按alertname分组让同类告警合并成一条。使用inhibit_rules配置抑制规则例如已有“主机宕机”这个严重告警就不要再重复发该主机上的所有子告警。在 Alertmanager 里设置静默Silence维护期间主动屏蔽。我可以分享一个常用抑制配置片段如果你已经在告警规则里设置了severity: critical和severity: warninginhibit_rules: - source_matchers: - severitycritical target_matchers: - severitywarning equal: [instance]这样当一台机器达到 critical 告警时针对同一个 instance 的 warning 告警就不会再发整体消息量会下降很多。要让告警真正有用必须控制在“关键信息被看到”的频率而不是数字上什么都报。5. Prometheus 如何从 OpenTelemetry Collector 收取数据5.1 理解 OpenTelemetry 和 Prometheus 的差异OpenTelemetry简称 OTel是目前可观测性领域的事实标准它统一了指标、日志和链路追踪的数据建模。很多人以为 Prometheus 可以直接吃掉 OTel 的数据实际上并没有这么简单。Prometheus 是拉取模式OTel Collector 的默认工作是接收来自应用的数据再推送到后端。两套体系的交互需要“翻译”或者“暴露”。把 OTel Collector 接到 Prometheus 通常有两条常见路径方案 A在 OTel Collector 里启用prometheusexporter它会把收集到的指标暴露成一个/metricsHTTP 接口然后让 Prometheus 从这个接口拉取。方案 BOTel Collector 通过prometheusremotewriteexporter把指标推送到支持remote write的后端比如 Prometheus 或 Thanos 接收端。热搜词里点名的“从 otel-collector 收取数据”其实是方案 A也就是让 OTel Collector 暂时充当一个 exporter。理解这个关系后排查问题时就不容易方向搞反。5.2 实际配置一个 OTel Collector 暴露指标假设应用已经通过 OTLP 协议把指标发送到localhost:4317。你可以在 OTel Collector 的配置文件otelcol-config.yaml中设置如下内容receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: prometheus: endpoint: 0.0.0.0:8889 namespace: otel_app service: pipelines: metrics: receivers: [otlp] exporters: [prometheus]启动 Collector 后它会在8889端口暴露 Prometheus 格式的指标。然后回到 Prometheus 的prometheus.yml添加一个 job 去抓这个端口- job_name: otel-collector static_configs: - targets: [otel-collector:8889]这一步非常关键Prometheus 并不会因为配置了 OTel Collector 就自动感知必须把 Collector 当成一个普通 exporter 加进scrape_configs。加完后在 Prometheus UI 输入otel_app_前缀的指标名就能看到采集结果。5.3 指标命名、类型和标签的坑从 OTel 到 Prometheus 不是简单的字段直转。OTel 的指标名是带点的比如http.server.durationPrometheus 推荐使用下划线所以导出时会变成http_server_duration。这个转换通常是自动的但你最好在命名规范上提前统一不要等写到一半才发现前端面板和后端指标对不上。另外OTel 的指标类型是Counter、Gauge、Histogram等Prometheus 也有类似类型但 Histogram 的 bucket 需要明确配置。默认导出时如果 bucket 语义不匹配可能会出现速率计算不准确。我的建议是如果已经在这套链路里用 Prometheus就在应用侧尽量直接暴露 Prometheus client 格式或者让 OTel Collector 只承担统一转发不反复转换。混合环境下启用include_metadata和过滤规则前一定要先看一段时间数据确认没有重复指标名或者指标冲突。6. 常见问题与排查技巧实录6.1 数据没采上来先查这些采集链路出问题时我通常按顺序排查Prometheus UI - Status - Targets看目标状态是否 UP。如果是 DOWN从 Prometheus 容器里curl一下目标地址和端口排除网络和防火墙。如果状态是 UP 但查询不到数据检查指标名是否正确job 或 instance 标签是否匹配。scrape_timeout是否过短尤其 SNMP 设备响应慢时会经常出现context deadline exceeded。日志里有没有权限错误比如Failed to scrape node-exporter多半是容器挂载路径或权限问题。用工具验证时我常用docker exec prometheus wget -qO- http://node-exporter:9100/metrics | head确定目标能返回数据。注意不是所有容器都有 wget有时需要换成curl或者直接在宿主机测试映射端口。6.2 Grafana 没数据或全是 NoDataPrometheus 有数据但 Grafana 面板显示 NoData最常见原因有四个面板时间范围太长而数据只保留 15 天会看到分段空白。面板里的 PromQL 用了不存在的标签值比如实例名已经变了。数据源 URL 写成了localhost:9090这个地址在 Grafana 容器里指向 Grafana 自身应该用服务名prometheus:9090。Dashboard 变量没有正确关联数据源。排查时直接用 Grafana Explore 跑一条简单查询比如up。如果 Explore 有数据说明数据源和 Prometheus 都没问题问题集中在 Dashboard 变量或者查询条件上顺着面板的表达式逐项对比即可。6.3 Docker 镜像下载慢或反复失败镜像拉取失败是老生长谈。除了配置镜像加速器之外还要注意 Compose 文件中 image tag 是否存在。一个很容易踩的坑是国内企业内网有时无法访问外网 Docker Hub这时需要有内部镜像仓库或者提前导出镜像文件。团队规模稍大的建议搭一套 Harbor 私有镜像仓库把常用镜像预先同步进去部署时直接从内部拉取网络更稳也便于做漏洞扫描和版本固化。6.4 告警总不发或者重复轰炸告警不发的排查思路是先在 Alerts 页面确认规则是否可以计算为pending或firing。如果规则状态一直是inactive说明表达式当前不满足阈值或标签写错。如果规则是firing但 Alertmanager 不显示检查 Prometheus 的alerting配置以及 Prometheus 容器里是否能看到 Alertmanager 连接日志。如果 Alertmanager 收到了但发送失败去看 Alertmanager 日志通常在 Webhook 地址、TLS 证书或接收服务挂了这几个点。重复轰炸则主要看路由repeat_interval和分组字段。把分组宽泛一点比如只按alertname分组而不是按instance分组能有效减少同一类告警的重复程度。注意 Group 和 Repeat 的效果不一样一个解决的是“同一批次多条”的合并另一个解决的是“间隔多久再发一次”。6.5 Prometheus 资源占用不正常的应对Prometheus 是个内存大户尤其目标数量多、指标基数大、查询范围宽的时候。一个容易忽略的因素是指标基数你给指标加的标签维度越多组合出来的时间序列就越多。比如http_request_total如果带了user_id标签那每个用户都会产生一条序列几万用户就是几万条。这种情况下调大内存解决不了根本问题应该移除高基数标签或者减小采集范围。本地存储膨胀后可以调整--storage.tsdb.retention.time和--storage.tsdb.retention.size比如限定保留 15 天、最大 50GB。如果还是不够就要考虑对接远端存储比如用 Thanos 统一多个 Prometheus或者用 VictoriaMetrics 作为集中存储。我最后提醒一句不要一开始就把所有采集间隔设成 5 秒默认 15 秒或 30 秒已经足够绝大多数业务使用对存储和内存压力小很多。7. 普罗米修斯平台后续还能怎么扩展很多团队把 Prometheus 搭好、配上 Grafana 后就觉得监控工作“结束了”。后面还有不少可以扩展的方向比如采集 Kubernetes 容器指标时可以加上 kube-state-metrics 获取 Deployment、Pod、Service 的状态想监控 MySQL、Redis 时部署对应的 exporter 并导入官方 Dashboard需要把告警发到钉钉、企业微信或者飞书时Alertmanager 支持配置多种 Webhook 接收方。另一个值得投入的方向是设定 SLO 和错误预算。Prometheus 可以很好地计算 SLI比如过去 30 天服务可用性、请求成功率、延迟分布再通过规则和 Grafana 展示出来。比起每天盯着一堆 CPU、内存面板把“可用性是否达标”作为核心指标监控体系才算和业务真正挂钩。我个人在实际使用中最深的一个体会是监控系统不是越复杂越好而是必须有一个“明确要回答的问题”。你监控这台机器是想知道它是否快挂了还是想分析容量趋势你配告警是想要提醒自己处理还是想要别人也看到这些想清楚后再倒推需要采集哪些指标、保留多久、怎么展示整个普罗米修斯平台的建设会顺畅许多。如果只是机械地跟风部署一堆组件最后大概率会陷入“装了但没人看、告警淹没在群里”的尴尬局面。