多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Prometheus与Grafana生产级手动部署实战指南

Prometheus与Grafana生产级手动部署实战指南 1. 这不是“又一个监控教程”而是你真正能落地的生产级观测栈搭建实录Prometheus 和 Grafana 这两个词现在几乎已经成了运维、SRE、云原生工程师日常对话里的“空气”——看不见摸不着但缺了它整个系统就喘不过气。我第一次在客户现场部署 PrometheusGrafana 是2019年当时用的是手动编译二进制包、手写 YAML 配置、连 Dashboard 都得靠复制粘贴社区模板。三年后我在一家中型电商公司主导重构监控体系把原来零散的 Zabbix 自研脚本 Excel 告警汇总表替换成统一的 PrometheusGrafanaAlertmanager 架构上线首月就定位到3起隐蔽的数据库连接池耗尽问题平均故障发现时间从47分钟压缩到92秒。这不是魔法是可复现、可验证、可交接的一套工程实践。今天这篇内容不讲“什么是指标”“为什么需要监控”只讲你打开终端、敲下第一行命令时该做什么、为什么这么做、哪里最容易卡住、以及我踩过的五个真实坑。适合两类人一类是刚拿到测试服务器、想快速跑通链路的新手另一类是正在为线上集群设计长期监控方案的工程师——前者能照着步骤5分钟拉起基础界面后者能从中提取出适配自己环境的架构取舍逻辑。核心关键词就是标题本身Prometheus、Grafana、安装、搭建。所有延伸内容比如 Alertmanager 集成、Exporter 选型、TLS 加密都围绕这四个词展开不发散、不炫技、不堆概念。下面进入正题。2. 整体设计思路为什么不用 Docker 一键启动为什么坚持手动部署2.1 选择“手动二进制部署”而非“Docker Compose 一键拉起”的底层逻辑很多人看到标题第一反应是“直接 docker run 不就完了”我试过也推荐过但最终在生产环境全部推翻重来。原因很实在可观测性系统本身必须是可观测的。当你用 Docker 启动 Prometheus它的进程、内存、磁盘 IO 全部被容器 runtime 封装在 cgroup 里一旦容器内核态出现 OOM Killer 杀掉进程或者 overlay2 文件系统写满导致 WAL 日志无法刷盘你连最基础的“为什么挂了”都查不到——因为宿主机上看不到 Prometheus 的真实进程树也看不到它实际占用的磁盘空间。而手动部署意味着你能用ps aux | grep prometheus看到完整进程参数用df -h /data/prometheus直接定位存储瓶颈用systemctl status prometheus查看服务生命周期状态。这不是复古是把监控系统的“自监控”能力前置到部署阶段。更关键的是配置治理。Docker Compose 把所有配置塞进一个docker-compose.yml当你要给不同环境dev/staging/prod配置不同的 scrape_interval、不同的 alert rules path、不同的 remote_write endpoint 时YAML 的嵌套和变量替换会迅速失控。而手动部署配合 systemd unit 文件天然支持EnvironmentFile/etc/default/prometheus-prod这种外部环境变量注入配合 Ansible 模板一套配置文件能覆盖 20 个集群节点且每个节点的配置差异比如某台物理机要额外采集 smartctl 硬盘健康数据只需修改一行ExecStart参数即可生效。2.2 架构分层明确 Prometheus 和 Grafana 的职责边界很多初学者把 Prometheus 当成“万能监控平台”试图让它既做数据采集、又做可视化、还做告警通知结果配置越写越臃肿重启一次要等两分钟。正确的分层是Prometheus 是时序数据库 规则引擎它只干三件事——从 Exporter 拉取指标scrape、按规则计算聚合值recording rules、触发告警条件alerting rules。它不存历史原始数据超过15天自动清理也不渲染图表那是 Grafana 的事更不发邮件/钉钉那是 Alertmanager 的活。Grafana 是可视化编排器它不碰任何指标采集逻辑只负责从 Prometheus或其他数据源查询数据用 Panel 组合成 Dashboard并提供告警规则配置入口但实际执行仍由 Alertmanager 完成。它的核心价值在于“组合”——你可以把 CPU 使用率、内存剩余量、HTTP 5xx 错误率、JVM GC 时间放在同一张图上对比这种跨维度关联分析是 Prometheus 自带的 Web UI 永远做不到的。Alertmanager 是告警路由器它接收 Prometheus 发来的告警事件做去重同一故障多次触发只发一次、分组把同一台机器的多个告警合并成一条消息、静默维护期间屏蔽特定告警、路由根据标签把数据库告警发给 DBA 组把网络告警发给网络组。它和 Prometheus 是松耦合的 HTTP API 关系可以独立部署、水平扩展。这个分层决定了我们的搭建顺序先让 Prometheus 跑起来并能采集自身指标self-monitoring再接入 Grafana 展示这些指标最后把 Alertmanager 接入形成闭环。跳过任一环节都会在后续调试中付出数倍时间代价。2.3 存储与性能的硬约束为什么必须提前规划数据目录和保留策略Prometheus 默认将所有时序数据写入本地磁盘的./data目录采用 WALWrite-Ahead Log Block 文件结构。WAL 保证崩溃恢复Block 文件按2小时切片归档。但很多人忽略一个致命细节Block 文件一旦生成就不可修改且删除操作是异步的。这意味着如果你设置--storage.tsdb.retention.time30dPrometheus 并不会每天精确删掉30天前的数据而是每2小时检查一次把所有早于30天的 Block 目录标记为“待删除”然后在后台线程里逐个 unlink。如果磁盘 I/O 性能差比如用机械硬盘或低配云盘这个删除过程可能持续数小时期间新数据仍在写入极易触发no space left on device。我们在线上集群的实测数据一台 8C16G 的监控服务器采集 500 个节点含 Kubernetes Pod、Node、etcd、API Server平均每秒写入 12,000 条样本30天 retention 下日均磁盘增长约 18GB。因此我们强制要求数据目录必须挂载在独立 SSD 分区如/mnt/prometheus-data禁止与系统盘共用初始分配空间不低于 200GB按 30 天预估留 20% buffer启动参数显式指定--storage.tsdb.path/mnt/prometheus-data避免默认路径误写入根分区retention 时间按业务 SLA 设定核心交易链路设 90 天中间件设 60 天基础设施设 30 天通过多实例分片实现。这个决策直接影响后续所有环节——Grafana 查询延迟、Alertmanager 告警触发实时性、甚至系统升级时的数据迁移成本。它不是“安装完再调”的事后优化而是部署前必须拍板的架构前提。3. 核心细节解析从下载到服务化每一步背后的原理与陷阱3.1 下载与校验为什么必须验证 SHA256而不是直接curl | bashPrometheus 和 Grafana 官方发布页https://prometheus.io/download/ 和 https://grafana.com/grafana/download提供 Linux AMD64 的 tar.gz 包。新手常犯的错误是直接wget https://github.com/prometheus/prometheus/releases/download/v2.47.2/prometheus-2.47.2.linux-amd64.tar.gz tar xzf prometheus-*.tar.gz看似省事实则埋下隐患。去年我们就遇到一起事故某外包团队从非官方镜像站下载的 Prometheus 包被植入挖矿木马导致监控服务器 CPU 满载所有告警失效。正确流程必须包含校验环节# 1. 下载二进制包和对应的 SHA256 校验文件 wget https://github.com/prometheus/prometheus/releases/download/v2.47.2/prometheus-2.47.2.linux-amd64.tar.gz wget https://github.com/prometheus/prometheus/releases/download/v2.47.2/prometheus-2.47.2.linux-amd64.tar.gz.sha256 # 2. 用 sha256sum 验证注意校验文件内容是 hash filename 格式 sha256sum -c prometheus-2.47.2.linux-amd64.tar.gz.sha256 # 输出应为prometheus-2.47.2.linux-amd64.tar.gz: OK # 3. 解压并重命名避免版本号混入路径 tar xzf prometheus-2.47.2.linux-amd64.tar.gz mv prometheus-2.47.2.linux-amd64 /opt/prometheus提示校验步骤不能省略。SHA256 是密码学哈希即使篡改一个字节校验值也会完全不同。这是防止供应链攻击的第一道防线。Grafana 同理但要注意其包名规律grafana-10.2.3-1.x86_64.rpmRPM或grafana-10.2.3.linux-amd64.tar.gztarball。我们优先选 tarball因为 RPM 安装会自动创建系统用户、修改/etc目录不利于容器化迁移而 tarball 完全可控所有路径、权限、启动方式均由我们定义。3.2 Prometheus 配置文件prometheus.yml的最小可行结构一个能跑通的prometheus.yml核心只需三块内容global 配置、scrape_configs、rule_files。很多人一上来就抄几十行复杂配置结果连自身指标都采不到。我们从最简开始# /etc/prometheus/prometheus.yml global: scrape_interval: 15s # 全局抓取间隔所有 job 默认继承此值 evaluation_interval: 15s # 规则评估间隔必须 scrape_interval scrape_configs: # 第一个 job采集 Prometheus 自身指标self-monitoring - job_name: prometheus static_configs: - targets: [localhost:9090] # Prometheus 自带的 metrics endpoint # 第二个 job采集 Node Exporter假设已运行在 192.168.1.100:9100 - job_name: node static_configs: - targets: [192.168.1.100:9100]这里的关键细节scrape_interval: 15s不是越小越好。频繁抓取会增加目标端负载尤其对 MySQL 这类 Exporter且 Prometheus 自身 CPU 消耗呈线性增长。我们线上集群统一设为 30s对大多数指标足够敏感。static_configs是最简单的服务发现方式适用于固定 IP 的物理机或虚拟机。Kubernetes 环境必须换成kubernetes_sd_configs但那是进阶内容不在本次搭建范围。targets必须写 IP端口不能写 hostname除非你确保所有节点/etc/hosts里有对应解析否则 DNS 失败会导致整个 job 抓取失败。注意配置文件必须用 UTF-8 编码保存Windows 记事本默认是 GBK用它编辑会导致parsing YAML file /etc/prometheus/prometheus.yml: yaml: control characters are not allowed错误。建议用 VS Code 或 vim 编辑并在底部状态栏确认编码。3.3 systemd 服务化为什么不用nohup ./prometheus 把 Prometheus 当成普通进程后台运行是新手最大误区。nohup无法管理进程生命周期一旦 OOM 被杀不会自动重启日志分散在nohup.out难以集中收集更严重的是它不遵循 Linux 的 service 语义无法与系统 shutdown 流程集成——服务器重启时Prometheus 可能比网络服务先启动导致localhost:9090连接拒绝。标准做法是编写 systemd unit 文件# /etc/systemd/system/prometheus.service [Unit] DescriptionPrometheus Server Documentationhttps://prometheus.io/docs/ Afternetwork.target [Service] Typesimple Userprometheus Groupprometheus ExecStart/opt/prometheus/prometheus \ --config.file/etc/prometheus/prometheus.yml \ --storage.tsdb.path/mnt/prometheus-data \ --web.listen-address:9090 \ --web.external-urlhttp://monitor.example.com:9090 \ --storage.tsdb.retention.time30d Restartalways RestartSec10 LimitNOFILE65536 [Install] WantedBymulti-user.target关键参数说明Userprometheus必须创建专用系统用户useradd --no-create-home --shell /bin/false prometheus禁止用 root 运行这是安全基线ExecStart参数分行书写便于阅读和调试--web.external-url是 Grafana 反向代理必需的否则 Dashboard 里点击链接会跳转到http://localhost:9090Restartalways确保崩溃后自动拉起RestartSec10避免频繁重启如配置错误导致秒退LimitNOFILE65536解除文件描述符限制Prometheus 在高负载时可能打开数千个文件。启用服务sudo systemctl daemon-reload sudo systemctl enable prometheus sudo systemctl start prometheus sudo systemctl status prometheus # 检查是否 active (running)3.4 Grafana 部署解压即用但必须改三处配置Grafana tarball 解压后目录结构清晰/opt/grafana/ ├── bin/ # 主程序 grafana-server ├── conf/ # 默认配置文件 defaults.ini ├── data/ # SQLite 数据库存放位置默认 ├── public/ # 前端静态资源 └── plugins/ # 插件目录启动命令./bin/grafana-server web即可但默认配置有三个必须修改点数据库路径默认用 SQLite 存 Dashboard 和用户信息但 SQLite 在高并发下易锁死。生产环境必须切换为 PostgreSQL 或 MySQL。我们选 PostgreSQL因其事务强一致性# 编辑 /opt/grafana/conf/defaults.ini [database] type postgres host 127.0.0.1:5432 name grafana user grafana password your_strong_password管理员密码首次访问http://ip:3000时默认账号 admin/admin必须立即修改。但更安全的做法是在启动前预置[security] admin_user admin admin_password YourSecurePassword2024!静态资源路径如果 Grafana 前端需通过 Nginx 反向代理如https://monitor.example.com必须设置[server] domain monitor.example.com root_url %(protocol)s://%(domain)s/ serve_from_sub_path true实操心得Grafana 的root_url设置是高频坑点。如果设为http://localhost:3000/而你用 Nginx 代理到/grafana/路径所有前端请求会 404。正确做法是 Nginx 配置location /grafana/ { proxy_pass http://127.0.0.1:3000/; }同时 Grafana 中root_url https://monitor.example.com/grafana/。我们曾因这个配置错位导致整个 Dashboard 加载空白排查耗时 3 小时。4. 实操全流程从零开始15 分钟完成可验证的监控链路4.1 环境准备清单四台机器的最小拓扑我们以最简但真实的场景为例一台监控服务器CentOS 7.9、一台被监控的 Linux 主机Ubuntu 22.04、一台 PostgreSQL 数据库同监控服务器、一台浏览器客户端。所有操作均在监控服务器上执行。角色IP 地址用途是否必需Prometheus Server192.168.1.10运行 Prometheus 服务✅Grafana Server192.168.1.10运行 Grafana 服务✅PostgreSQL192.168.1.10存 Grafana 元数据✅生产环境Target Node192.168.1.100运行 Node Exporter提供主机指标✅注意虽然 Prometheus 和 Grafana 可在同一台机器但强烈建议 PostgreSQL 独立部署。SQLite 在 Grafana 重启时可能损坏我们线上已发生 2 次 Dashboard 丢失事故。4.2 步骤一部署 Node Exporter被监控端Node Exporter 是 Prometheus 生态最基础的 Exporter采集 CPU、内存、磁盘、网络等主机指标。在192.168.1.100上执行# 创建专用用户 sudo useradd --no-create-home --shell /bin/false node_exporter # 下载并校验同 Prometheus 方式 wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz.sha256 sha256sum -c node_exporter-1.6.1.linux-amd64.tar.gz.sha256 # 解压并安装 tar xzf node_exporter-1.6.1.linux-amd64.tar.gz sudo cp node_exporter-1.6.1.linux-amd64/node_exporter /usr/local/bin/ sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter # 创建 systemd 服务 sudo tee /etc/systemd/system/node_exporter.service EOF [Unit] DescriptionNode Exporter Afternetwork.target [Service] Typesimple Usernode_exporter Groupnode_exporter ExecStart/usr/local/bin/node_exporter \ --collector.systemd \ --collector.filesystem.ignored-mount-points^/(sys|proc|dev|run|boot|var/lib/docker/.)($|/) \ --web.listen-address:9100 Restartalways RestartSec10 [Install] WantedBymulti-user.target EOF sudo systemctl daemon-reload sudo systemctl enable node_exporter sudo systemctl start node_exporter关键参数解释--collector.systemd启用 systemd 指标采集如服务状态、启动耗时这对 SRE 故障定位极有价值--collector.filesystem.ignored-mount-points忽略 Docker overlay2、/proc 等伪文件系统避免采集大量无意义指标--web.listen-address:9100监听所有接口方便 Prometheus 从其他网段抓取。验证curl http://192.168.1.100:9100/metrics | head -20应返回文本格式指标如node_cpu_seconds_total{cpu0,modeidle} 1.2345e06。4.3 步骤二配置 Prometheus 抓取 Node Exporter回到监控服务器192.168.1.10编辑/etc/prometheus/prometheus.yml添加 node jobscrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090] - job_name: node # 新增 job static_configs: - targets: [192.168.1.100:9100] # 指向被监控主机重载配置sudo systemctl reload prometheus # 或发送 SIGHUPkill -HUP $(pidof prometheus)验证访问http://192.168.1.10:9090/targetsStatus 应为 UPLabels 显示instance192.168.1.100:9100。点击 “Metrics” 标签页输入node_cpu_seconds_total应看到时间序列数据。4.4 步骤三启动 Grafana 并添加 Prometheus 数据源启动 Grafana# 创建数据目录和日志目录 sudo mkdir -p /var/log/grafana /var/lib/grafana sudo chown -R grafana:grafana /var/log/grafana /var/lib/grafana # 启动服务假设已配置 PostgreSQL sudo systemctl enable grafana-server sudo systemctl start grafana-server访问http://192.168.1.10:3000用admin/YourSecurePassword2024!登录。添加数据源点击左侧齿轮图标 → “Data Sources” → “Add data source”选择 “Prometheus”Name 填Prometheus-ProdURL 填http://localhost:9090Grafana 和 Prometheus 同机走 localhost其他保持默认点击 “Save test”提示如果 Grafana 和 Prometheus 不在同一台机器URL 必须填可路由的 IP如http://192.168.1.10:9090且确保防火墙开放 9090 端口sudo firewall-cmd --permanent --add-port9090/tcp。4.5 步骤四导入经典 Dashboard验证端到端链路Grafana 社区有海量现成 Dashboard。我们导入最经典的 “Node Exporter Full”ID: 1860点击左侧 “” → “Import”输入 Dashboard ID1860→ “Load”选择数据源 “Prometheus-Prod” → “Import”几秒钟后你会看到一张密密麻麻的主机监控大屏CPU 使用率曲线、内存使用热力图、磁盘 I/O 延迟分布、网络流量 TOP10 进程……随便点一个 Panel右上角 “Inspect” → “Query” 可看到背后的真实 PromQL 查询如100 - (avg by(instance) (rate(node_cpu_seconds_total{modeidle}[5m])) * 100)。此时整个链路已闭环Node Exporter 采集 → Prometheus 存储 → Grafana 查询展示。你可以放心进行下一步告警配置。5. 常见问题与排查技巧实录那些文档里不会写的实战经验5.1 问题速查表5 类高频故障及 3 分钟定位法现象可能原因快速定位命令解决方案http://ip:9090/targets显示 DOWNPrometheus 无法连接 targetcurl -v http://192.168.1.100:9100/metrics检查 target 端防火墙、node_exporter 进程、端口监听ss -tlnp | grep 9100Grafana Dashboard 空白Network 显示 404root_url配置错误或 Nginx 代理路径不匹配curl -I http://192.168.1.10:3000/public/build/app.abc123.js核对 Grafanaconf/defaults.ini中root_url和 Nginxlocation路径是否一致Prometheus 启动失败日志报open /mnt/prometheus-data: permission deniedsystemd 服务用户无数据目录权限sudo ls -ld /mnt/prometheus-datasudo chown -R prometheus:prometheus /mnt/prometheus-dataGrafana 登录后提示 “Database Error: pq: password authentication failed for user ‘grafana’”PostgreSQL 用户密码不匹配sudo -u postgres psql -c SELECT usename FROM pg_user;用sudo -u postgres psql进入执行ALTER USER grafana WITH PASSWORD newpass;Alertmanager 配置后告警不触发Prometheus 的 alert.rules 文件未加载或语法错误sudo /opt/prometheus/prometheus --config.file/etc/prometheus/prometheus.yml --alertmanager.urlhttp://localhost:9093 --dry-run检查rule_files路径是否存在用promtool check rules /etc/prometheus/alert.rules验证语法5.2 独家避坑技巧来自 37 次线上部署的血泪总结技巧一用promtool提前验证所有配置Prometheus 自带promtool它是配置安全阀。每次修改prometheus.yml或alert.rules必须执行# 验证主配置 /opt/prometheus/promtool check config /etc/prometheus/prometheus.yml # 验证告警规则 /opt/prometheus/promtool check rules /etc/prometheus/alert.rules我们曾因一个漏掉的引号severity: critical缺少结尾引号导致 Prometheus 启动失败回滚耗时 40 分钟。promtool能在systemctl start前 10 秒就发现问题。技巧二Grafana 插件安装必须用 CLI禁用 Web UIGrafana Web UI 的插件安装会下载到/var/lib/grafana/plugins/但该目录权限常被 systemd 服务重置。正确方式是# 切换到 grafana 用户执行 sudo -u grafana /opt/grafana/bin/grafana-cli plugins install grafana-piechart-panel sudo systemctl restart grafana-server否则插件列表里显示已安装但实际不生效。技巧三Prometheus 内存暴涨的终极解法当 Prometheus 内存持续增长至 90%top显示RES达 8GB不要急着 kill。先查# 查看内存占用 top 10 的 metric curl http://localhost:9090/api/v1/status/tsdb \| jq .stats.seriesCountByMetricName \| sort -k2 -nr \| head -10如果发现container_network_receive_bytes_total占比超 40%说明你采集了太多 Docker 容器网络指标。解决方案不是删数据而是在 scrape_configs 中加 relabel_rules 过滤- job_name: kubernetes-cadvisor kubernetes_sd_configs: [...] relabel_configs: - source_labels: [__name__] regex: container_network_receive_bytes_total|container_network_transmit_bytes_total action: drop这比重启 Prometheus 有效 10 倍。技巧四Grafana Dashboard 导出/导入的隐藏字段用 Grafana Web UI 导出的 JSON 文件包含id: 123字段。导入时若目标环境已有同名 DashboardGrafana 会报错。解决方法导出后手动删除 JSON 中的id行或使用 CLI 导出# CLI 导出不带 id可直接导入 /opt/grafana/bin/grafana-cli dashboard export 1860 node-full.json技巧五时间同步是所有监控系统的隐形基石我们曾遇到一个诡异问题Prometheus 抓取到的指标时间戳比实际晚 5 分钟导致 Grafana 图表显示“未来数据”。根源是监控服务器 NTP 未同步。强制同步sudo timedatectl set-ntp true sudo systemctl restart chronyd # 或 ntpd # 验证timedatectl status \| grep System clock synchronized所有节点Prometheus、Grafana、Exporter、Alertmanager必须严格时间同步误差 100ms否则时序对齐失效。5.3 告警闭环从 Prometheus 到 Alertmanager 的最小配置虽然标题未提 Alertmanager但没有告警的监控是残废的。补充最小可行告警链路下载 Alertmanager同 Prometheus 方式解压到/opt/alertmanager创建配置/etc/alertmanager/alertmanager.ymlglobal: resolve_timeout: 5m route: group_by: [alertname, cluster] group_wait: 30s group_interval: 5m repeat_interval: 12h receiver: email receivers: - name: email email_configs: - to: adminexample.com smarthost: smtp.example.com:587 from: alertmonitor.example.com auth_username: alertmonitor.example.com auth_password: your_smtp_password启动 Alertmanagersudo systemctl enable alertmanager sudo systemctl start alertmanager修改 Prometheus 配置指向 Alertmanageralerting: alertmanagers: - static_configs: - targets: [localhost:9093] rule_files: - /etc/prometheus/alert.rules创建/etc/prometheus/alert.rulesgroups: - name: example rules: - alert: HighCPUUsage expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{modeidle}[5m])) * 100) 80 for: 10m labels: severity: warning annotations: summary: High CPU usage on {{ $labels.instance }}最后提醒告警阈值不是拍脑袋定的。我们线上所有 80类规则都基于过去 30 天的历史 P95 值设定。用 PromQLhistogram_quantile(0.95, sum(rate(...)))计算比凭经验可靠得多。我在实际部署中发现最耗时的环节从来不是技术本身而是沟通——和开发确认哪些 JVM 指标要采集和 DBA 约定 MySQL Exporter 的慢查询阈值和安全团队对齐 Alertmanager 的 SMTP 白名单。这套 PrometheusGrafana 搭建流程我们已固化为标准 SOP在 12 个业务线推广平均部署时间从 3 天压缩到 4 小时。它不追求最新特性只确保每一步都经得起生产环境拷问。如果你按本文操作后仍有卡点欢迎带着具体错误日志来找我我们可以一起看journalctl -u prometheus -n 100的最后一行。
返回列表