前言
上个月公司服务器半夜挂了,第二天早上才发现。老板问:为什么没有监控?
好吧,是时候搞一套监控系统了。
调研了一圈,最终选了 Prometheus + Grafana 这套组合:
- Prometheus:负责采集和存储指标数据
- Grafana:负责可视化展示
- 开源免费,社区活跃
- 云原生标配,K8s原生支持
这篇文章记录完整的搭建过程,包括踩过的坑。
一、架构设计
先看整体架构:
┌─────────────────────────────────────────────────────────────┐ │ 监控系统架构 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 服务器A │ │ 服务器B │ │ 服务器C │ │ │ │ Node │ │ Node │ │ Node │ │ │ │ Exporter │ │ Exporter │ │ Exporter │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ │ │ │ └───────────────┼───────────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────┐ │ │ │ Prometheus │◄─── 拉取指标(Pull模式) │ │ │ (时序数据库) │ │ │ └───────┬────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────┐ │ │ │ Grafana │◄─── 可视化展示 │ │ │ (仪表盘) │ │ │ └───────┬────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────┐ │ │ │ Alertmanager │◄─── 告警推送 │ │ │ (告警管理) │ (邮件/钉钉/企微) │ │ └────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘
yaml
**核心组件:**
| 组件 | 作用 | 端口 |
|------|------|------|
| Prometheus | 指标采集、存储、查询 | 9090 |
| Grafana | 可视化仪表盘 | 3000 |
| Node Exporter | 采集服务器指标(CPU/内存/磁盘) | 9100 |
| Alertmanager | 告警管理和推送 | 9093 |
---
## 二、环境准备
**服务器配置:**
- 监控服务器:2核4GB(跑Prometheus+Grafana)
- 被监控服务器:若干台
**系统环境:**
- Ubuntu 22.04 / CentOS 7+
- Docker 20.10+(推荐用Docker部署)
---
## 三、部署 Prometheus
### 3.1 Docker Compose 部署
创建目录和配置文件:
```bash
mkdir -p /opt/monitoring/{prometheus,grafana,alertmanager}
cd /opt/monitoring
创建 docker-compose.yml:
yaml
version: '3.8'
services:
prometheus:
image: prom/prometheus:v2.47.0
container_name: prometheus
restart: always
ports:
- "9090:9090"
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' # 数据保留30天
- '--web.enable-lifecycle' # 支持热重载
networks:
- monitoring
grafana:
image: grafana/grafana:10.1.0
container_name: grafana
restart: always
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=your_password # 改成你的密码
- GF_USERS_ALLOW_SIGN_UP=false
networks:
- monitoring
alertmanager:
image: prom/alertmanager:v0.26.0
container_name: alertmanager
restart: always
ports:
- "9093:9093"
volumes:
- ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml
networks:
- monitoring
volumes:
prometheus_data:
grafana_data:
networks:
monitoring:
driver: bridge
3.2 配置 Prometheus
创建 prometheus/prometheus.yml:
yaml
global:
scrape_interval: 15s # 采集间隔
evaluation_interval: 15s # 规则评估间隔
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
rule_files:
- /etc/prometheus/rules/*.yml
scrape_configs:
# 监控Prometheus自身
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# 监控服务器(Node Exporter)
- job_name: 'nodes'
static_configs:
- targets:
- '192.168.1.10:9100' # 服务器A
- '192.168.1.11:9100' # 服务器B
- '192.168.1.12:9100' # 服务器C
relabel_configs:
- source_labels: [__address__]
regex: '([^:]+):.*'
target_label: instance
replacement: '${1}'
3.3 配置告警规则
创建 prometheus/rules/node_alerts.yml:
yaml
groups:
- name: node_alerts
rules:
# CPU使用率过高
- alert: HighCpuUsage
expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
annotations:
summary: "CPU使用率过高"
description: "服务器 {{ $labels.instance }} CPU使用率超过80%,当前值:{{ $value | printf \"%.1f\" }}%"
# 内存使用率过高
- alert: HighMemoryUsage
expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "内存使用率过高"
description: "服务器 {{ $labels.instance }} 内存使用率超过85%,当前值:{{ $value | printf \"%.1f\" }}%"
# 磁盘使用率过高
- alert: HighDiskUsage
expr: (1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "磁盘使用率过高"
description: "服务器 {{ $labels.instance }} 磁盘 {{ $labels.mountpoint }} 使用率超过85%"
# 服务器宕机
- alert: InstanceDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "服务器宕机"
description: "服务器 {{ $labels.instance }} 已经宕机超过1分钟"
3.4 配置 Alertmanager(钉钉告警)
创建 alertmanager/alertmanager.yml:
yaml
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'instance']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'dingtalk'
receivers:
- name: 'dingtalk'
webhook_configs:
- url: 'http://dingtalk-webhook:8060/dingtalk/webhook1/send'
send_resolved: true
钉钉Webhook需要单独部署一个转发服务,这里用 prometheus-webhook-dingtalk:
在 docker-compose.yml 中添加:
yaml
dingtalk:
image: timonwong/prometheus-webhook-dingtalk:v2.1.0
container_name: dingtalk-webhook
restart: always
ports:
- "8060:8060"
volumes:
- ./dingtalk/config.yml:/etc/prometheus-webhook-dingtalk/config.yml
networks:
- monitoring
创建 dingtalk/config.yml:
yaml
targets:
webhook1:
url: https://oapi.dingtalk.com/robot/send?access_token=你的钉钉机器人Token
secret: 你的钉钉机器人加签密钥
3.5 启动服务
bash
docker-compose up -d
# 检查状态
docker-compose ps
# 查看日志
docker-compose logs -f prometheus
访问 http://服务器IP:9090 验证Prometheus是否正常。
四、部署 Node Exporter
在每台被监控的服务器上部署 Node Exporter。
4.1 Docker 部署
bash
docker run -d \
--name node_exporter \
--restart always \
--net host \
--pid host \
-v "/:/host:ro,rslave" \
prom/node-exporter:v1.6.1 \
--path.rootfs=/host
4.2 二进制部署(推荐生产环境)
bash
# 下载
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz
# 解压
tar xvf node_exporter-1.6.1.linux-amd64.tar.gz
mv node_exporter-1.6.1.linux-amd64/node_exporter /usr/local/bin/
# 创建systemd服务
cat > /etc/systemd/system/node_exporter.service << 'EOF'
[Unit]
Description=Node Exporter
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/node_exporter
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 启动
systemctl daemon-reload
systemctl enable node_exporter
systemctl start node_exporter
# 验证
curl localhost:9100/metrics
4.3 验证数据采集
回到Prometheus的Web界面:
- 访问
http://Prometheus服务器:9090/targets - 确认所有Node Exporter状态为
UP
如果状态是 DOWN,检查:
- Node Exporter是否启动
- 防火墙是否开放9100端口
- 网络是否连通
五、配置 Grafana 仪表盘
5.1 登录 Grafana
访问 http://服务器IP:3000
- 用户名:admin
- 密码:docker-compose.yml 中设置的密码
5.2 添加数据源
- 左侧菜单 → Configuration → Data Sources
- 点击 "Add data source"
- 选择 "Prometheus"
- URL填写:
http://prometheus:9090(Docker网络内部地址) - 点击 "Save & Test"
5.3 导入仪表盘
不用从零开始做仪表盘,直接导入社区模板:
-
左侧菜单 → Dashboards → Import
-
输入仪表盘ID:
- Node Exporter Full:1860(最全面的服务器监控)
- Docker监控:893
- Prometheus Stats:2
-
选择Prometheus数据源
-
点击Import
导入1860号仪表盘后,你会看到:
- CPU使用率曲线
- 内存使用情况
- 磁盘IO
- 网络流量
- 系统负载
- ...
非常全面,基本不用自己配置。
5.4 自定义仪表盘(进阶)
如果想自定义,了解几个常用的PromQL查询:
CPU使用率:
promql
100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
内存使用率:
promql
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
磁盘使用率:
promql
(1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes) * 100
网络接收流量(MB/s):
promql
irate(node_network_receive_bytes_total{device!~"lo|veth.*"}[5m]) / 1024 / 1024
系统负载:
promql
node_load1 # 1分钟负载
node_load5 # 5分钟负载
node_load15 # 15分钟负载
六、监控更多服务
6.1 监控 MySQL
部署 mysqld_exporter:
bash
docker run -d \
--name mysqld_exporter \
--restart always \
-p 9104:9104 \
-e DATA_SOURCE_NAME="exporter:密码@(mysql服务器:3306)/" \
prom/mysqld-exporter
在Prometheus配置中添加:
yaml
- job_name: 'mysql'
static_configs:
- targets: ['mysqld_exporter:9104']
Grafana仪表盘ID:7362
6.2 监控 Redis
部署 redis_exporter:
bash
docker run -d \
--name redis_exporter \
--restart always \
-p 9121:9121 \
oliver006/redis_exporter \
--redis.addr=redis://Redis服务器:6379
Prometheus配置:
yaml
- job_name: 'redis'
static_configs:
- targets: ['redis_exporter:9121']
Grafana仪表盘ID:763
6.3 监控 Nginx
需要先开启Nginx的stub_status模块:
nginx
server {
listen 8080;
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
部署 nginx-prometheus-exporter:
bash
docker run -d \
--name nginx_exporter \
--restart always \
-p 9113:9113 \
nginx/nginx-prometheus-exporter \
-nginx.scrape-uri=http://Nginx服务器:8080/nginx_status
Grafana仪表盘ID:12708
6.4 监控 Docker 容器
部署 cAdvisor:
bash
docker run -d \
--name cadvisor \
--restart always \
-p 8080:8080 \
-v /:/rootfs:ro \
-v /var/run:/var/run:ro \
-v /sys:/sys:ro \
-v /var/lib/docker/:/var/lib/docker:ro \
gcr.io/cadvisor/cadvisor:v0.47.0
Prometheus配置:
yaml
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
Grafana仪表盘ID:893
七、告警配置实战
7.1 告警触发流程
Prometheus采集指标 → 匹配告警规则 → 触发告警 → 发送到Alertmanager → 推送到钉钉/邮件
7.2 告警规则详解
yaml
- alert: HighCpuUsage
expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m # 持续5分钟才告警,避免瞬时波动误报
labels:
severity: warning # 告警级别
annotations:
summary: "CPU使用率过高"
description: "服务器 {{ $labels.instance }} CPU使用率超过80%"
关键参数:
expr:PromQL表达式,满足条件则触发for:持续时间,防止抖动labels:标签,用于告警分组和路由annotations:告警内容描述
7.3 告警分级路由
在Alertmanager中配置不同级别告警发送到不同渠道:
yaml
route:
receiver: 'default'
routes:
# 严重告警发到运维群
- match:
severity: critical
receiver: 'ops-team'
repeat_interval: 1h
# 警告级别发到开发群
- match:
severity: warning
receiver: 'dev-team'
repeat_interval: 4h
receivers:
- name: 'default'
webhook_configs:
- url: 'http://dingtalk:8060/dingtalk/default/send'
- name: 'ops-team'
webhook_configs:
- url: 'http://dingtalk:8060/dingtalk/ops/send'
- name: 'dev-team'
webhook_configs:
- url: 'http://dingtalk:8060/dingtalk/dev/send'
7.4 告警静默
半夜发版不想收到告警?可以设置静默:
- 访问 Alertmanager:
http://服务器IP:9093 - 点击 "Silences" → "New Silence"
- 设置匹配条件和静默时间
八、远程监控方案
如果你的服务器分布在不同地方(公司、家里、云上),怎么统一监控?
8.1 方案一:公网暴露(不推荐)
把Prometheus的9090端口暴露到公网,不安全。
8.2 方案二:VPN(传统方案)
配置复杂,维护成本高。
8.3 方案三:组网工具(推荐)
我用的是星空组网,把分布在不同地方的服务器组成一个虚拟局域网:
- 每台服务器装星空组网客户端
- 登录同一账号,加入同一网络
- 服务器互相之间可以用虚拟IP访问
配置Prometheus监控远程服务器:
yaml
scrape_configs:
- job_name: 'nodes'
static_configs:
- targets:
- '10.26.1.10:9100' # 公司服务器(虚拟IP)
- '10.26.1.20:9100' # 家里NAS(虚拟IP)
- '10.26.1.30:9100' # 云服务器(虚拟IP)
优势:
- 不用暴露端口到公网
- 配置简单,5分钟搞定
- P2P直连,延迟低
- 免费版3设备够个人用
这样在家也能看到公司服务器的监控数据,出差时也能随时查看。
九、性能优化
9.1 Prometheus 存储优化
默认配置下,Prometheus会把所有数据存本地。数据量大了会有问题。
优化参数:
yaml
# docker-compose.yml 的 command 部分
command:
- '--storage.tsdb.retention.time=15d' # 减少保留时间
- '--storage.tsdb.retention.size=10GB' # 限制存储大小
- '--storage.tsdb.wal-compression' # 开启WAL压缩
9.2 采集频率优化
不是所有指标都需要15秒采集一次:
yaml
scrape_configs:
# 核心服务,15秒采集
- job_name: 'critical-nodes'
scrape_interval: 15s
static_configs:
- targets: ['核心服务器:9100']
# 非核心服务,1分钟采集
- job_name: 'normal-nodes'
scrape_interval: 60s
static_configs:
- targets: ['普通服务器:9100']
9.3 Grafana 查询优化
仪表盘卡顿?可能是查询太重:
- 减少时间范围(从7天改成1天)
- 增加查询步长(Step)
- 使用
rate()代替irate()(更平滑,计算量小)
十、踩过的坑
坑1:时间不同步导致数据断层
现象: Grafana图表有断层,Prometheus显示"target is 5m in the future"
原因: 被监控服务器时间比Prometheus快了5分钟
解决: 所有服务器配置NTP同步
bash
# Ubuntu
apt install chrony
systemctl enable chrony
# 强制同步
chronyc makestep
坑2:Docker网络内访问不通
现象: Prometheus采集不到容器内的Exporter
原因: 网络模式问题
解决: 确保所有容器在同一个Docker网络(monitoring)
坑3:Grafana仪表盘不显示数据
现象: 导入仪表盘后一片空白
原因: 数据源名称不匹配
解决: 仪表盘设置里把数据源改成你创建的名称
坑4:磁盘监控指标为空
现象: node_filesystem_* 指标没有数据
原因: Node Exporter没有挂载宿主机文件系统
解决: 用 --path.rootfs=/host 参数并挂载 /:/host:ro
十一、生产环境 Checklist
部署到生产环境前,检查这些:
- Prometheus数据持久化到宿主机目录
- Grafana密码已修改
- 告警规则配置完成
- 告警通知渠道已测试
- 所有服务器时间已同步
- 监控系统本身也在被监控
- 定期备份Grafana配置
- 防火墙只开放必要端口
十二、总结
Prometheus + Grafana 这套组合,基本是现在监控的事实标准。
核心要点:
- 架构:Prometheus采集 + Grafana展示 + Alertmanager告警
- 部署:推荐Docker Compose,方便管理
- 仪表盘:直接导入社区模板,省时省力
- 告警:规则要合理,避免告警风暴
- 远程监控:用组网工具打通不同地点的服务器
下一步可以做的:
- 接入更多服务监控(MySQL、Redis、应用指标)
- 配置更完善的告警规则
- 搭建高可用集群(Thanos/Cortex)
有问题评论区讨论,我尽量回复。
参考资料:
- Prometheus官方文档:prometheus.io/docs/
- Grafana官方文档:grafana.com/docs/
- Node Exporter GitHub:github.com/prometheus/...