black flat screen tv showing game

跑著量化策略和代理節點的伺服器,沒有監控是非常危險的。凌晨記憶體爆了、磁碟滿了、策略掛了——如果沒有告警,可能幾個小時後才發現。

這篇文章從零開始,搭建一套完整的監控系統:被監控機器上跑 Node Exporter 採集指標,Prometheus 收集儲存,Grafana 視覺化展示,加上 Telegram 告警。

架構說明

被監控 VPS(N臺)          監控中心 VPS(1臺)
┌──────────────┐          ┌─────────────────────┐
│ Node Exporter │ ──9100→ │ Prometheus(採集)   │
│ Node Exporter │ ──9100→ │ Grafana(展示)      │
│ Node Exporter │ ──9100→ │ Alertmanager(告警) │
└──────────────┘          └─────────────────────┘

我的做法:一臺小 VPS(1核1G 足夠)作為監控中心,其他機器裝 Node Exporter 暴露指標。

第一步:在被監控機器上安裝 Node Exporter

每臺要監控的 VPS 都要做這一步。

# 下載 Node Exporter(確認最新版本號)
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
mv node_exporter-1.8.2.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
User=nobody
ExecStart=/usr/local/bin/node_exporter --web.listen-address=:9100
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable node_exporter --now

驗證是否正常執行:

curl http://localhost:9100/metrics | head -20
# 看到大量指標輸出說明正常

防火牆設定:

Node Exporter 的 9100 埠只需要讓 Prometheus 伺服器訪問,不要對公網開放:

# 只允許監控中心 IP 訪問 9100
ufw allow from 監控中心IP to any port 9100
# 不要執行 ufw allow 9100  ← 這會對所有人開放

第二步:在監控中心安裝 Prometheus

這臺伺服器負責主動拉取所有機器的指標。

# 建立專用使用者
useradd --no-create-home --shell /bin/false prometheus

# 下載 Prometheus
cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v2.51.2/prometheus-2.51.2.linux-amd64.tar.gz
tar xzf prometheus-2.51.2.linux-amd64.tar.gz

# 安裝
mkdir -p /etc/prometheus /var/lib/prometheus
cp prometheus-2.51.2.linux-amd64/prometheus /usr/local/bin/
cp prometheus-2.51.2.linux-amd64/promtool /usr/local/bin/
cp -r prometheus-2.51.2.linux-amd64/consoles /etc/prometheus/
cp -r prometheus-2.51.2.linux-amd64/console_libraries /etc/prometheus/

chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus

建立配置檔案 /etc/prometheus/prometheus.yml:

global:
  scrape_interval: 30s      # 每 30 秒採集一次
  evaluation_interval: 30s

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['localhost:9093']

rule_files:
  - /etc/prometheus/rules/*.yml

scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets:
          - 'aws-hk-IP:9100'     # 香港節點
          - 'aws-us-IP:9100'     # 美國節點
          - 'aws-jp-IP:9100'     # 日本節點
          - 'dmit-us-IP:9100'    # DMIT 美國
        labels:
          env: 'production'

建立 systemd 服務:

cat > /etc/systemd/system/prometheus.service << 'EOF'
[Unit]
Description=Prometheus
After=network.target

[Service]
Type=simple
User=prometheus
ExecStart=/usr/local/bin/prometheus \
  --config.file=/etc/prometheus/prometheus.yml \
  --storage.tsdb.path=/var/lib/prometheus \
  --storage.tsdb.retention.time=30d \
  --web.listen-address=:9090
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable prometheus --now

訪問 http://監控中心IP:9090 驗證,在 Status → Targets 裡能看到所有被監控機器的狀態。

第三步:安裝 Grafana

# 新增 Grafana APT 源
apt-get install -y apt-transport-https software-properties-common
wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key
echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" | \
  tee /etc/apt/sources.list.d/grafana.list

apt-get update
apt-get install -y grafana

systemctl enable grafana-server --now

Grafana 預設跑在 3000 埠,訪問 http://監控中心IP:3000:

  • 預設賬號:admin
  • 預設密碼:admin(登入後會要求修改)

新增 Prometheus 資料來源

  1. 左側選單 → Connections → Data sources
  2. 點 Add data source → 選 Prometheus
  3. URL 填 http://localhost:9090
  4. 點 Save & test,顯示"Data source is working"即成功

匯入現成 Dashboard

不用自己畫圖,直接匯入社群的成熟 Dashboard:

  1. 左側選單 → Dashboards → Import
  2. 填入 Dashboard ID:1860(Node Exporter Full,最常用)
  3. 選擇 Prometheus 資料來源
  4. 點 Import

這個 Dashboard 包含:CPU 使用率、記憶體、磁碟 IO、網路流量、系統負載、檔案系統空間,非常完整。

第四步:配置 Telegram 告警

光有圖表不夠,機器出問題要第一時間收到通知。

建立 Telegram Bot

  1. 在 Telegram 裡找 @BotFather
  2. 傳送 /newbot,給 bot 起名字
  3. 儲存返回的 Bot Token(格式:1234567890:ABCD...)
  4. 給 bot 發一條訊息,然後訪問 https://api.telegram.org/bot你的TOKEN/getUpdates 獲取 chat_id

安裝 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
cp alertmanager-0.27.0.linux-amd64/alertmanager /usr/local/bin/
mkdir -p /etc/alertmanager

建立 /etc/alertmanager/alertmanager.yml:

global:
  resolve_timeout: 5m

route:
  receiver: telegram
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h

receivers:
  - name: telegram
    telegram_configs:
      - bot_token: '你的Bot Token'
        chat_id: 你的chat_id
        message: |
          🚨 告警:{{ .GroupLabels.alertname }}
          主機:{{ .GroupLabels.instance }}
          詳情:{{ range .Alerts }}{{ .Annotations.description }}{{ end }}
        send_resolved: true
cat > /etc/systemd/system/alertmanager.service << 'EOF'
[Unit]
Description=Alertmanager
After=network.target

[Service]
Type=simple
User=prometheus
ExecStart=/usr/local/bin/alertmanager \
  --config.file=/etc/alertmanager/alertmanager.yml \
  --storage.path=/var/lib/alertmanager
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable alertmanager --now

配置告警規則

建立 /etc/prometheus/rules/node_alerts.yml:

groups:
  - name: node_alerts
    rules:
      # CPU 超過 85% 持續 5 分鐘
      - alert: HighCPUUsage
        expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
        for: 5m
        annotations:
          description: "{{ $labels.instance }} CPU 使用率 {{ $value | printf \"%.1f\" }}%"

      # 記憶體可用低於 10%
      - alert: LowMemory
        expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 < 10
        for: 2m
        annotations:
          description: "{{ $labels.instance }} 可用記憶體僅剩 {{ $value | printf \"%.1f\" }}%"

      # 磁碟使用超過 85%
      - alert: DiskSpaceLow
        expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 < 15
        for: 5m
        annotations:
          description: "{{ $labels.instance }} 磁碟剩餘 {{ $value | printf \"%.1f\" }}%"

      # 機器宕機(超過 2 分鐘無法採集)
      - alert: InstanceDown
        expr: up == 0
        for: 2m
        annotations:
          description: "{{ $labels.instance }} 已離線超過 2 分鐘"

過載配置:

systemctl reload prometheus
# 或者
curl -X POST http://localhost:9090/-/reload

第五步:用 Nginx 反向代理(安全訪問)

不建議直接把 Grafana 的 3000 埠暴露到公網,用 Nginx 加一層:

apt install nginx -y

cat > /etc/nginx/sites-available/grafana << 'EOF'
server {
    listen 80;
    server_name grafana.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name grafana.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/grafana.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/grafana.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
EOF

ln -s /etc/nginx/sites-available/grafana /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

SSL 證書用 acme.sh 自動申請:

curl https://get.acme.sh | sh
~/.acme.sh/acme.sh --issue -d grafana.yourdomain.com --nginx
~/.acme.sh/acme.sh --install-cert -d grafana.yourdomain.com \
  --cert-file /etc/letsencrypt/live/grafana.yourdomain.com/fullchain.pem \
  --key-file /etc/letsencrypt/live/grafana.yourdomain.com/privkey.pem \
  --reloadcmd "systemctl reload nginx"

效果展示

搭建完成後你能看到:

  • 每臺機器的 CPU / 記憶體 / 磁碟實時曲線
  • 網路流量 in/out,清楚看到哪個節點在跑大流量
  • 系統負載趨勢,量化策略重算時的壓力一眼看出
  • 機器宕機或指標異常,Telegram 立刻收到告警

延伸閱讀:


📷 封面圖 · Flux Schnell AI 生成 · panshi.io 品牌風格