Prometheus 是云原生监控领域的事实标准,2012 年由 SoundCloud 发起,2016 年成为 CNCF 第二个毕业项目(仅次于 Kubernetes)。本文从架构、安装、服务发现、K8s 监控、PromQL 等十个维度,系统性地剖析 Prometheus 的设计原理与实战技巧。
011. Prometheus 架构
整体架构
Prometheus 生态由以下核心组件构成:
- Prometheus Server:生态中枢,负责指标采集(Retrieval)、时序存储(TSDB)、查询服务(HTTP Server)
- Exporters:将第三方系统的指标转换为 Prometheus 可识别格式(如 Node Exporter、MySQL Exporter)
- Pushgateway:为短生命周期任务提供推送式指标中转站
- Alertmanager:接收 Prometheus 告警,进行去重、分组、路由、抑制后通知
- Service Discovery:动态发现监控目标(Kubernetes、Consul、DNS 等)
- Grafana / 表达式浏览器:数据可视化
数据流全链路:
Targets (应用/Exporter)
↓ HTTP GET /metrics (Pull)
Prometheus Server
├── Retrieval (采集引擎)
│ ├── Service Discovery (发现 Target)
│ └── Scrape Manager (调度采集)
├── TSDB (时序数据库)
│ ├── Head Block (内存写入)
│ ├── WAL (预写日志)
│ ├── Persistent Blocks (持久化块)
│ └── Compaction (压缩合并)
├── Rules Engine (规则引擎)
│ ├── Recording Rules (预计算)
│ └── Alerting Rules (告警评估)
└── HTTP Server (API/UI)
├── PromQL 查询
└── Remote Read/Write
↓ 告警
Alertmanager (去重/分组/路由/通知)
↓ 可视化
GrafanaPrometheus Server 内部交互
Prometheus Server 启动后,各子系统的协作流程:
- 配置加载:
config/包解析prometheus.yml,构建 scrape 配置和 SD 配置 - 服务发现:
discovery/包根据配置启动对应的 Discoverer(如 Kubernetes SD),持续 watch 目标变化,将结果写入 channel - 采集调度:
scrape/包的 ScrapeManager 从 SD channel 读取目标列表,为每个 job 创建 ScrapePool,按scrape_interval周期性发起 HTTP 请求 - 数据写入:采集到的样本通过 Appender 接口写入 TSDB 的 Head Block,同时写入 WAL 保证持久性
- 规则评估:
rules/包的 Manager 按evaluation_interval周期评估 recording rules 和 alerting rules - 查询服务:
web/包提供 HTTP API,promql/包的 Engine 解析和执行 PromQL 查询
源码架构
Prometheus 源码仓库 (prometheus/prometheus) 的核心目录:
prometheus/
├── cmd/prometheus/ # 主入口 main.go
├── config/ # 配置文件解析 (prometheus.yml)
├── discovery/ # 服务发现实现
│ ├── kubernetes/ # K8s 服务发现
│ ├── consul/ # Consul 服务发现
│ ├── dns/ # DNS 服务发现
│ ├── file/ # 文件服务发现
│ ├── http/ # HTTP 服务发现
│ └── ... # 其他 SD (EC2, GCE, Azure 等)
├── scrape/ # 采集引擎 (ScrapeManager, ScrapePool, Scraper)
├── tsdb/ # 时序数据库
│ ├── head.go # Head Block (内存)
│ ├── wal/ # 预写日志
│ ├── index/ # 倒排索引
│ ├── chunks/ # 数据块存储
│ ├── tombstones/ # 删除标记
│ └── compact.go # 压缩合并
├── promql/ # PromQL 解析与执行引擎
│ ├── parser/ # 语法解析
│ ├── engine.go # 查询执行
│ └── math.go # 数学函数
├── rules/ # 规则引擎 (Recording/Alerting)
├── web/ # HTTP API 和 UI
├── storage/ # 存储抽象层 (本地 + Remote)
├── notifier/ # 告警通知发送
├── promhttp/ # HTTP 中间件 (instrumentation)
└── model/ # 数据模型 (labels, value, time)TSDB 内部结构详解
Prometheus 本地存储(TSDB)是理解 Prometheus 性能特性的关键:
Head Block(内存块):
- 所有新写入的样本首先进入 Head Block
- Head Block 中的 series 通过内存中的 hash map 快速定位
- 每个时间序列在内存中维护一个 chunk 切片,chunk 使用 XOR 编码压缩浮点数
- 默认每个 chunk 容纳 120 个样本,满后刷入磁盘
WAL(Write-Ahead Log):
- 每个样本写入 Head Block 前先写入 WAL
- WAL 按段(segment)组织,默认每段 128MB
- 崩溃恢复时从 WAL 重放,保证数据不丢失
- 可通过
--storage.tsdb.wal-compression启用 WAL 压缩
Persistent Block(持久化块):
- Head Block 写满一个时间窗口后(默认 2 小时),刷入磁盘成为一个 Persistent Block
- 每个 Block 目录结构:
<block_id>/
├── chunks/ # 压缩后的样本数据
├── index/ # 倒排索引 (series → chunks 映射)
├── meta.json # 元信息 (时间范围、compaction level)
└── tombstones # 删除标记Compaction(压缩合并):
- 将多个较小的 Block 合并为较大的 Block,减少 Block 数量
- 合并同时重建索引,提升查询效率
- Compaction level:L0(2h) → L1(6h) → L2(18h) → L3(54h)...
- 通过
--storage.tsdb.retention.time控制数据保留时长(默认 15 天)
查询路径:
- PromQL 查询时,Engine 同时查询 Head Block(内存)和 Persistent Blocks(磁盘)
- 通过倒排索引快速过滤匹配 label 的 series
- 数据从 chunks 文件读取后解码返回
022. 拉取与推送模型
Pull 模型:核心设计
Prometheus 采用 Pull 模型采集指标,即 Prometheus 主动向目标发起 HTTP GET 请求获取 /metrics 端点的数据。
Pull 模型的优势:
- 服务自省:Prometheus 知道哪些目标健康、哪些不可达(up 指标)
- 简化客户端:被监控服务只需暴露 HTTP 端点,无需知道 Prometheus 的存在
- 避免推送风暴:不会因大量客户端同时推送导致服务端过载
- 调试方便:直接浏览器访问 /metrics 即可查看指标
核心配置参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
scrape_interval |
1m | 采集间隔 |
scrape_timeout |
10s | 单次采集超时 |
metrics_path |
/metrics | 指标端点路径 |
honor_labels |
false | 是否保留抓取数据中已有的 job/instance 标签 |
honor_timestamps |
true | 是否使用目标暴露的时间戳 |
scheme |
http | 协议 (http/https) |
honor_labels 详解:
当 Prometheus 抓取数据时,会自动附加 job 和 instance 标签。如果目标暴露的指标本身也有这些标签,就产生冲突:
honor_labels: false(默认):Prometheus 保留自己的标签,将目标的冲突标签重命名为exported_job、exported_instancehonor_labels: true:保留目标暴露的标签,忽略 Prometheus 附加的标签
典型场景:抓取 Pushgateway 或联邦化时,需要设为 true。
Scrape 生命周期
一次完整的采集过程:
1. Service Discovery 产生目标列表
↓
2. relabel_configs (抓取前重标签)
- 过滤不需要的目标
- 修改 __address__、__metrics_path__ 等元标签
- 添加自定义标签
↓
3. 构造 HTTP 请求
- GET http://<__address__><__metrics_path__>
- 添加 Accept 头协商协议
- 添加认证头 (basic_auth / bearer_token)
↓
4. 发送请求,等待响应 (scrape_timeout)
- 成功:解析 exposition format
- 超时/错误:记录 up=0
↓
5. 解析响应体
- 支持 Prometheus text format 和 OpenMetrics format
- 解析指标名称、标签、值、时间戳
↓
6. metric_relabel_configs (抓取后重标签)
- 过滤不需要的指标
- 修改指标标签
↓
7. 追加到 TSDB (Appender)
- 写入 Head Block + WAL
- 更新 up 指标 (1=成功, 0=失败)每次采集后,Prometheus 会自动生成 up 指标:
up{job="xxx", instance="yyy"} = 1:采集成功up{job="xxx", instance="yyy"} = 0:采集失败
这是 Pull 模型的核心优势之一——通过 up 指标可以精确知道目标是否可达。
Push 模型:Pushgateway
Pushgateway 是 Prometheus 生态中唯一的推送入口,用于短生命周期任务(如 Cron Job、批处理脚本)推送指标。
为什么需要 Pushgateway:
Pull 模型无法监控短生命周期进程——这些进程可能只运行几秒就退出,Prometheus 的采集间隔(通常 1 分钟)可能永远抓不到它。Pushgateway 充当中转站,进程退出前把指标推送给 Pushgateway,Prometheus 再从 Pushgateway 拉取。
API 接口:
# 推送指标(覆盖同名 job+labels 组合)
curl -X POST http://pushgateway:9091/metrics/job/my_job/instance/my_instance \
-d 'my_metric 42'
# 推送指标(合并,不覆盖其他指标)
curl -X PUT http://pushgateway:9091/metrics/job/my_job/instance/my_instance \
-d 'my_metric 42'
# 删除某 job+instance 的所有指标
curl -X DELETE http://pushgateway:9091/metrics/job/my_job/instance/my_instance
# 删除所有指标
curl -X DELETE http://pushgateway:9091/api/v1/metricsPython 推送示例:
from prometheus_client import CollectorRegistry, Gauge, push_to_gateway
registry = CollectorRegistry()
g = Gauge('batch_job_duration_seconds', 'Duration of batch job', registry=registry)
g.set(123.4)
# 推送到 Pushgateway
push_to_gateway('pushgateway:9091', job='batch_process', registry=registry)Go 推送示例:
package main
import (
"log"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/push"
)
func main() {
startTime := time.Now()
// ... 执行批处理任务 ...
duration := prometheus.NewGauge(prometheus.GaugeOpts{
Name: "batch_job_duration_seconds",
Help: "Duration of batch job",
})
duration.Set(time.Since(startTime).Seconds())
if err := push.New("http://pushgateway:9091", "batch_job").
Collector(duration).
Push(); err != nil {
log.Fatal(err)
}
}Pushgateway 的局限性:
- 单点问题:所有推送都经过 Pushgateway,它成为瓶颈和单点故障
- 数据不是实时的:即使推送的进程已退出,Pushgateway 仍保留数据,Prometheus 会持续拉到"过期"数据
- 不适合服务监控:不要把 Pushgateway 当作服务代理,长期运行的服务应该暴露 /metrics 端点让 Prometheus 直接拉取
- up 指标失真:Prometheus 抓取 Pushgateway 成功时 up=1,但无法反映推送源是否还活着
Pushgateway 的 prometheus.yml 配置:
scrape_configs:
- job_name: 'pushgateway'
honor_labels: true # 必须设为 true,保留推送时指定的 job/instance
static_configs:
- targets: ['pushgateway:9091']Remote Write API
Prometheus 支持将采集到的数据远程写入外部存储,实现长期保存:
remote_write:
- url: "http://thanos-receive:19291/api/v1/receive"
queue_config:
max_samples_per_send: 10000
capacity: 20000
max_shards: 100
write_relabel_configs:
- source_labels: [__name__]
regex: 'go_.*'
action: drop # 不发送 Go runtime 指标常见远程存储方案:
| 方案 | 特点 |
|---|---|
| Thanos | 支持长期存储(S3/GCS)、全局查询、高可用 |
| Cortex | 多租户、支持 Cassandra/S3 后端 |
| VictoriaMetrics | 高性能、兼容 Prometheus 协议 |
| Mimir | Grafana Labs 出品,Cortex 分支 |
| Loki | 日志系统,不存储指标但常配合使用 |
Pull vs Push 对比
| 维度 | Pull | Push |
|---|---|---|
| 谁发起 | Prometheus 主动拉取 | 目标主动推送 |
| 健康感知 | 通过 up 指标自动感知目标状态 | 无法自动感知推送源状态 |
| 配置复杂度 | 需要配置目标地址 | 目标自注册 |
| 流量控制 | Prometheus 控制采集频率 | 可能出现推送风暴 |
| 适用场景 | 长期运行的服务 | 短生命周期任务 |
| 调试 | 浏览器直接访问 /metrics | 需要 Pushgateway 中转 |
| 防火墙友好 | 需要 Prometheus 能访问目标 | 需要目标能访问 Pushgateway |
033. 监控指标方法论
Google 四个黄金信号 (Four Golden Signals)
出自 Google SRE Book 第 6 章,是面向用户请求驱动型服务的监控方法论。
1. 延迟 (Latency)
定义:服务处理一个请求所花费的时间。需要区分成功请求和失败请求的延迟——一个返回 500 错误的请求可能延迟极低(因为快速失败了),如果只看平均值会掩盖问题。
Prometheus 指标示例:
# HTTP 请求延迟直方图
http_request_duration_seconds_bucket{handler="/api/users", le="0.1"}
http_request_duration_seconds_sum
http_request_duration_seconds_count
# P99 延迟
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
# 区分成功/失败请求的 P99
histogram_quantile(0.99,
sum by (le, status_code) (
rate(http_request_duration_seconds_bucket{status_code=~"2.."}[5m])
)
)2. 流量 (Traffic)
定义:衡量系统承载的请求量。不同系统有不同的流量衡量方式:HTTP 服务用 QPS,数据库用 TPS,流媒体用带宽。
Prometheus 指标示例:
# 每秒请求量 (QPS)
rate(http_requests_total[5m])
# 按状态码分类的 QPS
sum by (status_code) (rate(http_requests_total[5m]))
# 入站流量 (bytes)
rate(http_request_size_bytes_sum[5m])3. 错误 (Errors)
定义:请求失败的比率。包括显式错误(HTTP 500)和隐式错误(返回了错误内容、响应超时等)。
Prometheus 指标示例:
# 错误率
sum(rate(http_requests_total{status_code=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
# 错误率超过 1% 告警
100 *
sum(rate(http_requests_total{status_code=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m])) > 14. 饱和度 (Saturation)
定义:系统资源的使用程度,反映系统有多"满"。关注的是最受限的资源——当某个资源达到上限时,系统性能会急剧下降。
Prometheus 指标示例:
# CPU 饱和度 (运行队列长度)
node_load1 / on(instance) count(node_cpu_seconds_total{mode="idle"}) by (instance)
# 内存饱和度
1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes
# 磁盘饱和度 (IO 等待)
rate(node_cpu_seconds_total{mode="iowait"}[5m])
# 连接池饱和度
mysql_connections_active / mysql_connections_maxNetflix USE 方法
由 Brendan Gregg(Netflix 性能工程团队)提出,适用于基础设施资源(CPU、内存、磁盘、网络)的监控方法论。
USE = Utilization + Saturation + Errors
- Utilization(利用率):资源忙碌的百分比
- Saturation(饱和度):资源排队/溢出的程度
- Errors(错误):错误事件计数
CPU 资源:
| 指标 | 类型 | Prometheus 指标 |
|---|---|---|
| 利用率 | Utilization | 1 - rate(node_cpu_seconds_total{mode="idle"}[5m]) |
| 饱和度 | Saturation | node_load1 / count(node_cpu_seconds_total{mode="idle"}) by (instance) |
| 错误 | Errors | rate(node_cpu_seconds_total{mode="steal"}[5m])(虚拟化 CPU 偷取) |
内存资源:
| 指标 | 类型 | Prometheus 指标 |
|---|---|---|
| 利用率 | Utilization | 1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes |
| 饱和度 | Saturation | rate(node_vmstat_pgmajfault[5m])(主要页面错误) |
| 错误 | Errors | kube_pod_container_status_terminated_reason{reason="OOMKilled"} |
磁盘资源:
| 指标 | 类型 | Prometheus 指标 |
|---|---|---|
| 利用率 | Utilization | 1 - node_filesystem_avail_bytes / node_filesystem_size_bytes |
| 饱和度 | Saturation | rate(node_disk_io_time_seconds_total[5m]) |
| 错误 | Errors | rate(node_disk_read_errors_total[5m]) |
网络资源:
| 指标 | 类型 | Prometheus 指标 |
|---|---|---|
| 利用率 | Utilization | rate(node_network_transmit_bytes_total{device="eth0"}[5m]) |
| 饱和度 | Saturation | rate(node_netstat_Tcp_RetransSegs[5m])(TCP 重传) |
| 错误 | Errors | rate(node_network_receive_errs_total[5m]) + rate(node_network_transmit_errs_total[5m]) |
RED 方法
由 Tom Wilkie(Prometheus 早期贡献者、Grafana Labs 联合创始人)提出,专门针对请求驱动型的微服务:
RED = Rate + Errors + Duration
- Rate(速率):每秒请求数
- Errors(错误):每秒失败请求数
- Duration(持续时间):请求延迟分布
RED 方法本质上是四个黄金信号的简化版,特别适合构建微服务仪表盘——每个微服务一行,展示 Rate/Errors/Duration 三个指标。
USE vs RED vs 四个黄金信号
| 方法论 | 适用对象 | 关注维度 | 复杂度 |
|---|---|---|---|
| USE | 基础设施资源 (CPU/内存/磁盘/网络) | 利用率/饱和度/错误 | 低 |
| RED | 请求驱动型微服务 | 速率/错误/延迟 | 中 |
| 四个黄金信号 | 用户请求驱动型系统 | 延迟/流量/错误/饱和度 | 高 |
选择建议:
- 监控基础设施(节点、数据库、缓存)→ USE
- 监控微服务 API → RED
- 需要更全面的用户视角 → 四个黄金信号
SLI/SLO/SLA
定义:
- SLI (Service Level Indicator):衡量服务水平的量化指标。例如:"99% 的请求在 200ms 内完成"
- SLO (Service Level Objective):对 SLI 的目标承诺。例如:"P99 延迟 < 200ms"
- SLA (Service Level Agreement):带有商业后果的 SLO 承诺(未达标时的赔偿条款)
用 Prometheus 定义 SLO:
# 告警规则:SLO 违反
groups:
- name: slo-alerts
rules:
- alert: HighErrorRate
expr: |
100 * sum(rate(http_requests_total{status_code=~"5.."}[1h]))
/ sum(rate(http_requests_total[1h])) > 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "错误率超过 SLO (0.1%)"错误预算 (Error Budget):
Error Budget = 1 - SLO 目标
例如 SLO 是 99.9% 可用性,则每月的 Error Budget = 0.1% × 30天 × 86400秒 ≈ 2592 秒 ≈ 43.2 分钟。
# 30 天错误预算消耗率
100 * (
1 -
sum(rate(http_requests_total{status_code!~"5.."}[30d]))
/
sum(rate(http_requests_total[30d]))
)044. 安装部署
二进制安装
Step 1:下载
# 下载最新版(以 v2.53.0 为例)
wget https://github.com/prometheus/prometheus/releases/download/v2.53.0/prometheus-2.53.0.linux-amd64.tar.gz
tar xzf prometheus-2.53.0.linux-amd64.tar.gz
cd prometheus-2.53.0.linux-amd64Step 2:配置 prometheus.yml
global:
scrape_interval: 15s # 默认采集间隔
evaluation_interval: 15s # 默认规则评估间隔
scrape_timeout: 10s # 默认采集超时
# Prometheus 自身监控
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node'
static_configs:
- targets:
- '192.168.1.10:9100'
- '192.168.1.11:9100'
labels:
env: 'production'
# 告警管理器
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
# 告警规则文件
rule_files:
- 'rules/*.yml'Step 3:创建 systemd 服务
# /etc/systemd/system/prometheus.service
[Unit]
Description=Prometheus
After=network.target
[Service]
Type=simple
User=prometheus
Group=prometheus
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/data/prometheus \
--storage.tsdb.retention.time=30d \
--storage.tsdb.wal-compression \
--web.listen-address=0.0.0.0:9090 \
--web.enable-lifecycle \
--web.enable-admin-api \
--log.level=info
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable prometheus
sudo systemctl start prometheusStep 4:验证
# 检查服务状态
curl http://localhost:9090/-/healthy
# 返回 "Prometheus is Healthy."
# 检查是否抓取到自身
curl 'http://localhost:9090/api/v1/query?query=up'常用启动参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
--config.file |
prometheus.yml | 配置文件路径 |
--storage.tsdb.path |
data/ | TSDB 数据目录 |
--storage.tsdb.retention.time |
15d | 数据保留时长 |
--storage.tsdb.retention.size |
0 (无限制) | 数据保留大小上限 |
--storage.tsdb.wal-compression |
false | 启用 WAL 压缩 |
--web.listen-address |
0.0.0.0:9090 | 监听地址 |
--web.enable-lifecycle |
false | 启用 API 热加载 |
--web.enable-admin-api |
false | 启用管理 API |
--web.max-connections |
512 | 最大并发连接 |
--query.max-samples |
50000000 | 单次查询最大样本数 |
--query.timeout |
2m | 查询超时 |
热加载配置:
# 方式一:发送 SIGHUP
kill -HUP <pid>
# 方式二:HTTP API(需要 --web.enable-lifecycle)
curl -X POST http://localhost:9090/-/reloadKubernetes 安装
方式一:直接使用 Manifests
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: monitoring# rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups: [""]
resources:
- nodes
- nodes/metrics
- nodes/proxy
- services
- endpoints
- pods
verbs: ["get", "list", "watch"]
- apiGroups: ["extensions", "networking.k8s.io"]
resources:
- ingresses
verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus
subjects:
- kind: ServiceAccount
name: prometheus
namespace: monitoring# configmap.yaml - Prometheus 配置
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: monitoring
data:
prometheus.yml: |
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'kubernetes-apiservers'
kubernetes_sd_configs:
- role: endpoints
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels:
- __meta_kubernetes_namespace
- __meta_kubernetes_service_name
- __meta_kubernetes_endpoint_port_name
action: keep
regex: default;kubernetes;https
- job_name: 'kubernetes-nodes'
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels:
- __address__
- __meta_kubernetes_pod_annotation_prometheus_io_port
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: prometheus
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: prometheus
template:
metadata:
labels:
app: prometheus
spec:
serviceAccountName: prometheus
containers:
- name: prometheus
image: prom/prometheus:v2.53.0
args:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=30d'
- '--web.enable-lifecycle'
ports:
- containerPort: 9090
volumeMounts:
- name: config
mountPath: /etc/prometheus
- name: data
mountPath: /prometheus
volumes:
- name: config
configMap:
name: prometheus-config
- name: data
persistentVolumeClaim:
claimName: prometheus-data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: prometheus-data
namespace: monitoring
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
---
apiVersion: v1
kind: Service
metadata:
name: prometheus
namespace: monitoring
spec:
type: NodePort
ports:
- port: 9090
targetPort: 9090
nodePort: 30090
selector:
app: prometheus方式二:Helm (kube-prometheus-stack)
# 添加仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 安装
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set prometheus.prometheusSpec.retention=30d \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.storageClassName=local-path \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=50Gi \
--set grafana.adminPassword=admin123方式三:Prometheus Operator (ServiceMonitor)
Prometheus Operator 引入了 ServiceMonitor 和 PodMonitor 两个 CRD,通过声明式方式定义监控目标:
# ServiceMonitor 自动发现匹配的 Service
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app
namespace: monitoring
labels:
release: monitoring
spec:
selector:
matchLabels:
app: my-app
namespaceSelector:
any: true
endpoints:
- port: http
path: /metrics
interval: 15s# 对应的 Service
apiVersion: v1
kind: Service
metadata:
name: my-app
labels:
app: my-app
spec:
ports:
- name: http
port: 8080
targetPort: 8080
selector:
app: my-app055. 服务发现
静态配置 (static_configs)
最简单的服务发现,手动指定目标地址:
scrape_configs:
- job_name: 'my-app'
static_configs:
- targets:
- '10.0.0.1:8080'
- '10.0.0.2:8080'
labels:
env: 'production'
team: 'backend'文件服务发现 (file_sd_configs)
将目标列表放在外部文件中,修改文件后 Prometheus 自动重新加载:
scrape_configs:
- job_name: 'file-sd'
file_sd_configs:
- files:
- '/etc/prometheus/targets/*.json'
- '/etc/prometheus/targets/*.yaml'
refresh_interval: 5mJSON 格式示例:
[
{
"targets": ["10.0.0.1:8080", "10.0.0.2:8080"],
"labels": {
"env": "production",
"team": "backend"
}
}
]Kubernetes 服务发现 (kubernetes_sd_configs)
Kubernetes SD 是云原生场景下最常用的服务发现方式,通过 K8s API 动态发现目标。
认证配置:
集群内运行时,使用 ServiceAccount 自动认证:
kubernetes_sd_configs:
- role: endpoints
# 自动使用 /var/run/secrets/kubernetes.io/serviceaccount/ 下的凭证集群外运行时,需要手动配置:
kubernetes_sd_configs:
- role: endpoints
api_server: https://k8s-api.example.com:6443
tls_config:
ca_file: /etc/prometheus/k8s-ca.crt
bearer_token_file: /etc/prometheus/k8s-token五种 Role 详解:
1. endpoints role(最常用):发现 Service 对应的 Endpoints(Pod IP)
可用元标签:
__meta_kubernetes_namespace:Endpoint 所在命名空间__meta_kubernetes_service_name:对应 Service 名称__meta_kubernetes_endpoint_port_name:端口名称__meta_kubernetes_endpoint_port_protocol:端口协议__meta_kubernetes_pod_name:对应 Pod 名称__meta_kubernetes_pod_label_<labelname>:Pod 标签__meta_kubernetes_pod_annotation_<annotationname>:Pod 注解__meta_kubernetes_pod_container_name:容器名称__meta_kubernetes_pod_node_name:Pod 所在节点
2. pod role:直接发现 Pod,不依赖 Service。适合 Pod 直接暴露指标的场景(如 DaemonSet 部署的 Exporter)。
可用元标签:
__meta_kubernetes_pod_name:Pod 名称__meta_kubernetes_namespace:命名空间__meta_kubernetes_pod_label_<labelname>:Pod 标签__meta_kubernetes_pod_annotation_<annotationname>:Pod 注解__meta_kubernetes_pod_container_name:容器名称__meta_kubernetes_pod_container_port_name:容器端口名__meta_kubernetes_pod_container_port_number:容器端口号__meta_kubernetes_pod_node_name:所在节点__meta_kubernetes_pod_phase:Pod 阶段 (Pending/Running/Succeeded/Failed)__meta_kubernetes_pod_ready:Pod 是否 Ready (true/false)__meta_kubernetes_pod_container_init:是否为 init 容器
3. service role:发现 Service,适合监控服务本身的健康状态。
可用元标签:
__meta_kubernetes_service_name:Service 名称__meta_kubernetes_namespace:命名空间__meta_kubernetes_service_label_<labelname>:Service 标签__meta_kubernetes_service_annotation_<annotationname>:Service 注解__meta_kubernetes_service_port_name:端口名__meta_kubernetes_service_port_protocol:端口协议__meta_kubernetes_service_cluster_ip:ClusterIP__meta_kubernetes_service_type:Service 类型 (ClusterIP/NodePort/LoadBalancer)__meta_kubernetes_service_external_name:ExternalName
4. node role:发现集群节点,适合监控节点级别指标(如 Node Exporter、kubelet)。
可用元标签:
__meta_kubernetes_node_name:节点名称__meta_kubernetes_node_label_<labelname>:节点标签__meta_kubernetes_node_annotation_<annotationname>:节点注解__meta_kubernetes_node_address_<address_type>:节点地址(InternalIP/ExternalIP/Hostname)
5. ingress role:发现 Ingress 资源,适合黑盒探测。
可用元标签:
__meta_kubernetes_ingress_name:Ingress 名称__meta_kubernetes_namespace:命名空间__meta_kubernetes_ingress_label_<labelname>:Ingress 标签__meta_kubernetes_ingress_annotation_<annotationname>:Ingress 注解__meta_kubernetes_ingress_scheme:协议 (http/https)__meta_kubernetes_ingress_path:Ingress 路径__meta_kubernetes_ingress_host:Host
Consul 服务发现
scrape_configs:
- job_name: 'consul-services'
consul_sd_configs:
- server: 'consul.example.com:8500'
token: 'my-token'
datacenter: 'dc1'
services: ['my-service'] # 可选,不指定则发现所有服务
tags: ['production'] # 可选,按标签过滤
refresh_interval: 30sDNS 服务发现
scrape_configs:
- job_name: 'dns-sd'
dns_sd_configs:
- names:
- 'my-service.default.svc.cluster.local'
type: 'A' # A 记录或 SRV 记录
port: 8080 # A 记录需要指定端口
refresh_interval: 30sHTTP 服务发现
scrape_configs:
- job_name: 'http-sd'
http_sd_configs:
- url: 'http://config-server/targets'
refresh_interval: 1m
basic_auth:
username: user
password: passHTTP SD 端点需要返回与 file_sd 相同格式的 JSON。
Relabeling 详解
Relabeling 是 Prometheus 服务发现中最重要的机制,用于在采集前/后对标签进行修改、过滤和增强。
两个处理阶段:
- relabel_configs:在抓取前执行。作用于 Target 级别,可以决定是否采集某个目标、修改目标的地址/路径等
- metric_relabel_configs:在抓取后执行。作用于指标级别,可以过滤掉不需要的指标、修改指标的标签
所有 Action:
| Action | 说明 |
|---|---|
keep |
保留 source_labels 匹配 regex 的 Target/指标 |
drop |
丢弃 source_labels 匹配 regex 的 Target/指标 |
replace |
将 target_label 替换为 replacement(默认动作) |
labelmap |
对所有匹配 regex 的标签名执行 replacement 替换 |
labeldrop |
丢弃标签名匹配 regex 的标签 |
labelkeep |
保留标签名匹配 regex 的标签 |
hashmod |
对 source_labels 的哈希值取模,结果写入 target_label |
关键配置字段:
| 字段 | 说明 |
|---|---|
source_labels |
源标签列表,多个标签用 separator 连接 |
separator |
连接符,默认 ; |
target_label |
目标标签名(replace/hashmod 使用) |
regex |
正则表达式,默认 (.*) |
modulus |
取模数(hashmod 使用) |
replacement |
替换模板,默认 $1 |
action |
动作,默认 replace |
实战示例:
# 示例1:只监控特定 namespace 的 Pod
relabel_configs:
- source_labels: [__meta_kubernetes_namespace]
regex: 'production|staging'
action: keep
# 示例2:从 __address__ 提取主机和端口
relabel_configs:
- source_labels: [__address__]
regex: '([^:]+):(\d+)'
target_label: __host__
- source_labels: [__address__]
regex: '([^:]+):(\d+)'
replacement: '${2}'
target_label: __port__
# 示例3:添加集群标签
relabel_configs:
- target_label: cluster
replacement: prod-east-1
# 示例4:使用 labelmap 将 K8s 标签映射为 Prometheus 标签
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
# 将 __meta_kubernetes_node_label_topology_kubernetes_io_zone
# 映射为 topology_kubernetes_io_zone
# 示例5:过滤不需要的指标(metric_relabel_configs)
metric_relabel_configs:
- source_labels: [__name__]
regex: 'go_[a-z_]+'
action: drop # 丢弃所有 go_ 前缀的指标
- source_labels: [__name__]
regex: 'container_[a-z_]+_seconds_total'
action: drop
# 示例6:hashmod 实现分片采集
relabel_configs:
- source_labels: [__address__]
modulus: 4
target_label: __tmp_hash
action: hashmod
- source_labels: [__tmp_hash]
regex: '^0