08 Grafana + Prometheus 资源监控

定位:CloudLab 的"主机资源监控",面试官可实时查看服务器 CPU/内存/磁盘/负载图表
服务器:华为云 Flexus · 目录 /opt/cloudlab/monitor
日期:2026-10-19


一、项目介绍

一套白盒指标监控,由三个开源组件组成,是云原生监控的事实标准:

组件 职责 端口
Node Exporter 采集主机指标(CPU/内存/磁盘/网络/负载),暴露给 Prometheus 9100
Prometheus 定时拉取(pull)指标,存为时间序列(TSDB) 9090
Grafana 可视化,把 Prometheus 数据做成仪表盘(对外展示) 3000

与 Uptime Kuma 的分工

Uptime Kuma(06) 本套(08)
视角 黑盒:服务/网站是否可用 白盒:主机资源多少
判断 探测状态码(Up/Down) 采集指标(CPU/内存数值)
数据 响应时间、可用率 时序指标、趋势

部署架构

flowchart LR
    subgraph 宿主机[宿主机 华为云Flexus]
      NE[Node Exporter:9100<br/>挂载 /proc /sys /]
    end
    NE -->|pull 每15秒| P[Prometheus:9090<br/>TSDB 保留15天]
    P -->|数据源| G[Grafana:3000<br/>Node Exporter Full]
    G --> U[用户/面试官]

二、要做什么

  1. 评估内存,加 Swap 兜底
  2. 一个 Compose 部署三个容器(只对外暴露 Grafana)
  3. 配置 Prometheus 采集 Node Exporter
  4. Grafana 添加 Prometheus 数据源
  5. 导入现成 Node Exporter 仪表盘
  6. (备案后)NPM 反代 monitor.cloud321.cloud

三、可能遇到的问题

  1. 2G 内存紧张、无 Swap → OOM 风险
  2. Node Exporter 不挂载宿主机就读不到真实指标
  3. 数据源 URL 填 127.0.0.1 会连不通
  4. 导入仪表盘大量空白/No data(时间窗口)
  5. 域名 80/443 被未备案阻断

四、实际部署经历

1. 内存评估 + 加 Swap

free -h
docker stats --no-stream
  • available 1.1G,现有容器(Kuma 164MB、Vaultwarden 22MB、NPM 98MB)共约 283MB;
  • 但无 Swap,峰值有 OOM 风险,加 1G Swap 兜底:
dd if=/dev/zero of=/swapfile bs=1M count=1024
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
grep -q '/swapfile' /etc/fstab || echo '/swapfile none swap sw 0 0' >> /etc/fstab

2. 采集配置 prometheus.yml

global:
  scrape_interval: 15s        # 采集间隔
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
  - job_name: 'node'
    static_configs:
      - targets: ['node-exporter:9100']   # 用服务名

3. 编排 docker-compose.yml

services:
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--path.rootfs=/rootfs'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    expose: ['9100']

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=15d'
      - '--web.enable-lifecycle'
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    expose: ['9090']

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: unless-stopped
    ports: ['3000:3000']
    volumes:
      - grafana-data:/var/lib/grafana

volumes:
  prometheus-data:
  grafana-data:

要点:
- Node Exporter 挂载宿主机 /proc /sys /(只读),并改 --path.procfs 等,才能读到真实主机指标;
- expose(非 ports):Prometheus/Node Exporter 只在内部网络可见,不暴露公网;
- 三容器同一网络,用服务名互通;
- 只对外暴露 Grafana 3000;
- 保留期 15 天,省内存和磁盘。

4. 启动 + 验证采集

docker-compose up -d
docker-compose ps
# targets 健康
docker exec prometheus wget -qO- http://localhost:9090/api/v1/targets | grep -oE '"(job|health)":"[^"]*"'
# 指标样例
docker exec node-exporter wget -qO- http://localhost:9100/metrics | grep node_cpu_seconds_total

结果:node、prometheus 两个 job 均 up;node_cpu_seconds_total、node_load1 有数据。

5. 放行 3000 + 登录 Grafana

iptables -I INPUT -p tcp --dport 3000 -j ACCEPT
service iptables save

安全组入方向也加 3000。访问 http://公网IP:3000,默认 admin/admin,首次强制改密。

6. 添加 Prometheus 数据源

  • 左侧 Connections → Data sources → Add data source → Prometheus
  • Prometheus server URL:http://prometheus:9090(服务名,非 127.0.0.1)
  • Save & test,出现 "Successfully queried the Prometheus API"。

7. 导入仪表盘

  • Dashboards → Import,输入模板 ID 1860(Node Exporter Full)
  • 选择 Prometheus 数据源 → Import
  • 立即看到全套主机监控图。

8. 时间窗口 No data + 指标解读

  • 现象:Last 24 hours 窗口大量空白、P 显示 No data;
  • 原因:数据从现在才开始采集,24 小时窗口里只有最右侧有数据;
  • 解决:时间范围改成 Last 15 minutes,全部填充;
  • 验证 node_load1 = 0.14(采集正常,只是窗口问题)。

当前指标:CPU 2核/2.7%、内存 2GiB/64.1%、Swap 1024MiB/0%、磁盘 39GiB/29.9%、Uptime 1.3 天。


五、核心概念深入(面试重点)

1. Pull(拉)模型 vs Push(推)

Pull(Prometheus) Push(Zabbix Agent 等)
方向 Server 主动定时来拉目标 Agent 主动上报给 Server
优点 集中控制、目标健康可见(up)、易调试 适合短任务/ NAT 后目标
缺点 不适合短命任务(用 Pushgateway 补) 服务端被动、难发现失联

2. 指标类型

类型 特点 例子
Counter 单调递增,只增不减(重启归零) node_cpu_seconds_total、网络收发字节
Gauge 瞬时值,可大可小 node_load1、node_memory_MemFree
Histogram 采样分布,分桶计数 请求延迟分布
Summary 直接给分位数 P99 延迟

3. Exporter 模式

  • Exporter 把各系统/服务的数据转换成 Prometheus 文本格式,在 HTTP 端点(/metrics)暴露;
  • 常见:Node Exporter(主机)、MySQL Exporter、Blackbox Exporter(黑盒);
  • Prometheus 只需拉取对应端点。

4. PromQL 基础(看懂仪表盘)

up                                              # 目标是否在线(1/0)
node_load1                                      # 1分钟负载
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100   # 可用内存%
100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)  # CPU使用率
  • rate():求 Counter 每秒增长率(只用于 Counter);
  • [5m]:取最近 5 分钟窗口;
  • by(instance):按实例分组聚合。

5. TSDB 与保留期

  • Prometheus 内置时序数据库(TSDB),数据按"指标名+标签+时间戳"存储;
  • --storage.tsdb.retention.time=15d 控制保留时长,小服务器设短以省空间;
  • 长期存储可对接 Thanos、VictoriaMetrics(单机学习用不到)。

六、踩坑记录与关键经验

问题 根因 解决
OOM 风险 2G 内存无 Swap 加 1G Swap
主机指标缺失 未挂载宿主机命名空间 挂载 /proc /sys / 并改路径
数据源连不通 填了 127.0.0.1 用服务名 prometheus:9090
大量 No data 时间窗口 24h、数据刚采 改 15 分钟,等待
域名访问不了 未备案 走备案(07)

核心经验:
1. Prometheus 是 Pull 模型,目标暴露 /metrics 即可被采集;
2. 容器采集宿主机指标,必须挂载宿主命名空间;
3. 内部服务用 expose 收敛、只暴露必要端口,缩小攻击面;
4. 监控数据需要时间积累,时间窗口要匹配数据采集时长。


七、项目不足与扩展

  • 仅监控单机,未做多目标/服务发现;
  • 未配置告警规则(Prometheus Alertmanager + Grafana Alerting 可扩展);
  • 数据保留短(15天),无长期存储;
  • 对外正式访问依赖 ICP 备案(07),当前用 http://公网IP:3000;
  • 可增加 MySQL Exporter、Nginx Exporter 等,覆盖更多服务。