VPS 监控搭建实战:Prometheus + node_exporter + Grafana 从零部署到告警通知
一、为什么要自建监控:云厂商监控的三个短板
很多 VPS 用户依赖云厂商控制台自带的监控面板,但遇到实际问题时往往不够用:
- 指标粒度粗:控制台只有 CPU、内存、带宽几个大项,磁盘 IOPS、TCP 连接数、inode 使用率、进程级指标统统没有;
- 历史数据短:免费版通常只保留几天到一个月,出了故障想回溯三个月前的数据曲线,查不到;
- 告警能力弱:控制台告警要么收费、要么只能发站内信,做不到自定义阈值、分组、静默、对接钉钉/企业微信。
自建一套 Prometheus + Grafana 监控只需要 200MB 左右内存,却能把以上三个短板全部补齐。本文以 Debian/Ubuntu 系的 VPS 为例,CentOS 系只需把 apt 换成 yum、systemd 写法保持一致即可。
二、架构总览:四个组件各管一件事
整套体系由四个组件组成,职责非常清晰:
- node_exporter:装在每一台被监控的服务器上,负责采集系统指标(CPU/内存/磁盘/网络等),通过 HTTP 暴露给 Prometheus;
- Prometheus:监控中心,按固定间隔(默认 15s)主动拉取各 exporter 的数据,存入本地时序数据库 TSDB,并执行告警规则;
- Grafana:可视化面板,从 Prometheus 查询数据画图,支持丰富的图表和仪表盘;
- Alertmanager:告警统一出口,负责把 Prometheus 推来的告警做分组、去重、抑制,再转发到钉钉/企业微信/邮件。
+-------------+ scrape (15s) +------------------+ query +----------+
| node_exporter| -------------> | Prometheus | <------ | Grafana |
| :9100 | | :9090 | | :3000 |
+-------------+ +------------------+ +----------+
| alert rule
v
+------------------+ webhook +-----------+
| Alertmanager | ----------> | 钉钉/企微 |
| :9093 | +-----------+
+------------------+
如果是单台 VPS 自用,Prometheus、Grafana、node_exporter 装在同一台机器上即可;如果有多台服务器,node_exporter 装在各业务机上,Prometheus 只装在其中一台。
三、第一步:安装并配置 node_exporter
node_exporter 官方只发布二进制压缩包,用下面的命令下载最新稳定版(以 1.8.2 为例,实际版本号可去 GitHub releases 查询):
cd /tmp wget https://github.com/prometheus/node_exporter/releases/download/v1.8.2/node_exporter-1.8.2.linux-amd64.tar.gz tar xzf node_exporter-1.8.2.linux-amd64.tar.gz sudo mv node_exporter-1.8.2.linux-amd64/node_exporter /usr/local/bin/ sudo useradd -r -s /usr/sbin/nologin node_exporter sudo mkdir -p /etc/node_exporter
创建一个 systemd 服务文件,让它在开机时自动拉起:
sudo tee /etc/systemd/system/node_exporter.service > /dev/null <<'EOF'
[Unit]
Description=Prometheus Node Exporter
After=network.target
[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter \
--web.listen-address=:9100 \
--web.config-file=/etc/node_exporter/web.yml \
--collector.filesystem.mount-points-exclude='^/(sys|proc|dev|run)($|/)'
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
注意这里指定了 --collector.filesystem.mount-points-exclude,把虚拟文件系统排除掉,否则 Grafana 磁盘面板里会多出一堆 /proc、/sys 之类的无效挂载点。默认的采集器全集里,可以只保留常用的:
sudo tee /etc/node_exporter/web.yml > /dev/null <<'EOF' basic_auth_users: prometheus: $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx EOF
上面的密码是 bcrypt 哈希,可以用 Python 或 htpasswd 生成(见第五节安全加固)。先启动并验证:
sudo systemctl daemon-reload sudo systemctl enable --now node_exporter curl -s http://127.0.0.1:9100/metrics | head -20
如果能看到 node_cpu_seconds_total、node_memory_MemTotal_bytes 等指标,说明采集正常。先用 curl 自测,不要急着开放端口。
四、第二步:安装配置 Prometheus
同样下载二进制包安装:
cd /tmp
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
sudo mv prometheus-2.53.0.linux-amd64/{prometheus,promtool} /usr/local/bin/
sudo useradd -r -s /usr/sbin/nologin prometheus
sudo mkdir -p /etc/prometheus /var/lib/prometheus
编写主配置文件 /etc/prometheus/prometheus.yml:
global:
scrape_interval: 15s # 抓取间隔
evaluation_interval: 15s # 告警规则评估间隔
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
basic_auth:
username: prometheus
password: '你的明文密码'
# 如果还有别的服务器,把内网 IP 加进来即可:
# - targets: ['10.0.0.2:9100', '10.0.0.3:9100']
rule_files:
- /etc/prometheus/rules/*.yml
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
创建 systemd 服务:
sudo tee /etc/systemd/system/prometheus.service > /dev/null <<'EOF'
[Unit]
Description=Prometheus
After=network.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/var/lib/prometheus \
--storage.tsdb.retention.time=180d \
--web.listen-address=:9090 \
--web.enable-lifecycle
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo chown -R prometheus:prometheus /var/lib/prometheus /etc/prometheus
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
两个参数值得说明:--storage.tsdb.retention.time=180d 把数据保留 180 天(默认只有 15 天,这是自建监控最大的价值);--web.enable-lifecycle 允许用 curl -X POST http://localhost:9090/-/reload 热加载配置,改完配置不用重启服务。
启动后验证:
curl -s http://127.0.0.1:9090/api/v1/targets | python3 -m json.tool | head -30
如果看到 "health": "up",说明 Prometheus 已经成功拉到 node_exporter 的指标。
五、第三步:安装配置 Grafana 并导入面板
Grafana 官方提供 apt 源,推荐直接添加源安装,升级方便:
sudo apt-get install -y wget gnupg
wget -q -O - https://packages.grafana.com/gpg.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/grafana.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://packages.grafana.com/oss/deb stable main" \
| sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install -y grafana
sudo systemctl enable --now grafana-server
首次打开 http://服务器IP:3000,默认账号密码都是 admin,登录后先改密码。然后添加数据源:
- 左侧菜单 Connections > Data sources > Add data source,选择 Prometheus;
- URL 填
http://localhost:9090; - 如果配置了 basic_auth,打开 Auth 里的 Basic Auth,填用户名密码;
- 点击 Save & test,看到
Successfully queried the Prometheus API即成功。
导入现成面板最省事,使用社区最流行的 node_exporter 全量面板(ID 8919,作者 StarsL):
面板导入步骤: 1. 左侧 Dashboards > Import,输入 8919 回车; 2. 选择 Prometheus 数据源; 3. Import 即可。
导入后即可看到 CPU 使用率、内存、磁盘、网络、TCP 连接数等二十多个图表。如果某些面板显示 No data,多半是 node_exporter 里没启用对应采集器(例如 --collector.processes),需要先开启对应 collector 再重启服务。
六、第四步:告警配置 Alertmanager + 钉钉机器人
监控没有告警等于白搭。先装 Alertmanager:
cd /tmp wget https://github.com/prometheus/alertmanager/releases/download/v0.27.0/alertmanager-0.27.0.linux-amd64.tar.gz tar xzf alertmanager-0.27.0.linux-amd64.tar.gz sudo mv alertmanager-0.27.0.linux-amd64/alertmanager /usr/local/bin/ sudo useradd -r -s /usr/sbin/nologin alertmanager sudo mkdir -p /etc/alertmanager
Alertmanager 配置文件 /etc/alertmanager/alertmanager.yml,这里用最省事的企业微信/钉钉机器人 Webhook 方式(以钉钉为例):
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 5m
repeat_interval: 4h # 同一告警 4 小时重复提醒一次
receiver: 'dingtalk'
receivers:
- name: 'dingtalk'
webhook_configs:
- url: 'https://oapi.dingtalk.com/robot/send?access_token=替换成你的token'
send_resolved: true
然后在 Prometheus 的 rules 目录写告警规则 /etc/prometheus/rules/node.yml:
groups:
- name: node_rules
rules:
- alert: HostHighCpuLoad
expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} CPU 使用率超过 90%"
- alert: HostMemoryLow
expr: (1 - node_memory_Available_bytes / node_memory_MemTotal_bytes) * 100 > 90
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} 内存使用率超过 90%"
- alert: HostDiskSpaceLow
expr: (1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}) * 100 > 85
for: 10m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} 磁盘 {{ $labels.mountpoint }} 使用率超过 85%"
- alert: HostUnreachable
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} 已无法抓取(机器宕机或 exporter 停止)"
写完用 promtool 校验语法,然后重启三个服务:
sudo promtool check rules /etc/prometheus/rules/node.yml sudo systemctl restart alertmanager prometheus # 观察告警是否进入 firing 状态 curl -s http://127.0.0.1:9090/api/v1/alerts | python3 -m json.tool
注意磁盘告警规则里用 fstype!~"tmpfs|overlay" 过滤掉了 tmpfs 和 Docker overlay 挂载点,否则 Docker 环境会疯狂误报磁盘满。
七、常见排错:五类高频问题一次说清
7.1 Grafana 面板一片空白 / No data
按顺序排查:先在 Grafana 的 Explore 页面执行 up 查询,返回 1 说明数据源链路通;然后查 node_memory_MemTotal_bytes 是否有值。都没有,就回到 Prometheus Status > Targets 看 target 是否 UP。最常见的坑是 Prometheus 配置里写的是 localhost,但 Prometheus 是 Docker 容器跑的,容器内的 localhost 不是宿主机的 localhost——Docker 部署时 target 要写宿主机 IP。
7.2 端口通但 curl 超时 / 数据抓不到
先确认三个端口监听在正确的地址上:
ss -tlnp | grep -E '9100|9090|3000' # 期望看到 0.0.0.0:9100 等监听
如果 Grafana 想通过公网访问,检查防火墙和云厂商安全组是否放行 3000 端口。Debian 系默认 ufw 未启用,但有些系统镜像预装了 firewalld:
sudo firewall-cmd --add-port=3000/tcp --permanent sudo firewall-cmd --reload
7.3 告警一直不触发
先在 Prometheus Status > Rules 页面看规则状态。规则是 Pending 说明阈值已超但还没到 for 时长,属正常;一直是 Inactive 说明表达式结果没达到阈值。用 PromQL 单独算一下表达式,确认单位换算(比如 Prometheus 里 CPU 用率是 0~1 还是 0~100,取决于表达式写法)。另外确认 alerting.alertmanagers 配置没写错,curl http://127.0.0.1:9093/api/v2/status 能返回 JSON 才说明链路通。
7.4 磁盘容量明明没满却报警
大概率是 tmpfs/overlay 被统计进去了。解决办法就是前面规则里加 fstype!~"tmpfs|overlay" 过滤。还可以在 node_exporter 启动参数里加上挂载点排除,双保险。
7.5 Grafana 图表时间轴不对(晚 8 小时)
这是时区问题。Grafana 默认用 UTC,在 Configuration > Preferences 把 Timezone 改成 Asia/Shanghai,或者直接在 URL 上追加 ?tz=Asia%2FShanghai。注意 Grafana 存储的时间戳本身是 UTC 绝对时间,改时区只影响显示,不影响数据正确性。
八、安全加固:不要裸奔 9090 和 3000
Prometheus 9090 和 Grafana 3000 都不建议直接暴露公网,三件事必做:
8.1 给 exporter 加 basic_auth
node_exporter 的 web.yml 里 bcrypt 密码可以用 htpasswd 生成(node_exporter 官方文档明确支持 bcrypt 前缀):
sudo apt-get install -y apache2-utils htpasswd -nbB prometheus '你的强密码' # 输出形如 prometheus:$2y$05$xxxxxxxx,把它填进 web.yml 的 basic_auth_users
8.2 通过 Nginx 反代访问 Grafana 并上 HTTPS
server {
listen 443 ssl;
server_name grafana.example.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Grafana 官方要求带上以下两个头
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
同时给 9090、3000、9100 加防火墙白名单,只允许内网 IP 或本机访问:
sudo ufw allow from 127.0.0.1 to any port 9090,9100 sudo ufw allow from 你的管理机IP to any port 3000
九、进阶:一台监控机管全部服务器
当你有 5 台、10 台 VPS 时,只需要在每台业务机上装 node_exporter,Prometheus 的 targets 里把内网 IP 列出来即可。再配合 --storage.tsdb.retention.time=180d,半年的历史数据随便翻。如果数据量太大(每天超过几 GB),还可以用 remote_write 对接 VictoriaMetrics,但那又是另一篇文章了。
整套系统跑起来后,你会有两件事:一是把默认密码全改掉,二是把告警阈值调成自己业务真正敏感的值。监控的价值不在"有图",而在"出故障时能第一时间收到消息,并且能翻出历史曲线定位问题"。




