为什么是 Prometheus + Grafana
K8s 时代之前,监控选型百花齐放(Zabbix / Nagios / Cacti / InfluxDB+Telegraf...)。Prometheus 出现后把这件事重新定义了一遍 —— Pull 模型 + 多维度 label + PromQL,几乎成了 Cloud Native 监控的事实标准。Grafana 则是它最佳搭档,只负责一件事:把数据画好看。
Prometheus 的核心理念
- Pull 模型(server 主动抓 target 的
/metrics) - 多维度 label 数据模型
- PromQL 查询语言
- 自带 TSDB(单机 1.5 亿样本/s)
- 服务发现(K8s / Consul / DNS / 静态)
Grafana 的核心理念
- 数据源无关(Prom / Loki / InfluxDB / MySQL / ...)
- 强大的面板编辑器 + transform
- Dashboard as Code(JSON / Provisioning)
- 内建告警引擎(Unified Alerting)
- 多用户 / Org / Folder 权限
两者的边界很清晰:Prometheus 负责采集 + 存储 + 计算,Grafana 负责展现 + 告警 UI。
整体架构
[Exporters] ── scrape ──▶ [Prometheus] ──▶ [Grafana] ──▶ 浏览器
│
▼
[Alertmanager] ──▶ 告警通道(钉钉/邮件/PagerDuty)最小生产级部署需要 4 类组件:
组件分工
- 01Prometheus —— 时序库 + 抓取调度器 + 规则引擎
- 02Alertmanager —— 告警去重 / 分组 / 路由 / 静默 / 抑制
- 03Grafana —— 可视化 + 用户系统 + 告警 UI(也内置告警引擎,但通常只用前者)
- 04若干 Exporter —— 把目标系统的指标转成 Prometheus 格式(Node / MySQL / Redis / Blackbox / ...)
准备工作
前置要求
- Linux 主机一台(建议 4C8G 起步,Prometheus 内存随 series 数量线性增长)
- Docker 24.x + Docker Compose v2
- ≥ 100 GB 数据盘(监控数据 retention 默认 15 天)
- 公网域名(强烈建议,便于配 TLS)
- 80 / 443 端口空闲
下面以一台 Ubuntu 22.04 LTS 为例,所有组件跑在 Docker 里。
一、目录结构
mkdir -p /opt/monitoring/{prometheus/config,prometheus/rules,alertmanager/config,grafana/provisioning,grafana/dashboards,data/prometheus,data/grafana,data/alertmanager}
cd /opt/monitoring
# 数据目录权限 —— 容器里跑的 uid 各不相同
sudo chown -R 65534:65534 data/prometheus # nobody:nogroup
sudo chown -R 472:472 data/grafana # grafana
sudo chown -R 65534:65534 data/alertmanager二、Prometheus 配置
prometheus/config/prometheus.yml:
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
cluster: prod
replica: 0
rule_files:
- /etc/prometheus/rules/*.rules.yml
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
scrape_configs:
# Prometheus 自监控
- job_name: prometheus
static_configs:
- targets: ['localhost:9090']
# 主机指标
- job_name: node
static_configs:
- targets: ['node-exporter:9100']
# 黑盒探测(HTTP 健康检查)
- job_name: blackbox-http
metrics_path: /probe
params:
module: [http_2xx]
static_configs:
- targets:
- https://yantao.wiki
- https://example.com/healthz
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: blackbox-exporter:9115需要更长期可加 为什么 retention 默认是 15 天?
Prometheus 的设计定位是 短期热存储,长期保留靠 remote_write 转到 Mimir / Thanos / VictoriaMetrics。15 天的默认值平衡了:--storage.tsdb.retention.time=90d,但同时要扩磁盘并接受重启变慢的代价。
三、告警规则
prometheus/rules/node.rules.yml:
groups:
- name: node
rules:
- alert: NodeDown
expr: up{job="node"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "节点 {{ $labels.instance }} 失联超过 2 分钟"
description: "Prometheus 抓取 {{ $labels.job }}/{{ $labels.instance }} 失败"
- alert: HighCPU
expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
for: 10m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} CPU 持续超过 85%"
- alert: DiskFull
expr: |
(node_filesystem_avail_bytes{mountpoint="/"}
/ node_filesystem_size_bytes{mountpoint="/"}) * 100 < 10
for: 5m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} 根分区剩余 < 10%"for: 字段非常重要 —— 它决定了「连续异常多久才真正 firing」。设得太短会被毛刺打爆 oncall 群,设得太长又延迟响应。一般规律:metric 异常时延 < for < 业务可容忍的延迟。四、Alertmanager 配置
alertmanager/config/alertmanager.yml:
global:
resolve_timeout: 5m
route:
receiver: default
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- matchers:
- severity = critical
receiver: critical-pager
continue: true # 让 critical 也走 default 一份(双通道)
receivers:
- name: default
webhook_configs:
- url: https://oapi.dingtalk.com/robot/send?access_token=YOUR_DD_TOKEN
- name: critical-pager
webhook_configs:
- url: https://oapi.dingtalk.com/robot/send?access_token=YOUR_DD_TOKEN
email_configs:
- to: oncall@example.com
smarthost: smtp.example.com:587
auth_username: alert@example.com
auth_password: '<smtp-pass>'
from: alert@example.com
require_tls: true钉钉 / 飞书 / Slack 都用 webhook 接入,但 Alertmanager 默认 payload 格式不是它们的。中间通常加一个转换器,常用的是 prometheus-webhook-dingtalk。
五、Grafana 数据源 & 仪表盘自动导入
Grafana 推荐用 provisioning 把数据源和仪表盘做成代码,避免点点点。
grafana/provisioning/datasources/prometheus.yml:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
jsonData:
timeInterval: 15s
httpMethod: POSTgrafana/provisioning/dashboards/default.yml:
apiVersion: 1
providers:
- name: default
folder: ''
type: file
options:
path: /var/lib/grafana/dashboards把社区精品仪表盘的 JSON 下载到 grafana/dashboards/:
| Dashboard | ID | 来源 |
|---|---|---|
| Node Exporter Full | 1860 | rfmoz |
| Prometheus Stats | 2 | grafana |
| Blackbox Exporter | 7587 | grafana |
Grafana 启动时会自动加载,重启容器即生效。
六、Docker Compose 编排
docker-compose.yml:
version: '3.8'
services:
prometheus:
image: prom/prometheus:v2.55.0
container_name: prometheus
restart: unless-stopped
user: '65534:65534'
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --storage.tsdb.retention.time=15d
- --web.enable-lifecycle # POST /-/reload 热加载
- --web.external-url=https://prom.yantao.wiki
volumes:
- ./prometheus/config:/etc/prometheus
- ./prometheus/rules:/etc/prometheus/rules
- ./data/prometheus:/prometheus
networks: [monitoring]
alertmanager:
image: prom/alertmanager:v0.27.0
container_name: alertmanager
restart: unless-stopped
user: '65534:65534'
command:
- --config.file=/etc/alertmanager/alertmanager.yml
- --storage.path=/alertmanager
- --web.external-url=https://am.yantao.wiki
volumes:
- ./alertmanager/config:/etc/alertmanager
- ./data/alertmanager:/alertmanager
networks: [monitoring]
grafana:
image: grafana/grafana:11.3.0
container_name: grafana
restart: unless-stopped
user: '472:472'
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=changeme-now
- GF_SERVER_ROOT_URL=https://grafana.yantao.wiki
- GF_AUTH_ANONYMOUS_ENABLED=false
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- ./grafana/provisioning:/etc/grafana/provisioning
- ./grafana/dashboards:/var/lib/grafana/dashboards
- ./data/grafana:/var/lib/grafana
networks: [monitoring]
node-exporter:
image: prom/node-exporter:v1.8.2
container_name: node-exporter
restart: unless-stopped
pid: host
network_mode: host
volumes:
- /:/host:ro,rslave
command:
- --path.rootfs=/host
- --collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($|/)
blackbox-exporter:
image: prom/blackbox-exporter:v0.25.0
container_name: blackbox-exporter
restart: unless-stopped
networks: [monitoring]
networks:
monitoring:
name: monitoring启动:
docker compose up -d
docker compose ps七、首次访问验证
- 访问
http://<host>:9090 - 顶部菜单 Status → Targets:所有 endpoint 应显示
UP - Status → Configuration:检查解析后的最终配置
- Graph 面板执行
up:应该看到所有 target 的状态 - 执行
rate(prometheus_tsdb_head_samples_appended_total[5m]):当前的样本写入速率
http://<host>:9093ready临时发个 test alert 验证通道:
curl -XPOST http://localhost:9093/api/v2/alerts -H 'Content-Type: application/json' \
-d '[{"labels":{"alertname":"TestAlert","severity":"critical"},"annotations":{"summary":"测试"}}]'- 访问
http://<host>:3000,admin / 你设的密码 - Connections → Data sources → 点 Prometheus → Save & test:绿色 OK
- Dashboards 自动看到 provisioning 的几张图
- 任意面板检查曲线是否在画
八、生产化清单
部署能跑只是第一步,下面是上生产前必补的 6 层:
生产级补丁层(按优先级)
- L1TLS + 反代 —— Caddy / Nginx 给三个 UI 都套上 HTTPS。Caddy 自动 Let's Encrypt 最省心。Prometheus / Alertmanager 的
--web.external-url必须设对,否则 redirect / link 会回到 localhost。 - L2鉴权 —— Prometheus / Alertmanager 默认裸奔,对外必须加 basic auth(在反代层配);Grafana 内置用户系统就够用,记得关掉
GF_AUTH_ANONYMOUS_ENABLED和GF_USERS_ALLOW_SIGN_UP。 - L3数据持久化 ——
./data子目录映射做对就行。生产建议挂独立云盘,定期 snapshot;Prometheus 的/prometheus/snapshotsAPI 可以触发热备。 - L4长期存储 —— 单机 Prometheus 撑 1-2 个月数据,超出走
remote_write到 VictoriaMetrics / Mimir / Thanos。VM 单机性能比原生 Prom 高 10x,迁移成本低。 - L5HA —— Prometheus 双副本(同 config,不同
external_labels.replica)→ Alertmanager 集群(gossip 协议)→ 任意一台挂了告警不丢、查询走 Thanos Querier 自动去重。 - L6备份 —— Grafana 仪表盘走 provisioning + git;Prometheus 数据 snapshot via API;Alertmanager silence 也是状态,值得备份。
九、常见踩坑
踩坑 1 :Targets 显示 DOWN 但目标服务正常
90% 是 Docker 网络问题。先验证容器间能不能 talk:
docker exec prometheus wget -qO- http://node-exporter:9100/metrics | head如果 node-exporter 用了 network_mode: host,Prometheus 容器要用 宿主机的 docker0 IP(在 Linux 上通常是 172.17.0.1),不是 host.docker.internal(那个只在 Docker Desktop 上有)。
踩坑 2 :Grafana 提示
data source proxy: dial tcp ... connection refused数据源 URL 用了 http://localhost:9090 —— Grafana 容器里的 localhost 不是宿主机!必须用 docker compose 的 service name:
url: http://prometheus:9090 # ✅
url: http://localhost:9090 # ❌ 在容器里指向自己
url: http://127.0.0.1:9090 # ❌ 同上并且两个容器要在同一个 networks 下。
踩坑 3 :Alertmanager 告警没发出
按下面的顺序排查,一般卡在第 4 步:
- Prometheus → Status → Targets:
up{job="alertmanager"} == 1吗? - Prometheus → Alerts:规则在 firing 吗?
- Alertmanager → Alerts:告警传到了吗?
- Alertmanager → Status → Config:route 匹配到了吗?常见问题是 matcher 写错(用了
severity == "critical"而不是severity = critical) - Alertmanager 容器 log:webhook 调用是否 200?
踩坑 4 :内存爆涨 / OOM
Prometheus 内存随 active series 数量线性增长,估算公式:
内存(GB) ≈ active_series × 3.5 KB / 1024 / 1024百万 series 大约吃 3.5 GB heap。如果你的 metrics 里有高基数 label(比如把 user_id / request_id 当 label),会迅速爆掉。
排查:topk(20, count by(__name__)({__name__=~".+"})) 看哪个 metric 占了最多 series。
十、写在最后
下一步可以扩展的方向:
- Loki + Promtail —— 日志聚合,和 metrics 在 Grafana 里跨源关联
- Tempo —— 分布式追踪,OpenTelemetry-native
- Pyroscope —— 持续性能剖析(Continuous Profiling)
- Mimir / Thanos —— 多租户 + 长期存储
完整 LGTM Stack(Loki + Grafana + Tempo + Mimir)把 Logs / Metrics / Traces / Profiles 全部串起来,下一篇细讲。
还没有评论
欢迎留下你的观点,保持交流的清晰和友好。
写下评论