跳轉到內容

Prometheus + Grafana 監控系統搭建實戰 2026

Prometheus + Grafana 監控

📊 為什麼需要監控? 你花幾小時搭好的代理服務、博客、數據庫,一旦半夜掛掉,沒有監控你根本不知道。等到第二天用戶來反饋,黃金恢復時間早就錯過了。Prometheus + Grafana 是業界標準的開源監控組合——一個負責採集存儲指標,一個負責可視化告警,配合起來幾乎零成本就能擁有企業級監控能力。

本文將帶你從零搭建一套完整的 VPS 監控系統:

  • ✅ 監控 vs 告警:為什麼兩者缺一不可
  • ✅ Prometheus 核心原理(時序數據庫 / Pull 模型 / Exporter)
  • ✅ Node Exporter 採集 CPU/內存/磁盤/網絡
  • ✅ Docker Compose 一鍵部署整套監控棧
  • ✅ Grafana 看板導入與自定義
  • ✅ Alertmanager 郵件 / Telegram 告警
  • ✅ Nginx、SSL 證書、網站可用性進階監控
  • ✅ 多 VPS 集中管控與常見問題

一、為什麼需要 VPS 監控

1.1 典型痛點

痛點沒有監控有監控
服務宕機用戶反饋才知道告警秒級推送
磁盤寫滿數據庫崩潰才發現80% 容量就預警
流量異常月底才發現被刷實時流量曲線可見
性能劣化憑感覺優化數據驅動定位瓶頸
安全入侵事後溯源困難異常進程/連接立即可見

1.2 監控 vs 告警

很多人把監控等同於「看個圖表」,這是片面的。兩者職責不同:

  • 監控(Monitoring):持續採集指標、可視化展示,讓你「看得見」系統狀態。
  • 告警(Alerting):當指標突破閾值時主動通知你,讓你「被提醒」。

💡 只有看板沒有告警,等於裝了攝像頭卻沒人看;只有告警沒有看板,出問題了卻沒法分析原因。兩者必須配套。

1.3 開源方案對比

方案組成優點缺點適用
Prometheus + Grafana採集+可視化生態最完善、查詢強大、免費組件稍多通用首選
Zabbix一體化開箱即用、Agent 豐富配置偏重、UI 老舊傳統企業
Netdata一體化安裝極簡、實時性強長期存儲弱、定製差單機快速看
Nagios告警為主告警邏輯成熟可視化弱、配置繁瑣純告警場景
VictoriaMetrics替代 Prometheus性能更高、存儲更省生態較新超大規模

結論: 個人 VPS / 中小團隊首選 Prometheus + Grafana,生態成熟、資料多、遷移成本低。


二、Prometheus 核心原理

2.1 時序數據庫(TSDB)

Prometheus 存儲的是時序數據——帶時間戳的指標序列:

<指標名>{<標籤1>=<值1>, <標籤2>=<值2>} <數值> <時間戳>
node_memory_MemAvailable_bytes{instance="server-1:9100", job="node"} 3.2e+09 1750000000
  • 指標名:如 node_cpu_seconds_total
  • 標籤(Label):區分維度,如 instancejobmode
  • 數值:浮點數
  • 時間戳:毫秒級

2.2 Pull 模型

Prometheus 採用主動拉取(Pull)模式:服務端定時去各 Exporter 的 HTTP 接口抓取指標。

Prometheus Server
   │  (每 15s 拉取 /metrics)
   ├──> Node Exporter :9100/metrics
   ├──> Nginx Exporter :9113/metrics
   └──> Blackbox Exporter :9115/metrics

Pull vs Push 對比:

維度Pull(Prometheus)Push(如 StatsD)
服務發現天然支持需額外註冊
故障定位誰掛了一目瞭然推送失敗難排查
防火牆服務端主動出客戶端主動出
短任務需 Pushgateway 中轉天然支持

2.3 Exporter 生態

Exporter 是「指標翻譯器」,把各系統的內部狀態暴露成 Prometheus 格式:

Exporter監控對象
Node Exporter主機 CPU/內存/磁盤/網絡
cAdvisorDocker 容器
Nginx ExporterNginx 連接/請求
MySQL Exporter數據庫狀態
Blackbox ExporterHTTP/DNS/TCP 探測
Redis Exporter緩存狀態
Process Exporter指定進程

三、Node Exporter 部署

3.1 Docker 方式

bash
docker run -d \
  --name node-exporter \
  --restart=always \
  --network host \
  --pid host \
  -v "/proc:/host/proc:ro" \
  -v "/sys:/host/sys:ro" \
  -v "/:/rootfs:ro" \
  prom/node-exporter:latest \
  --path.procfs=/host/proc \
  --path.sysfs=/host/sys \
  --path.rootfs=/rootfs

3.2 二進制方式(Systemd)

bash
# 下載
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 cp node_exporter-1.8.2.linux-amd64/node_exporter /usr/local/bin/

# 創建 systemd 服務
sudo tee /etc/systemd/system/node-exporter.service > /dev/null <<'EOF'
[Unit]
Description=Node Exporter
After=network.target

[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter
Restart=always

[Install]
WantedBy=multi-user.target
EOF

# 創建專用用戶並啟動
sudo useradd -rs /bin/false node_exporter
sudo systemctl daemon-reload
sudo systemctl enable --now node-exporter

3.3 驗證指標

bash
curl http://localhost:9100/metrics | head -20
# 應看到 node_cpu_seconds_total、node_memory_MemAvailable_bytes 等指標

3.4 安全加固(重要)

Node Exporter 默認無認證,切勿直接暴露公網。推薦用 Nginx 反向代理 + Basic Auth 或僅監聽內網:

nginx
# /etc/nginx/conf.d/node-exporter.conf
location /metrics {
    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
    proxy_pass http://127.0.0.1:9100;
}

四、Prometheus 服務端部署

4.1 Docker Compose 完整配置

創建 docker-compose.yml

yaml
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: always
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=30d'
      - '--web.enable-lifecycle'

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: always
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=your_strong_password
    volumes:
      - grafana_data:/var/lib/grafana

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: always
    network_mode: host
    pid: host
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro

volumes:
  prometheus_data:
  grafana_data:

4.2 Prometheus 配置文件

prometheus.yml

yaml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  # 監控 Prometheus 自己
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # 監控本機
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']
        labels:
          instance: 'server-main'

  # 監控另一臺 VPS(通過內網/隧道 IP)
  - job_name: 'node-remote'
    static_configs:
      - targets: ['10.0.0.2:9100']
        labels:
          instance: 'server-edge'

4.3 數據保留與性能

參數說明建議
retention.time數據保留時長15~30d(個人)
retention.size數據體積上限2GB 防止寫滿磁盤
wal-compressionWAL 壓縮開啟節省空間

磁盤佔用估算:

每目標 ≈ 1~2 MB/天(默認採集頻率)
30 天 × 5 目標 ≈ 150~300 MB

4.4 啟動與驗證

bash
docker compose up -d
# 訪問 http://你的IP:9090
# 在 Graph 頁面執行: up  → 應看到所有 target 的 up=1

五、Grafana 可視化

5.1 首次登錄

地址: http://你的IP:3000
默認賬號: admin / admin(首次登錄強制改密碼)

5.2 添加 Prometheus 數據源

  1. 左側菜單 Connections → Data sources → Add data source
  2. 選擇 Prometheus
  3. URL 填 http://prometheus:9090(同一 Docker 網絡用服務名)
  4. 點擊 Save & test,顯示綠色對勾即成功

5.3 導入 Node Exporter 看板

Grafana 社區有成熟的現成看板,無需從零畫:

  1. 左側 Dashboards → New → Import
  2. 輸入官方 Dashboard ID:1860(Node Exporter Full)或 8919(新版)
  3. 選擇剛才添加的 Prometheus 數據源
  4. 點擊 Import

💡 推薦常用 Dashboard ID:

  • 1860 — Node Exporter Full(主機監控經典)
  • 11074 — Node Exporter 輕量版
  • 893 — 主機硬件溫度(需額外 exporter)

5.4 核心指標 PromQL 查詢

如果你想自己畫面板,以下是常用查詢:

promql
# CPU 使用率(非 idle)
100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# 內存使用率
100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)

# 磁盤使用率(根分區)
100 * (1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})

# 網絡流入速率(Mbps)
rate(node_network_receive_bytes_total{device="eth0"}[5m]) * 8 / 1024 / 1024

# 1 分鐘負載
node_load1 / count by(instance)(node_cpu_seconds_total{mode="idle"})

六、核心 Dashboard 構建

6.1 推薦面板佈局

面板指標
概覽系統狀態總覽up
CPU使用率 / 核心分佈node_cpu_seconds_total
內存已用 / 可用 / Swapnode_memory_*
磁盤分區使用率 / IO 速率node_filesystem_* / node_disk_*
網絡入站 / 出站流量node_network_*
進程運行進程數 / 負載node_procs_running / node_load*

6.2 示例面板 JSON 片段

Grafana 面板是 JSON 結構,以下是一個「CPU 使用率」面板核心字段:

json
{
  "title": "CPU 使用率",
  "type": "timeseries",
  "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 },
  "targets": [
    {
      "expr": "100 - (avg by(instance)(rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)",
      "legendFormat": "{{instance}}"
    }
  ],
  "fieldConfig": {
    "defaults": {
      "unit": "percent",
      "max": 100
    }
  }
}

6.3 閾值與單位

Grafana 支持在面板中設置閾值變色:

指標單位警告閾值嚴重閾值
CPU 使用率%7090
內存使用率%8095
磁盤使用率%8090
網絡流量MB/s按帶寬定

七、告警規則配置

7.1 告警規則文件

alerts.yml

yaml
groups:
  - name: node-alerts
    rules:
      - alert: 實例宕機
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.instance }} 已離線"
          description: "實例 {{ $labels.instance }} 持續 1 分鐘無法抓取"

      - alert: 高CPU使用率
        expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.instance }} CPU 過高"
          description: "CPU 使用率持續 5 分鐘超過 85%"

      - alert: 磁盤即將寫滿
        expr: 100 * (1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) > 85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.instance }} 磁盤空間不足"
          description: "根分區使用率超過 85%"

      - alert: 內存不足
        expr: 100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 90
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.instance }} 內存緊張"
          description: "內存使用率超過 90%"

prometheus.yml 中引用:

yaml
rule_files:
  - /etc/prometheus/alerts.yml

7.2 Alertmanager 部署

yaml
# 在 docker-compose.yml 中追加
  alertmanager:
    image: prom/alertmanager:latest
    container_name: alertmanager
    restart: always
    ports:
      - "9093:9093"
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
    command:
      - '--config.file=/etc/alertmanager/alertmanager.yml'

prometheus.yml 添加告警路由:

yaml
alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

7.3 郵件告警通道

alertmanager.yml

yaml
global:
  smtp_smarthost: 'smtp.gmail.com:587'
  smtp_from: 'monitor@gmail.com'
  smtp_auth_username: 'monitor@gmail.com'
  smtp_auth_password: '應用專用密碼'
  smtp_require_tls: true

route:
  receiver: 'email-alert'
  group_by: ['alertname', 'instance']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h

receivers:
  - name: 'email-alert'
    email_configs:
      - to: 'admin@example.com'
        subject: '[監控告警] {{ .CommonAnnotations.summary }}'
        body: |
          告警: {{ .CommonAnnotations.summary }}
          詳情: {{ .CommonAnnotations.description }}
          時間: {{ .StartsAt }}

7.4 Telegram 告警通道

Telegram 更適合移動端即時推送。先找 @BotFather 創建 Bot 獲取 Token,再找 @userinfobot 獲取 Chat ID。

yaml
receivers:
  - name: 'telegram-alert'
    telegram_configs:
      - bot_token: '你的BOT_TOKEN'
        chat_id: '你的CHAT_ID'
        message: |
          🔥 *{{ .CommonAnnotations.summary }}*
          {{ .CommonAnnotations.description }}
          🖥 實例: {{ .CommonLabels.instance }}

八、進階監控

8.1 Nginx 訪問統計

啟用 Nginx stub_status,再用 nginx-prometheus-exporter 採集:

nginx
# nginx.conf
location /nginx_status {
    stub_status on;
    allow 127.0.0.1;
    deny all;
}
bash
docker run -d --name nginx-exporter \
  -p 9113:9113 \
  nginx/nginx-prometheus-exporter:latest \
  -nginx.scrape-uri=http://你的IP/nginx_status

Prometheus 添加 job:

yaml
  - job_name: 'nginx'
    static_configs:
      - targets: ['nginx-exporter:9113']

看板 ID:11199(Nginx 請求/連接/狀態碼)。

8.2 SSL 證書過期監控

Blackbox Exporter 探測 HTTPS 並解析證書剩餘天數:

yaml
# blackbox.yml
modules:
  https:
    prober: http
    http:
      preferred_ip_protocol: ip4
      tls: true

Prometheus 添加探測 job:

yaml
  - job_name: 'ssl-check'
    metrics_path: /probe
    params:
      module: [https]
    static_configs:
      - targets:
          - https://y-m.top
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: blackbox-exporter:9115

證書剩餘天數告警:

yaml
  - alert: SSL證書即將過期
    expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 14
    for: 1h
    labels:
      severity: warning
    annotations:
      summary: "SSL 證書將在 14 天內過期"
      description: "域名 {{ $labels.instance }} 證書剩餘不足 14 天"

8.3 網站可用性探測

Blackbox Exporter 還能探測網站是否可訪問、響應時間:

yaml
  - alert: 網站不可達
    expr: probe_success{job="blackbox-http"} == 0
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "{{ $labels.instance }} 訪問失敗"
      description: "HTTP 探測連續失敗超過 2 分鐘"
yaml
  - alert: 響應過慢
    expr: probe_duration_seconds{job="blackbox-http"} > 3
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "{{ $labels.instance }} 響應緩慢"
      description: "HTTP 響應時間持續超過 3 秒"

九、常見問題

Q1:Prometheus 內存佔用過高怎麼辦?
  1. 調低採集頻率:scrape_interval 從 15s 調到 30s 或 60s
  2. 減少目標數量:只為關鍵服務建 job
  3. 限制數據保留:--storage.tsdb.retention.time=15d
  4. 設置數據體積上限:--storage.tsdb.retention.size=2GB
  5. 給容器限制內存:deploy.resources.limits.memory: 1g
Q2:數據存哪裡?會不會寫滿磁盤?

默認存在 Docker 卷 prometheus_data(映射在 /var/lib/docker/volumes/)。務必設置 retention.size 上限,並監控宿主機磁盤。建議單獨掛一塊盤或定期備份:

bash
# 手動備份(停止容器後)
docker run --rm -v prometheus_data:/data -v $(pwd):/backup alpine \
  tar czf /backup/prometheus-backup.tar.gz -C /data .
Q3:多臺 VPS 如何集中監控?

三種方案:

方案做法適合
中心拉取監控服務器直接拉各 VPS 的 Exporter(需網絡可達)同內網/有隧道
反向代理各 VPS 用 Nginx 暴露 Exporter,中心統一拉有公網 IP
Pushgateway邊緣節點定時推送(適合 NAT/動態 IP)無公網 IP

最常用是中心拉取:監控服務器 Prometheus 配置多個 static_configs,targets 填各 VPS 內網 IP + 端口(通過 WireGuard 組網可互通)。

Q4:Grafana 進不去 / 密碼忘了?
bash
# 重置 admin 密碼
docker exec -it grafana grafana-cli admin reset-admin-password newpassword
Q5:告警不觸發?如何排查?
  1. 訪問 http://IP:9090/alerts 看規則是否 PENDING/FIRING
  2. 檢查 alertmanager.yml 語法:amtool check-config alertmanager.yml
  3. 確認 Prometheus alerting 段指向正確的 Alertmanager 地址
  4. amtool alert query 查看當前告警
  5. Telegram 確認 Bot Token 和 Chat ID 正確(Chat ID 是負數需帶負號)
Q6:能監控 Docker 容器嗎?

能。部署 cAdvisor 採集容器指標:

bash
docker run -d --name cadvisor \
  -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:latest

Prometheus 添加 job 指向 cadvisor:8080,看板 ID:893(Docker 監控)。

Q7:生產環境如何保護監控面板?
  1. Grafana/Prometheus 不要直接暴露公網,套一層 Nginx + Basic Auth 或反向代理
  2. Grafana 配置 GF_AUTH_ANONYMOUS_ENABLED=false 禁用匿名訪問
  3. 修改默認端口(9090/3000 眾所周知易被掃描)
  4. 啟用 HTTPS(參考站內 VPS 安全加固實戰指南
  5. 定期更新鏡像版本
Q8:和 VPS 供應商自帶的監控(如阿里云云監控)有什麼區別?
維度廠商監控Prometheus+Grafana
數據歸屬廠商掌握自己掌握
自定義受限完全自由
跨廠商各看各的統一看板
成本高級功能收費免費
告警渠道廠商 App郵件/Telegram/釘釘/Slack

自建監控的最大價值是跨廠商統一數據自主


總結

Prometheus + Grafana 是 VPS 監控的黃金組合。回顧核心要點:

  1. 架構清晰:Prometheus 拉取指標存儲,Grafana 可視化,Alertmanager 管告警
  2. 部署簡單:Docker Compose 一份配置拉起整套棧
  3. 看板現成:導入社區 Dashboard ID(1860/11199)即可用
  4. 告警靈活:郵件 + Telegram 雙通道,PromQL 精準定義閾值
  5. 可擴展:Nginx / SSL / 網站可用性 / 多節點一站式覆蓋

搭建順序建議:

1. Node Exporter(採集主機指標)
2. Prometheus(存儲 + 查詢)
3. Grafana(可視化看板)
4. 導入 Dashboard 1860
5. Alertmanager(郵件/Telegram 告警)
6. 進階:Blackbox + Nginx Exporter

延伸閱讀:

🚀 監控不是錦上添花,而是系統穩定運行的底線。花一晚上搭好這套監控,未來無數個安穩的夜晚都是它換來的。


相關命令速查:

bash
# 啟動整套監控
docker compose up -d

# 查看狀態
docker compose ps

# 重啟單個服務
docker compose restart prometheus

# 熱加載 Prometheus 配置(無需重啟)
curl -X POST http://localhost:9090/-/reload

# 查看告警
docker logs alertmanager

最後更新於: