Prometheus + Grafana 服务器监控栈实战指南

Prometheus + Grafana 服务器监控栈实战指南

一、引言

服务器监控是运维体系的”眼睛”。没有监控,你就像在黑暗中驾驶——直到用户报故障才知道系统出了问题。2026 年,Prometheus + Grafana 组合已成为开源监控领域的事实标准,被从个人 Homelab 到大型企业的广泛采用。

本文从零开始,搭建一套完整的监控栈:Prometheus 负责指标采集与存储,Grafana 负责可视化与告警,Node Exporter 负责主机指标暴露。所有组件通过 Docker Compose 一键部署,适合单台服务器到中小规模集群。


二、架构概览

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
┌─────────────────────────────────────────────────┐
│ Grafana │
│ 仪表盘 · 告警规则 · 数据源配置 │
└────────────┬───────────────────────┬────────────┘
│ HTTP :3000 │ HTTP :9090
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐
│ Prometheus │ │ Alertmanager │
│ 指标存储 · 查询 │ │ 告警路由 · 通知 │
│ :9090 │ │ :9093 │
└────┬──────┬──────┬────┘ └──────────────────────┘
│ │ │
▼ ▼ ▼
┌──────┐┌──────┐┌──────┐
│Node ││Node ││... │ Node Exporter 采集主机指标
│Exp. ││Exp. ││ │ (CPU/内存/磁盘/网络)
└──────┘└──────┘└──────┘

三、前置要求

  • Linux 服务器(本文基于 Ubuntu 22.04/24.04)
  • 已安装 Docker 和 Docker Compose(v2+)
  • 基本的命令行操作能力
  • 了解端口、HTTP 协议等基本概念

四、Docker Compose 部署监控栈

4.1 目录结构

1
2
mkdir -p /opt/monitoring/{prometheus,grafana,alertmanager}
cd /opt/monitoring

4.2 docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
version: "3.8"

networks:
monitoring:
driver: bridge

volumes:
prometheus_data:
grafana_data:

services:
prometheus:
image: prom/prometheus:v2.53.0
container_name: prometheus
restart: always
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- ./prometheus/rules:/etc/prometheus/rules
- prometheus_data:/prometheus
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--storage.tsdb.retention.time=30d"
- "--web.console.libraries=/etc/prometheus/console_libraries"
- "--web.console.templates=/etc/prometheus/consoles"
- "--web.enable-lifecycle"
ports:
- "9090:9090"
networks:
- monitoring

grafana:
image: grafana/grafana:11.1.0
container_name: grafana
restart: always
volumes:
- ./grafana/datasources:/etc/grafana/provisioning/datasources
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin123
- GF_INSTALL_PLUGINS=
- GF_SERVER_ROOT_URL=http://your-server-ip:3000
ports:
- "3000:3000"
networks:
- monitoring
depends_on:
- prometheus

alertmanager:
image: prom/alertmanager:v0.27.0
container_name: alertmanager
restart: always
volumes:
- ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml
ports:
- "9093:9093"
networks:
- monitoring

node_exporter:
image: prom/node-exporter:v1.8.0
container_name: node_exporter
restart: always
command:
- "--path.rootfs=/host"
- "--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)"
pid: host
volumes:
- /:/host:ro,rslave
ports:
- "9100:9100"
networks:
- monitoring

⚠️ 安全提示:生产环境请修改 GF_SECURITY_ADMIN_PASSWORD,并使用环境变量文件(.env)管理敏感信息。

4.3 Prometheus 配置

prometheus/prometheus.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_timeout: 10s

alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093

rule_files:
- "rules/*.yml"

scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]

- job_name: "node"
static_configs:
- targets:
- "node_exporter:9100"
relabel_configs:
- source_labels: [__address__]
regex: "(.*):9100"
target_label: instance
replacement: "server-01"

# 添加更多 Node Exporter 目标
# - job_name: "node-server-02"
# static_configs:
# - targets: ["192.168.1.101:9100"]

4.4 告警规则

prometheus/rules/node_alerts.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
groups:
- name: node_alerts
interval: 30s
rules:
- alert: HighCpuUsage
expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} CPU 使用率过高"
description: "CPU 使用率已超过 80%(当前值:{{ $value }}%)"

- alert: HighMemoryUsage
expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} 内存使用率过高"
description: "内存使用率已超过 85%(当前值:{{ $value }}%)"

- alert: DiskSpaceLow
expr: (node_filesystem_avail_bytes{mountpoint="/",fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{mountpoint="/",fstype!~"tmpfs|overlay"}) * 100 < 10
for: 5m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} 磁盘空间不足"
description: "磁盘可用空间低于 10%(当前值:{{ $value | humanizePercentage }})"

- alert: NodeDown
expr: up{job="node"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} 已离线"
description: "节点 {{ $labels.instance }} 已离线超过 1 分钟"

- alert: HighDiskIO
expr: rate(node_disk_io_time_seconds_total[5m]) > 0.5
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} 磁盘 IO 过高"
description: "磁盘 IO 时间占比超过 50%(当前值:{{ $value | humanizePercentage }})"

4.5 Alertmanager 配置

alertmanager/alertmanager.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
global:
resolve_timeout: 5m
smtp_smarthost: "smtp.example.com:587"
smtp_from: "alert@example.com"
smtp_auth_username: "alert@example.com"
smtp_auth_password: "your-password"

route:
receiver: "default"
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- match:
severity: critical
receiver: "critical"
repeat_interval: 1h

receivers:
- name: "default"
email_configs:
- to: "admin@example.com"

- name: "critical"
email_configs:
- to: "oncall@example.com"
webhook_configs:
- url: "https://hooks.example.com/alert"

4.6 Grafana 自动配置数据源

grafana/datasources/datasource.yml

1
2
3
4
5
6
7
8
9
apiVersion: 1

datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: false

4.7 启动监控栈

1
2
3
4
5
6
7
8
cd /opt/monitoring
docker compose up -d

# 验证所有服务正常运行
docker compose ps

# 查看日志
docker compose logs -f

验证各组件:

1
2
3
4
5
6
7
8
9
10
11
# Prometheus Web UI
curl http://localhost:9090/targets

# Node Exporter 指标
curl http://localhost:9100/metrics | head -20

# Grafana
curl -I http://localhost:3000

# Alertmanager
curl http://localhost:9093/#/alerts

五、Grafana 仪表盘配置

5.1 导入官方仪表盘

Grafana 启动后,访问 http://your-server-ip:3000,使用 admin / admin123 登录。

推荐导入的 Node Exporter 仪表盘:

仪表盘 ID 名称 说明
1860 Node Exporter Full 最全面的主机监控仪表盘
11074 Node Exporter Server Metrics 轻量级主机监控
16098 1 Node Exporter for Prometheus Dashboard 现代化设计

导入方法:

  1. 左侧菜单 → Dashboards → New → Import
  2. 输入 Dashboard ID → Load
  3. 选择 Prometheus 数据源 → Import

5.2 自动预配仪表盘(进阶)

grafana/dashboards/node_exporter.json 可以从 Grafana Dashboards 下载 JSON 文件后放入此目录,Grafana 启动时会自动加载。


六、关键指标解读

6.1 CPU 指标

1
2
3
4
5
6
7
8
# CPU 使用率(排除 idle)
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# 按 CPU 核心查看使用率
100 - (avg by(instance, cpu) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# CPU 负载(1/5/15 分钟)
node_load1 / node_load5 / node_load15

6.2 内存指标

1
2
3
4
5
6
7
8
# 内存使用率
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

# 实际使用内存(不含缓存/缓冲区)
node_memory_MemTotal_bytes - node_memory_MemFree_bytes - node_memory_Buffers_bytes - node_memory_Cached_bytes

# Swap 使用率
(node_memory_SwapTotal_bytes - node_memory_SwapFree_bytes) / node_memory_SwapTotal_bytes * 100

6.3 磁盘指标

1
2
3
4
5
6
7
8
9
# 磁盘使用率(按挂载点)
(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) / node_filesystem_size_bytes{mountpoint="/"} * 100

# 磁盘 IO 读写速率
rate(node_disk_read_bytes_total[5m])
rate(node_disk_written_bytes_total[5m])

# 磁盘 IO 等待时间
rate(node_disk_io_time_seconds_total[5m])

6.4 网络指标

1
2
3
4
5
6
7
8
# 网络入站流量
rate(node_network_receive_bytes_total{device!="lo"}[5m])

# 网络出站流量
rate(node_network_transmit_bytes_total{device!="lo"}[5m])

# TCP 连接数
node_netstat_Tcp_CurrEstab

七、告警通知配置

7.1 邮件通知

alertmanager.yml 中配置 SMTP 后,重启 Alertmanager:

1
docker compose restart alertmanager

7.2 Webhook 通知(企业微信/钉钉/Slack)

1
2
3
4
5
6
# alertmanager.yml 中的 webhook 配置
receivers:
- name: "wechat"
webhook_configs:
- url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
send_resolved: true

7.3 Grafana 内置告警(替代方案)

Grafana 11.x 内置了告警引擎,可以直接在 UI 中配置告警规则:

  1. 左侧菜单 → Alerting → Alert rules → New alert rule
  2. 选择 Prometheus 数据源,编写 PromQL 查询
  3. 设置评估间隔和条件阈值
  4. 配置通知渠道(邮件、Webhook、Telegram 等)

八、生产环境最佳实践

8.1 安全加固

1
2
3
4
5
6
7
# 为 Prometheus 启用基础认证
# 生成密码哈希
# htpasswd -nBC 10 "" | tr -d ':\n'

# prometheus/web.yml
basic_auth_users:
admin: $2y$10$... # bcrypt hash
1
2
3
4
5
# 在 docker-compose.yml 中挂载认证配置
volumes:
- ./prometheus/web.yml:/etc/prometheus/web.yml
command:
- "--web.config.file=/etc/prometheus/web.yml"

8.2 数据保留策略

1
2
3
4
# Prometheus 数据保留
command:
- "--storage.tsdb.retention.time=30d" # 保留 30 天
- "--storage.tsdb.retention.size=50GB" # 或限制最大 50GB

8.3 资源限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# docker-compose.yml 中添加资源限制
services:
prometheus:
deploy:
resources:
limits:
memory: 2G
cpus: "1.0"
grafana:
deploy:
resources:
limits:
memory: 512M
cpus: "0.5"

8.4 备份策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
# /opt/monitoring/backup.sh
BACKUP_DIR="/backup/monitoring"
DATE=$(date +%Y%m%d)

# 备份 Prometheus 数据
docker run --rm -v prometheus_data:/data -v $BACKUP_DIR:/backup alpine \
tar czf /backup/prometheus-$DATE.tar.gz -C /data .

# 备份 Grafana 数据
docker run --rm -v grafana_data:/data -v $BACKUP_DIR:/backup alpine \
tar czf /backup/grafana-$DATE.tar.gz -C /data .

# 保留最近 30 天
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete

九、常见问题

Q1:Prometheus 启动后 target 显示 DOWN

原因:通常是网络不通或端口未暴露。

排查

1
2
3
4
5
6
7
8
# 检查容器是否运行
docker compose ps

# 从 Prometheus 容器内测试连通性
docker exec prometheus wget -qO- http://node_exporter:9100/metrics

# 检查防火墙
sudo ufw status

Q2:Grafana 无法连接 Prometheus 数据源

原因:Grafana 容器内使用 http://prometheus:9090 而非 localhost:9090

解决:确认 datasource.yml 中的 URL 使用 Docker 服务名 http://prometheus:9090

Q3:磁盘空间被 Prometheus 数据占满

原因:默认无数据保留限制。

解决:设置 --storage.tsdb.retention.time=15d--storage.tsdb.retention.size=20GB

Q4:告警没有触发

原因:告警规则文件未正确加载。

排查

1
2
3
4
5
# 检查 Prometheus 是否加载了规则文件
curl http://localhost:9090/api/v1/rules

# 检查 Alertmanager 状态
curl http://localhost:9093/api/v2/status

Q5:Node Exporter 指标不完整

原因:容器内无法访问宿主机文件系统。

解决:确保挂载了 pid: host 和卷 /:host:ro,rslave

Q6:如何监控多台服务器?

方案:在每台服务器上运行 Node Exporter(Docker 或直接安装),然后在 Prometheus 配置中添加 target:

1
2
3
4
5
6
7
scrape_configs:
- job_name: "node"
static_configs:
- targets:
- "192.168.1.10:9100" # 服务器 A
- "192.168.1.11:9100" # 服务器 B
- "192.168.1.12:9100" # 服务器 C

十、总结

通过本文,你已搭建了一套完整的 Prometheus + Grafana 监控栈:

组件 端口 用途
Prometheus 9090 指标采集与存储
Grafana 3000 可视化仪表盘
Alertmanager 9093 告警路由与通知
Node Exporter 9100 主机指标暴露

这套方案的优势在于:Docker Compose 一键部署、组件解耦可独立扩展、告警规则可编程、仪表盘可共享。对于中小规模基础设施,它已经足够胜任生产环境监控需求。


参考资源