Prometheus + Grafana:从零搭建服务器监控与告警体系
如果你手上管着三五台以上的服务器无论是 Linux 虚机还是云主机我猜你迟早会遇到同一个问题系统出故障时你根本不知道是哪台先出的问题CPU 是在凌晨几点被打满的磁盘又是什么时候悄悄写满的。传统做法是挨个 SSH 上去敲uptime、free -m、df -h但机器一多这套流程根本不现实。我在经历了一次半夜被磁盘告警电话叫醒、却花了二十分钟才定位到是哪台机器之后下定决心把监控体系好好搭一遍最终定型的就是 Prometheus Grafana 这套组合。这篇文章会把我从零开始部署的完整过程、配置细节和踩过的坑全部写出来适合刚接触监控体系的运维、后端开发以及所有想给自己服务器加一道安全网的读者。这套部署方案的核心就三件事用 Prometheus 抓取和存储监控数据用 Grafana 把数据变成直观的面板和图表再用 Alertmanager 在指标异常时把告警推到你的手机上。下面我从选型逻辑开始讲再逐步拆解二进制部署、exporter 接入、告警配置和容器化落地全程照着操作就能复现。1. 为什么我推荐 Prometheus Grafana 这套组合1.1 从登录服务器敲命令到统一监控大盘监控体系的本质是把分散在每台机器上的状态信息集中起来解决两个问题一是现在有没有异常二是过去一段时间发生了什么。只靠登录服务器敲命令这两件事都做不到——你不可能在故障发生后还原几小时前的 CPU 曲线也不可能同时盯住十几台机器的磁盘水位。Prometheus 解决的是怎么采集和存储它把每台机器上的指标CPU、内存、磁盘、网络等按固定节奏抓过来存成带时间戳的时序数据并提供 PromQL 查询语言让你能灵活地按时间范围和标签条件筛选数据。Grafana 解决的是怎么看它把 Prometheus 里的查询结果渲染成折线图、柱状图、仪表盘还能多块图表拼成一个大盘一屏看完所有机器的状态。这套组合我用下来的最大感受是排查故障的时候不用再猜了。以前是感觉那台机器有问题现在是看曲线就知道问题从什么时候开始、持续了多久、影响面多大。对于两三台机器的个人项目它可能显得重但只要是面向长期运行的服务这套体系早晚都得建起来。1.2 拉模型 vs 推模型Prometheus 和 Zabbix 的本质差异我早期也考虑过 Zabbix毕竟它历史更久、中文资料也多。但在实际对比之后还是选了 Prometheus。这里面的核心差异在数据采集方式上。Zabbix 是典型的推模型加轮询Agent 主动把数据推给 ServerServer 也可以反过来轮询设备数据组织方式是树形的监控项。Prometheus 是拉模型监控端定期主动去访问被监控端暴露的/metrics接口抓取指标。数据组织方式是指标名加标签组成的多维矩阵。这两种模式在动态环境下差别非常大。拉模型天然适合容器、云主机这种随时可能创建销毁的资源池Prometheus 通过服务发现就能自动找到新出现的目标不需要在监控端手工新增一台机器。推模型则需要 Agent 端主动注册或配置好上报关系新增节点多了一道手工步骤。维度PrometheusZabbix数据模型指标名 标签的多维时序树形组织的监控项采集方式主动拉取 /metrics 接口Agent 推送 Server 轮询服务发现原生支持文件、Consul、K8s 等依赖脚本和手工配置告警能力Alertmanager 统一路由去重自带触发器可视化配合 Grafana 生态强大自带图表定制能力弱1.3 exporter 机制和生态优势Prometheus 的拉模型能成立靠的是 exporter 这套标准接口。官方和社区给几乎所有常用软件都写了 exporterLinux 主机有node_exporterMySQL 有mysqld_exporterRedis 有redis_exporter连 Nginx、MongoDB、Kafka 都有对应的现成方案。每个 exporter 暴露一个 HTTP 端口输出格式统一的监控指标文本。这样 Prometheus 本身只需要学会一种协议就能监控整个世界。Grafana 这边的生态更是省心。官方模板库里几万块现成仪表盘最常见的主机监控模板直接导入就能用不需要你从零开始画图表。我在第一次部署的时候从下载到看到完整的主机监控大盘前后不到半个小时。对于一个需要快速见效的场景来说这套组合的上手速度是传统监控方案很难比的。2. 规划先行服务器、端口、版本和时间同步2.1 监控服务器的最低配置很多人部署监控系统喜欢一步到位上高配但实际没必要。我的建议是Prometheus 和 Grafana 合装在一台 2 核 4G 的机器上作为起步配置完全够用。磁盘则要看数据保留策略和采集规模默认保留 15 天数据的情况下监控几十台主机的常规指标一天新增的数据量大概在几百 MB 到 1GB 之间所以建议至少给监控数据目录分 100GB 空间省得频繁清理。被监控机器这边不需要装什么重量级 agent只需要跑一个 exporter 进程占用资源很小。node_exporter 的常驻内存大概 30MB 左右对业务机器的性能影响可以忽略不计。网络方面有一个原则必须记住Prometheus 是拉模型所以监控机的网络要能访问所有被监控目标的 exporter 端口。如果你有云防火墙记得在安全组里放行这些端口不然会看到 targets 页面上一片红。2.2 端口规划表部署前先把端口规划好后面配置的时候思路会清晰很多。这是我常用的分配方式组件端口默认认证说明Prometheus9090自带 UI 和 API无登录认证Grafana3000默认账户 admin/admin首次登录强制改密node_exporter9100指标接口无认证mysqld_exporter9104指标接口无认证Alertmanager9093管理 UI 和告警 API2.3 时间同步是隐藏的硬门槛说它是硬门槛是因为时间不同步导致的问题极具迷惑性图表上数据断断续续告警触发时机不对数据点对不上。TSDB 存储本身用的是 Unix 时间戳理论上不受时区影响但实际抓取过程中如果目标和监控机之间时间差超过一定阈值Prometheus 会认为数据点异常甚至在查询时出现断层。所以部署之前所有参与监控的机器务必确认时间同步正常。Linux 上检查timedatectl确保 NTP synchronized 状态是 yes否则就配好 chrony 或 ntpdate。这个步骤 5 分钟就能做完但能省掉后面几十个小时的排查痛苦。2.4 版本选择原则我的习惯是不用 latest选发布了一段时间的次新小版本。因为最新版本刚发布时可能带一些回归 bug而太老的版本又缺少新功能。以我写这篇文章时为例稳定的组合搭配是Prometheus 2.53.0Grafana 11.3.0Alertmanager 0.28.0node_exporter 1.8.2Prometheus 2.x 系列的配置格式大体保持稳定YAML 配置在这几个小版本之间兼容性都很好。Grafana 11.x 的界面和 10.x 差别不大data source 配置方式完全一致。选定一组版本后后续所有机器的部署都用同一组版本避免版本漂移带来的配置差异。3. Prometheus 本体部署二进制方式完整实操3.1 下载解压与目录结构二进制部署虽然比 Docker 多几步但能让你把每个配置项的作用都搞清楚我建议第一次部署一定用这种方式走一遍。到 GitHub 的 prometheus 官方仓库下载 tarballcd /opt wget https://github.com/prometheus/prometheus/releases/download/v2.53.0/prometheus-2.53.0.linux-amd64.tar.gz tar xvf prometheus-2.53.0.linux-amd64.tar.gz mv prometheus-2.53.0.linux-amd64 /usr/local/prometheus解压后的目录里有几个关键文件。prometheus是主程序promtool是命令行工具专门用来校验配置和规则文件后面排错全靠它prometheus.yml是主配置文件console_libraries和consoles两个目录是老的模板方案遗留物现在基本用不上可以不用管。先试着用默认配置跑起来看看cd /usr/local/prometheus ./prometheus --config.fileprometheus.yml启动后浏览器访问http://监控机IP:9090看到 Prometheus 自带的查询页面就算第一步成功了。3.2 prometheus.yml 核心配置逐行拆解先把最精简的配置写出来我再解释每一行的作用global: scrape_interval: 15s evaluation_interval: 15s alerting: alertmanagers: - static_configs: - targets: - localhost:9093 rule_files: - /usr/local/prometheus/rules/*.yml scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090]scrape_interval是全局抓取间隔Prometheus 会每隔 15 秒访问一次每个 target 的指标接口。15 秒对主机监控足够对延时敏感的业务可以调到 10 秒甚至 5 秒但要权衡磁盘和 CPU 开销。evaluation_interval是告警规则评估间隔Prometheus 每隔这么久检查一次规则文件里的条件是否满足。alerting段配置 Alertmanager 地址暂时可以先放着等第七节部署完告警组件再启用。rule_files声明告警规则文件的路径支持通配符。scrape_configs是核心每个job_name代表一组监控目标static_configs下面列出目标地址。3.3 用 systemd 把 Prometheus 托管起来生产环境不能靠前台进程跑一定要用 systemd 托管这样开机自启、崩溃自动拉起都省心。先创建专用用户安全考虑不用 root 跑监控服务useradd -M -s /usr/sbin/nologin prometheus mkdir -p /usr/local/prometheus /data/prometheus chown -R prometheus:prometheus /usr/local/prometheus /data/prometheus然后创建/etc/systemd/system/prometheus.service[Unit] DescriptionPrometheus Server Afternetwork.target [Service] Userprometheus Groupprometheus Typesimple ExecStart/usr/local/prometheus/prometheus \ --config.file/usr/local/prometheus/prometheus.yml \ --storage.tsdb.path/data/prometheus \ --storage.tsdb.retention.time15d Restarton-failure RestartSec5s [Install] WantedBymulti-user.target--storage.tsdb.path指定时序数据存放目录务必放到磁盘空间充足的路径。--storage.tsdb.retention.time15d是数据保留时间超过 15 天的数据自动清理。启动并验证systemctl daemon-reload systemctl enable --now prometheus systemctl status prometheus curl http://localhost:9090/-/healthy返回Prometheus is Healthy就说明服务正常。/-/ready接口则能检查数据是否 ready。3.4 用 promtool 校验配置在修改配置之后养成用 promtool 先校验的习惯可以避免很多低级错误/usr/local/prometheus/promtool check config /usr/local/prometheus/prometheus.yml如果配置有语法错误promtool 会精确定位到某个 YAML 行号。确认无误后执行systemctl reload prometheus热加载配置Prometheus 支持在不重启的情况下刷新配置非常方便。4. 把监控目标接进来exporter 部署与抓取配置4.1 用 file_sd_configs 做动态目标管理静态配置适合就一两台机器的情况机器一多直接在prometheus.yml里写 targets 列表会越写越乱。我推荐用的是file_sd_configs文件发现方式把目标列表单独放在一个 YAML 文件里Prometheus 定期读取这个文件改文件不需要重载主配置。在prometheus.yml的scrape_configs里加一个 job- job_name: linux-node file_sd_configs: - files: - /usr/local/prometheus/sd/node.yml refresh_interval: 30s目标文件/usr/local/prometheus/sd/node.yml这样写- targets: - 192.168.1.10:9100 - 192.168.1.11:9100 labels: env: prod这里加的env: prod标签会附加到这些目标抓取的所有指标上后面在 Grafana 里按环境筛选就很方便。每次加新机器只需要往这个文件里追加一条30 秒内 Prometheus 会自动感知。4.2 relabel 与标签管理的最佳实践标签是 Prometheus 多维查询的基石。默认情况下每个指标自带job和instance两个标签instance是IP:端口格式有时候不够友好。可以用 relabel 规则提取成新的标签relabel_configs: - source_labels: [__address__] regex: (.*):9100 target_label: node_ip replacement: ${1}这段的意思是从__address__原始地址里用正则提取出 IP 部分写到新标签node_ip上。配置好以后PromQL 里就能用node_ip来筛选具体机器。这里有一条重要原则不要加高基数的标签。标签的每个取值组合都会生成独立的时序数据比如把用户的 ID、请求的 URL 这种高变化值当成标签时序数量会爆炸式增长内存和磁盘都扛不住。标签只应该用于区分有限几个维度环境、机房、角色、版本这些。4.3 扫描 target 状态的方法配置完成后在 Prometheus 页面的 Status 菜单下的 Targets 页面能看到每个 target 的健康状态。UP 表示最近一次抓取成功DOWN 表示失败。点开某个 target 还能看到抓取耗时、上次抓取时间、详细的错误信息。如果某个 target 是 DOWN最常见的几个原因安全组没放行端口、exporter 没启动、IP 或端口写错。按照这个顺序排查基本都能解决。5. Grafana 部署与数据源接入从安装到第一块面板5.1 安装 GrafanaGrafana 官方提供了 RPM 和 DEB 包安装方式很直接。RHEL/CentOS 系sudo yum install -y https://dl.grafana.com/oss/release/grafana-11.3.0-1.x86_64.rpm systemctl daemon-reload systemctl enable --now grafana-serverDebian/Ubuntu 系sudo apt-get install -y adduser libfontconfig1 musl wget https://dl.grafana.com/oss/release/grafana_11.3.0_amd64.deb sudo dpkg -i grafana_11.3.0_amd64.deb安装完成后访问http://监控机IP:3000默认账号 admin默认密码 admin首次登录会强制要求修改密码。Grafana 的配置文件在/etc/grafana/grafana.ini大部分默认配置够用我通常只改时区设置。5.2 添加 Prometheus 数据源登录后进入 Administration - Data sources - Add data source选 Prometheus。关键配置只有一项HTTP URL 填http://localhost:9090如果 Grafana 和 Prometheus 在同一台机器。其他选项保持默认就好然后点底部的 Save test看到绿色的 Datasource is working 提示就说明数据链路已经通了。这个步骤如果报错优先检查网络连通性和端口用curl http://localhost:9090/-/healthy验证一下 Prometheus 是否正常。5.3 导入现成模板半小时见到完整仪表盘自己从零画面板效率太低直接导入模板社区现成的方案。在 grafana.com/dashboards 里搜索 node exporter最经典的模板 ID 是 1860Node Exporter Full还有 8919、11074 等常见选择。导入方法是Dashboards - New - Import输入模板 ID选好数据源点 Import 即可。导入完成后就能看到一整面包含 CPU、内存、磁盘、网络、文件系统等状态的主机监控大盘。这里有一个容易踩的坑很多模板默认指标名是node_cpu_seconds_total如果你的 exporter 版本较新指标会带一些额外标签图可能显示不出数据。解决办法是把模板里的 PromQL 查询和当前指标的标签对一下或者干脆改用和我上面提到版本匹配的模板。1860 这个模板经历过多轮更新对新版本 node_exporter 的兼容性较好。5.4 手写一个最简单的 CPU 使用率面板模板能解决 80% 的需求但自己会写查询才能应对剩下的 20%。我拿最常用的 CPU 使用率做例子。PromQL 查询如下100 - avg(irate(node_cpu_seconds_total{modeidle}[5m])) by (instance) * 100含义拆解node_cpu_seconds_total是 CPU 累计运行时间计数器modeidle筛出空闲状态irate(...[5m])计算最近 5 分钟的瞬时速率avg(..) by (instance)按实例聚合平均最后用 100 减去空闲率得到使用率。创建一个新的 Dashboard选 Add visualization数据源选 Prometheus把查询粘进去一个实时 CPU 使用率面板就好了。掌握几个基础函数rate、irate、sum、avg、by的用法之后大部分指标查询都能自己写出来。6. node_exporter 与 mysqld_exporter实战接入两个监控目标6.1 node_exporter 部署流程主机监控靠 node_exporter。在每台被监控机器上执行cd /opt wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz tar xvf node_exporter-1.8.2.linux-amd64.tar.gz mv node_exporter-1.8.2.linux-amd64 /usr/local/node_exporter创建用户和 systemd serviceuseradd -M -s /usr/sbin/nologin node_exporter[Unit] DescriptionNode Exporter Afternetwork.target [Service] Usernode_exporter Groupnode_exporter Typesimple ExecStart/usr/local/node_exporter/node_exporter --web.listen-address:9100 Restarton-failure RestartSec5s [Install] WantedBymulti-user.target启动后访问http://被监控机IP:9100/metrics能看到一长串文本形式的指标。这就是 Prometheus 拉取的数据源。node_exporter 默认启用了所有 collector包括 CPU、内存、磁盘、文件系统、网络等。某些 collector 用不上的可以在启动参数里加--collector.disable-defaults再手动启用需要的不过初期直接用默认配置就行。最后把目标加到/usr/local/prometheus/sd/node.ymlPrometheus 会在 30 秒内自动发现新主机。6.2 mysqld_exporter 部署监控 MySQL 的方法类似但多了一步授权。先在 MySQL 里创建专用监控账号CREATE USER exporter% IDENTIFIED BY exporter_pass; GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO exporter%;mysqld_exporter 通过 DSN 连接 MySQL在启动时用环境变量传入wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.15.1/mysqld_exporter-0.15.1.linux-amd64.tar.gz tar xvf mysqld_exporter-0.15.1.linux-amd64.tar.gz mv mysqld_exporter-0.15.1.linux-amd64 /usr/local/mysqld_exporter创建 systemd service注意 Environment 里的 DSN 格式[Unit] DescriptionMySQL Exporter Afternetwork.target [Service] Usermysqld_exporter Groupmysqld_exporter Typesimple EnvironmentDATA_SOURCE_NAMEexporter:exporter_passtcp(localhost:3306)/ ExecStart/usr/local/mysqld_exporter/mysqld_exporter --web.listen-address:9104 Restarton-failure RestartSec5s [Install] WantedBymulti-user.target然后把IP:9104加入 Prometheus 的抓取目标文件里配好 job_name 为mysql。之后在 Grafana 里导入 MySQL 监控模板比如 ID 7362就能看到连接数、慢查询、QPS 等指标了。6.3 验证抓取链路是否完整接入完成之后一定要回 Prometheus 的 Targets 页面确认所有目标都是 UP 状态Scrape Duration正常是一个好的信号说明拉取没有超时。接着到 Graph 页面随便查一个指标比如up看返回是否正常。up是 Prometheus 自动生成的特殊指标值为 1 表示目标在线0 表示离线。通过up{jobmysql} 0这样的查询就能快速判断某个 job 下的哪些实例挂了。7. 告警闭环Alertmanager 部署与通知接入7.1 监控不加告警等于白搭这是我反复强调的观点只搭监控不配告警等于给别人展示你家的窗户有多大却没有装报警器。Prometheus 本身负责判断指标是否异常Alertmanager 负责异常了怎么通知人。两者配合才能形成一个完整的监控闭环。7.2 编写告警规则文件创建/usr/local/prometheus/rules/node.ymlgroups: - name: node-alerts rules: - alert: NodeDown expr: up{joblinux-node} 0 for: 1m labels: severity: critical annotations: summary: {{ $labels.instance }} 已宕机 description: 实例 {{ $labels.instance }} 已经超过 1 分钟无法访问 - alert: HighCpuUsage expr: 100 - avg(irate(node_cpu_seconds_total{modeidle}[5m])) by (instance) * 100 90 for: 5m labels: severity: warning annotations: summary: {{ $labels.instance }} CPU 使用率过高for: 5m表示条件持续 5 分钟后才触发告警这是为了过滤瞬时尖峰导致的误报。写好后用 promtool 校验/usr/local/prometheus/promtool check rules /usr/local/prometheus/rules/node.yml然后在prometheus.yml的rule_files里引用这个目录我前面配置里已经写好了/usr/local/prometheus/rules/*.yml所以直接把文件丢进去reload 配置即可。7.3 Alertmanager 安装与路由配置下载并安装 Alertmanagercd /opt wget https://github.com/prometheus/alertmanager/releases/download/v0.28.0/alertmanager-0.28.0.linux-amd64.tar.gz tar xvf alertmanager-0.28.0.linux-amd64.tar.gz mv alertmanager-0.28.0.linux-amd64 /usr/local/alertmanagerAlertmanager 的核心是/usr/local/alertmanager/alertmanager.yml它决定告警怎么路由、向哪里发送。一个最简配置route: group_by: [alertname] group_wait: 10s group_interval: 30s repeat_interval: 4h receiver: webhook receivers: - name: webhook webhook_configs: - url: http://127.0.0.1:8000/alert几个时间参数值得细说。group_wait是同一组告警第一次触发后等待多久再发送这样可以把短时间内同时触发的多条告警合并成一条。group_interval控制两组告警之间的发送间隔。repeat_interval是同一个告警未恢复时的重复通知间隔我设成 4 小时避免告警刷屏你也可以按业务紧急程度改成 1 小时或更长。同样用 systemd 托管运行。启动后访问9093端口能看到 Alertmanager 的 UI里面可以管理静默规则、查看已接收的告警。7.4 用极简 webhook 把告警推到钉钉Alertmanager 原生支持邮件、Slack、企业微信但钉钉需要额外转发。最简单的方案是写一个十几个行的小服务接收 Alertmanager 的 webhook 请求再转发到钉钉机器人。我用 Python Flask 写过这样一个转发器整个过程很快from flask import Flask, request import requests app Flask(__name__) DINGTALK_WEBHOOK https://oapi.dingtalk.com/robot/send?access_token你的token app.route(/alert, methods[POST]) def alert(): data request.json alerts data.get(alerts, []) for alert in alerts: status alert.get(status) name alert[labels].get(alertname) instance alert[labels].get(instance) summary alert[annotations].get(summary, ) msg {msgtype: text, text: {content: f[{status}] {name} - {instance}: {summary}}} requests.post(DINGTALK_WEBHOOK, jsonmsg) return ok if __name__ __main__: app.run(host0.0.0.0, port8000)把脚本部署在一台能被 Alertmanager 访问的机器上配置好钉钉机器人的 webhook token然后在 alertmanager.yml 里把 webhook URL 指向这个服务reload 后就能在手机上收到告警消息了。同样的思路也可以对接企业微信机器人或者飞书核心只是换一个 webhook 地址。7.5 告警状态的完整生命周期理解告警状态流转能让排错时少绕弯子。一个告警规则从触发到通知会经历 inactive、pending、firing、resolved 四个状态。条件刚满足时进入 pending持续超过for设定的时间后变成 firingAlertmanager 这时才发送通知条件恢复后进入 resolved并发送恢复通知。很多时候你觉得告警没触发其实它可能在 pending 状态等for窗口或者已经被 Alertmanager 静默了。排查时先看 Prometheus 的 Alerts 页面确认规则的状态再去 Alertmanager 的 UI 里看是否被抑制或静默这两个页面基本能定位 90% 的问题。8. 容器化部署Docker Compose 和 k8s 的落地姿势8.1 用 Docker Compose 一键拉起整套监控栈如果你已经习惯容器化运维或者只是想在开发环境快速验证Docker Compose 是最省事的方式。直接写一个docker-compose.ymlservices: prometheus: image: prom/prometheus:v2.53.0 container_name: prometheus volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - ./rules:/etc/prometheus/rules - prometheus-data:/prometheus ports: - 9090:9090 restart: always alertmanager: image: prom/alertmanager:v0.28.0 container_name: alertmanager volumes: - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml ports: - 9093:9093 restart: always grafana: image: grafana/grafana:11.3.0 container_name: grafana environment: - GF_SECURITY_ADMIN_PASSWORDadmin volumes: - grafana-data:/var/lib/grafana ports: - 3000:3000 depends_on: - prometheus restart: always volumes: prometheus-data: grafana-data:本地目录下的prometheus.yml和alertmanager.yml可以沿用前面所有配置直接挂进容器即可。执行docker compose up -d整套监控栈就起来了。注意容器内时区默认是 UTCGrafana 显示时间会差 8 小时需要在 Grafana 的 Settings 里把 Default timezone 改成 Asia/Shanghai。8.2 容器部署时的数据持久化要点容器是无状态的数据必须放在 volume 里。上面的 compose 文件里prometheus-data和grafana-data就是 named volume容器删除重建后数据依然保留。升级版本前建议先停掉容器、备份数据目录再换镜像启动。实际操作中遇到过用旧数据跑新版本导致 TSDB 启动失败的情况所以备份这一步千万别省。备份 Prometheus 数据直接打包 volume 对应的目录就可以Grafana 则主要备份配置文件和数据源配置面板数据通常建议用 provisioning 方式统一管理而不是手动点出来的。8.3 Kubernetes 部署的思路与注意点在 k8s 集群内部署监控就不建议手写 Deployment 了直接用kube-prometheus-stack这个 Helm chart它把 Prometheus、Grafana、Alertmanager 以及各类 exporter 都打包好还带上了 ServiceMonitor 机制。K8s 部署和裸机部署最大区别在于服务发现方式。裸机用 static_configs 或 file_sd_configsk8s 里则通过kubernetes_sd_configs自动发现 Pod、Service、Node 等资源配合 ServiceMonitor 声明我要监控哪个服务的哪些指标。Prometheus 会自动捕捉这些声明并生成抓取配置。在 k8s 里部署的明显优势是新增服务自动被发现不需要手工改配置缺点是需要理解 Operator、CRD 的概念学习曲线比裸机部署陡一些。如果只是小集群三五台节点我的建议是先在节点上用二进制方式部署把基础监控跑起来后续再迁移到 Operator 方案。9. 上线运行后最常踩的坑六条排障经验9.1 时间不同步导致数据断层和告警误判这个问题我在前面说过但值得再强调一次因为它是我遇到过的伪装性最强的坑。现象是 Grafana 图表出现明显断层Prometheus 查询出来的数据点错位甚至告警在没有任何异常时反复触发。排查结果是某台被监控机器的系统时间慢了 3 分钟。解决办法就是所有机器统一部署 chrony并配置开机自启。监控机和被监控机都要做不能只做一边。9.2 TSDB 磁盘被写满Prometheus 默认只清理超出保留期我配的是 15 天的数据如果某段时间数据量暴涨磁盘可能在保留期到达前就写满。我当时在一批高基数指标接入后一天涨了 3GB差点把监控机磁盘撑爆。预防手段有三个一是定期用du -sh /data/prometheus检查数据目录大小变化趋势二是在 Grafana 上给监控机的磁盘使用率单独建一个告警三是适当缩短--storage.tsdb.retention.time比如改成 7 天。9.3 抓取超时导致丢点Prometheus 默认scrape_timeout是 10 秒。如果某个 exporter 响应慢或者网络质量差抓取就会超时目标状态变成 DOWN 或抓取失败。在 Grafana 上看到曲线不是平滑的而是有规律的缺口基本就是这个原因。可以在 job 级别单独覆盖抓取超时- job_name: slow-exporter scrape_timeout: 30s static_configs: - targets: [192.168.1.20:9104]但要记住scrape_timeout 不能设置得比 scrape_interval 还大否则会不断丢数据。9.4 高基数标签导致内存暴涨这是我吃过最大的一次亏。曾经在一套业务监控里把一个包含用户 ID 的维度做成标签结果指标数量从几万冲到几百万Prometheus 内存占用飙到十几个 GB直接把监控机拖垮。判断一个标签是否高基数最简单的标准是它的取值数量是否随业务量线性增长。机器名、环境名、服务名可以当标签用户 ID、会话 ID、请求 URL 绝对不能当标签。如果已经很混乱了可以通过promtool analyze分析 TSDB 的 series 数量分布找出占比重最大的指标然后调整采集端。9.5 告警反复触发刷屏告警配置完成后最常遇到的问题就是通知太频繁。刚开始我把 repeat_interval 设成 1 小时结果一次小故障群里被刷了几十条同样的消息。要解决这个问题重点在于理解group_wait和repeat_interval的配合。group_wait设成 10s 左右让同一时间触发的一组告警合并发送repeat_interval设成 4 小时以上保证一条告警至少 4 小时才重复一次。对于短时抖动类告警还可以在规则里把for设置得更长比如 5 分钟让真正的持续故障才触发告警。9.6 Grafana 图空白但 targets 状态正常面板显示 No data 是最常见的 Grafana 排错场景。按这个顺序排查先确认查询里用的指标名字是否存在去 Prometheus 的 Graph 页面执行一遍同样查询如果有数据问题出在 Grafana 侧。常见原因有面板的数据源选错多数据源环境容易发生、面板变量名和实际标签不匹配、查询时间范围太大导致性能问题。另一个低调的坑是模板导入后默认查询的 job 名和你的实际 job 名对不上。比如模板写的jobnode_exporter而我配置的 job_name 是linux-node结果整个面板都空白。解决办法是去 Prometheus 的 Targets 页面确认实际的 job 标签值然后在 Grafana 面板的查询里全局替换或者在模板 dashboard 设置里修改变量的默认值。写在最后的一点体会整个部署流程跑下来我最深的感受是监控系统不是一次搭完就结束的它必须跟着业务一起演进。第一次部署只需要五个组件加三台机器跑通主机和数据库监控跑顺之后再逐步把中间件、业务指标、k8s 集群纳进来每次都加一小块系统性地扩展。还有一个建议生产环境监控机的告警一定要做成多通道钉钉群负责日常告警邮件作为兜底。我在某个晚上遇到过 webhook 转发服务因为服务器重启而失效的情况虽然监控在正常跑但告警完全没发出去第二天早上才发现。所以现在我会在监控机上加一个定时任务定期探测告警链路是否可用这个习惯帮我在之后的运行中避免了好几次假安全。最后再分享一个小技巧每次调整告警规则或者抓取配置之前先执行一遍promtool check config和promtool check rules。这两条命令花不了 10 秒钟但能省掉触发规则语法错误导致整个规则组不加载的麻烦。等你把整套体系跑起来再回到登录服务器敲命令的老路上看一眼大概率就再也不想回去了。