Prometheus 自 2012 年由 SoundCloud 开源以来,已从单一的监控工具演变为云原生可观测性的事实标准。但"部署成功"与"部署正确"之间往往存在显著差距------前者只是进程跑起来了,后者要求你对 Pull 模型的内存语义、TSDB 的块生命周期、3.x 的破坏性变更以及生产环境的容量边界有清醒认知。本文以 OS 运维与 DevOps 的双重视角,从概念原理出发,逐步落地到可复用的二进制部署与生产加固实践。
一、概念与原理:Prometheus 到底在做什么
1.1 核心架构与数据流向
Prometheus 不是单体工具,而是一个由多个组件协作的生态系统。其核心组件与数据流如下:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐
│ Node │ │ MySQL │ │ Blackbox │ │ Pushgateway │
│ Exporter │ │ Exporter │ │ Exporter │ │ (短任务) │
└────┬─────┘ └────┬─────┘ └────┬─────┘ └─────┬──────┘
│ /metrics │ /metrics │ /metrics │ Push
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ Prometheus Server │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │Retrieval │──▶│ TSDB │◀──│ HTTP Server │ │
│ │(采集引擎)│ │ (存储) │ │ (查询API) │ │
│ └────┬─────┘ └──────────┘ └──────────────────┘ │
│ │ │
│ ┌────┴──────────────────┐ │
│ │ Service Discovery │ │
│ │ (K8s / Consul / 文件) │ │
│ └───────────────────────┘ │
└──────────────────────┬──────────────────────────────────┘
│
┌────────────┴────────────┐
▼ ▼
┌──────────────────┐ ┌─────────────────────┐
│ Alertmanager │ │ Remote Storage │
│ (告警路由/抑制) │ │ (Thanos / VM / ...) │
└────────┬─────────┘ └─────────────────────┘
▼
Slack / 钉钉 / 邮件
Prometheus Server 是绝对核心 ,包含三个子模块:Retrieval 负责按配置拉取指标;TSDB 负责时序数据的持久化存储;HTTP Server 提供 PromQL 查询接口。Exporter 将异构系统的指标标准化为 /metrics 端点;Pushgateway 专为 CronJob 等短生命周期任务设计,弥补 Pull 模型无法覆盖的场景;Alertmanager 独立于 Server 处理告警的分组、抑制、静默和路由,与采集侧解耦。
1.2 Pull 模型的工程含义
Prometheus 采用拉取模型,而非 Zabbix 式的推送模型。这一选择带来了三个运维层面的事实:
- 目标健康即拉取健康 :
up == 0就是目标可达性的直接信号,无需额外的"心跳"机制。 - 采集节奏由 Prometheus 主导:目标端的负载不受采集频率的突发影响,便于容量规划。
- 服务发现是动态环境的必需项 :在 Kubernetes 或弹性伸缩场景中,手动维护
targets列表不具备可运维性,必须引入基于 API 的服务发现。
1.3 TSDB 的存储生命周期
理解 TSDB 的行为对生产容量规划至关重要。Prometheus 的本地存储遵循"内存 → WAL → 持久块"的三级结构:
- WAL(预写日志) :所有新样本首先写入环形缓冲区,保证进程崩溃时最近约 2 小时的数据可恢复。
- Head Block(内存块) :活跃写入区,驻留最近 2 小时的数据。
- Persistent Block(磁盘块) :每 2 小时将 Head 压缩落盘为一个块,随后后台按 2h → 8h → 24h 的层级进行合并压缩。
这意味着:单纯增加磁盘不会线性延长可查询的历史窗口 ,保留时长由 --storage.tsdb.retention.time 显式控制,默认仅 15 天。对于需要 90 天以上保留期的生产环境,必须规划远程存储或长期存储方案。
二、部署前的环境准备
2.1 版本选择:优先 3.x,而非 2.x
截至当前,Prometheus 3.x 已是稳定主线。不建议沿用大量 2.x 时代的教程,因为 3.0 引入了若干破坏性变更:
--enable-feature=promql-at-modifier、promql-negative-offset等特性标志已被移除,相关行为成为默认。- 抓取目标不再根据 scheme 自动补全端口(
no-default-scrape-port),依赖https://example.com→example.com:443隐式行为的配置需要显式补齐端口。 consoles/和console_libraries/目录在 3.0 中已移除,旧教程中的拷贝步骤不再适用。- 容器环境中自动设置
GOMEMLIMIT和GOMAXPROCS,与 cgroup 限制对齐。
本文以 Prometheus 3.x 为基准进行部署。
2.2 系统层面准备
| 项目 | 建议值 | 说明 |
|---|---|---|
| OS | RHEL/Rocky 9、Ubuntu 22.04/24.04 | systemd 管理,内核 ≥ 5.4 |
| 最小资源 | 4 vCPU / 8 GB RAM / 50 GB SSD | 生产建议在此基础上 ×1.5--2 |
| 文件系统 | XFS 或 ext4,独立数据盘 | TSDB 写入模式对顺序写友好,SSD 显著降低压缩合并时的 I/O 争用 |
| 防火墙 | 仅放行 9090 来自受信网段 | 9090 默认无认证,切勿裸暴露至公网 |
| 时间同步 | chrony/systemd-timesyncd 启用 | 时间戳偏差直接影响查询对齐与告警触发 |
存储选型的关键点 :TSDB 的块压缩(compaction)会产生显著的磁盘 I/O 峰值。将 /var/lib/prometheus 放在独立磁盘上,可以避免压缩 I/O 与系统盘上的日志、容器运行时争抢带宽。
三、二进制部署(systemd 管理)
3.1 创建专用系统用户与目录
以非 root 身份运行是 OS 安全基线的硬性要求:
bash
sudo useradd --system --no-create-home --shell /usr/sbin/nologin prometheus
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
sudo chmod 0755 /etc/prometheus /var/lib/prometheus
/etc/prometheus 存放配置,/var/lib/prometheus 存放 TSDB 数据,二者分离便于备份与磁盘扩展。
3.2 下载与安装二进制
bash
cd /tmp
curl -LO https://github.com/prometheus/prometheus/releases/download/v3.13.1/prometheus-3.13.1.linux-amd64.tar.gz
tar xvf prometheus-3.13.1.linux-amd64.tar.gz
cd prometheus-3.13.1.linux-amd64
sudo cp prometheus promtool /usr/local/bin/
sudo chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtool
sudo chmod 0755 /usr/local/bin/prometheus /usr/local/bin/promtool
promtool 是后续配置校验和规则测试的核心工具,务必与 server 同步安装。3.x 中已不再需要拷贝 consoles/ 目录。
3.3 最小可用配置
先将自带配置落地,再按需扩展:
bash
sudo cp prometheus.yml /etc/prometheus/prometheus.yml
sudo chown prometheus:prometheus /etc/prometheus/prometheus.yml
最小配置只需抓取自身,用于验证采集管道是否打通:
yaml
# /etc/prometheus/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
3.4 配置校验------启动前的强制关卡
bash
promtool check config /etc/prometheus/prometheus.yml
输出 SUCCESS 后方可继续。promtool 能捕获 YAML 语法错误、无效字段和不一致的配置结构,是避免服务启动即崩溃的第一道防线。
3.5 systemd 单元文件
ini
# /etc/systemd/system/prometheus.service
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/var/lib/prometheus \
--storage.tsdb.retention.time=30d \
--storage.tsdb.retention.size=45GB \
--web.listen-address=0.0.0.0:9090 \
--web.enable-lifecycle
[Install]
WantedBy=multi-user.target
参数决策依据:
--storage.tsdb.retention.time=30d与--storage.tsdb.retention.size=45GB双重限制同时生效,先到者触发清理,防止磁盘被意外撑满。--web.enable-lifecycle启用后,方可通过POST /-/reload热加载配置,避免每次改配置都重启进程。--web.listen-address=0.0.0.0:9090仅在需要远程访问时使用;若前置了反向代理,可绑定至127.0.0.1:9090以缩小攻击面。
启动并验证:
bash
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
systemctl status prometheus --no-pager
curl -s http://localhost:9090/-/healthy # 应返回 "Prometheus Server is Healthy."
curl -s http://localhost:9090/api/v1/targets | head # 确认 targets 处于 up 状态
四、核心配置详解:scrape_configs 与目标接入
prometheus.yml 的核心在于 scrape_configs。每个 job 定义一组目标及其抓取行为。
4.1 接入 Node Exporter(主机监控的最小闭环)
在被监控节点上部署 Node Exporter 后,在 Prometheus 侧添加 job:
yaml
scrape_configs:
- job_name: "node"
scrape_interval: 15s
scrape_timeout: 10s # 建议为 interval 的 50%,避免慢目标拖住整个 job
static_configs:
- targets:
- "10.0.1.11:9100"
- "10.0.1.12:9100"
labels:
env: "prod"
role: "app"
关键约束 :scrape_timeout 必须 ≤ scrape_interval,否则配置校验会报错,且在实际运行中会造成采集队列堆积。生产环境默认 15s 采集间隔已能满足绝大多数场景;过短的间隔(如 5s)会成倍放大存储压力和网络开销,应仅在确有高精度需求时开启。
4.2 配置热加载
修改 YAML 后,Prometheus 不会自动感知。标准流程为:
bash
promtool check config /etc/prometheus/prometheus.yml
curl -X POST http://localhost:9090/-/reload
先校验、后 reload,任何一步失败都应在影响服务之前被拦截。
4.3 从静态配置走向服务发现
static_configs 仅适用于目标固定的场景。在 Kubernetes 中,应使用 kubernetes_sd_configs 自动发现 Pod/Service/Endpoints;在虚拟机集群中,可借助 Consul 或基于文件的服务发现(file_sd_configs)实现目标的动态更新,避免手动维护 IP 列表成为运维瓶颈。
五、生产环境关键注意事项
5.1 存储与容量规划:不要凭感觉估算
TSDB 的容量可以用公式粗略量化:
存储量 ≈ 时间序列数 × 1.5 bytes/sample × (86400 / scrape_interval) × 保留天数 × 压缩因子
以一个 10 万活跃序列、15s 采集、30 天保留的场景为例,压缩后约占 24 GB。但 "活跃序列数"是最容易被低估的变量 :高基数标签(如 user_id、request_id、pod_name 未经裁剪)会使序列数在短时间内膨胀几个数量级。部署后应监控 prometheus_tsdb_head_series 指标,设定与容量规划匹配的告警阈值。
本地 TSDB 的设计定位是短期存储。若业务要求 90 天以上的历史查询,不应无限增大本地 retention,而应引入远程读/写 或 Thanos Sidecar 方案,将历史块上传至对象存储,实现存储与查询的分离。
5.2 安全加固:9090 端口不是"内网就安全"
Prometheus 的 Web UI 和 API 默认没有任何认证。仅依赖"放在内网"是一种危险的假设。生产环境至少应做到:
- Web 层认证与 TLS :自 2.24 起,Prometheus 支持通过
--web.config.file启用 basic auth 和 TLS,无需额外反向代理即可保护 UI/API。 - 采集侧加密:对 Exporter 启用 HTTPS 或 mTLS,防止指标数据在传输中被窃听或篡改;Node Exporter 可通过 web 配置支持 TLS + basic auth。
- 网络隔离:Exporter 不应暴露在互联网上;抓取流量应限制在私有网络或 VPC 内部。
- 管理 API 保护 :
--web.enable-admin-api会开放删除序列、清理 tombstone 等高危操作,除非确有运维需求,不应默认启用。
5.3 高可用:单机 Prometheus 不是高可用方案
单机 Prometheus 存在明确的可靠性边界:节点故障即监控盲区。生产级高可用通常从两个层面展开:
采集层高可用:部署两套完全相同的 Prometheus 实例,抓取同一组目标,各自独立存储。查询时由 Grafana 或上层代理对两个数据源去重合并。这是最简单、最成熟的双跑模式。
长期存储与全局视图 :当需要跨集群、跨区域聚合数据,或保留期超过本地磁盘能力时,Thanos 和 VictoriaMetrics 是两条主流路径。Thanos 以 Sidecar 方式挂载在现有 Prometheus 旁,将块上传至对象存储,对现有采集配置零侵入;VictoriaMetrics 则作为独立的远程写入后端,资源占用更低、单机即可支撑较高负载,但需要 Prometheus 通过 remote_write 额外复制数据。选型的核心判断依据是:你是否愿意保留 Prometheus 的原生存储与查询路径------愿意则 Thanos,愿意替换存储层追求运维简洁则 VictoriaMetrics。
5.4 告警职责的分离
不要在 Prometheus Server 上"顺手"处理告警路由。Alertmanager 的分组、抑制、静默机制是专门为告警降噪设计的;将其与采集进程解耦,可以在 Prometheus 维护或重启时保持告警通道的独立可用性。Prometheus 只负责规则评估并将告警推送到 Alertmanager,后者负责"谁在什么时候以什么方式收到什么告警"。
5.5 容器化与 Kubernetes 场景的额外提示
若选择 Docker Compose 部署,务必将 prometheus.yml 和 TSDB 目录以 volume 挂载,否则容器重建即丢失配置与数据。在 Kubernetes 中,kube-prometheus-stack 是社区标准方案,但 Helm chart 的默认值不适合生产:持久化默认关闭、存储容量偏小、保留期未定制。务必在 values.yaml 中显式设置 PVC、retention 和资源 requests/limits,并认真对待 chart 安装后输出的警告信息。
六、部署后验证清单
在宣布"部署完成"之前,逐项确认:
| 检查项 | 命令/方法 | 预期 |
|---|---|---|
| 服务健康 | curl localhost:9090/-/healthy |
返回 Healthy |
| 配置已加载 | curl localhost:9090/api/v1/status/config |
YAML 与磁盘一致 |
| 目标可达 | 访问 /targets 页面或 API |
所有 job 的 target 为 UP |
| 采集间隔生效 | 查询 prometheus_target_interval_length_seconds |
与配置一致 |
| TSDB 写入正常 | 查询 rate(prometheus_tsdb_head_samples_appended_total[5m]) |
非零且稳定 |
| 磁盘余量 | df -h /var/lib/prometheus |
使用率 < 70% |
| 保留期生效 | 查询 prometheus_tsdb_retention_limit_bytes / 观察旧块清理 |
与 --storage.tsdb.retention.* 匹配 |
| 告警链路(如已配置) | 在 Alertmanager 侧确认收到测试告警 | 路由正确、通知可达 |
Prometheus 的部署难点从来不在"把二进制跑起来"。真正的工程挑战在于:理解 Pull 模型和 TSDB 行为对生产可用性的约束,在 3.x 的破坏性变更面前保持配置的正确性,以及在安全、容量、高可用三个维度上做出与业务规模匹配的清醒取舍。本文给出的二进制部署路径是理解这些约束的最佳起点------当你清楚每一个 systemd flag 和 YAML 字段的代价之后,再向 Kubernetes 或远程存储方案迁移,才会是可控的演进,而非盲目的堆叠。