VPS 监控搭建实战:Prometheus + node_exporter + Grafana 从零部署到告警通知


VPS 监控搭建实战:Prometheus + node_exporter + Grafana 从零部署到告警通知

VPS 监控搭建实战:Prometheus + node_exporter + Grafana 从零部署到告警通知

一、为什么要自建监控:云厂商监控的三个短板

很多 VPS 用户依赖云厂商控制台自带的监控面板,但遇到实际问题时往往不够用:

  1. 指标粒度粗:控制台只有 CPU、内存、带宽几个大项,磁盘 IOPS、TCP 连接数、inode 使用率、进程级指标统统没有;
  2. 历史数据短:免费版通常只保留几天到一个月,出了故障想回溯三个月前的数据曲线,查不到;
  3. 告警能力弱:控制台告警要么收费、要么只能发站内信,做不到自定义阈值、分组、静默、对接钉钉/企业微信。

自建一套 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,登录后先改密码。然后添加数据源:

  1. 左侧菜单 Connections > Data sources > Add data source,选择 Prometheus;
  2. URL 填 http://localhost:9090;
  3. 如果配置了 basic_auth,打开 Auth 里的 Basic Auth,填用户名密码;
  4. 点击 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,但那又是另一篇文章了。

整套系统跑起来后,你会有两件事:一是把默认密码全改掉,二是把告警阈值调成自己业务真正敏感的值。监控的价值不在"有图",而在"出故障时能第一时间收到消息,并且能翻出历史曲线定位问题"。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

Web 性能优化实战:HTTP/2 开启、gzip/brotli 压缩与浏览器缓存策略

国际阿里云|腾讯云|AWS亚马逊云|谷歌云|微软云,全球云代理商7折优惠,海外服务器便捷开通

评 论
更换验证码