自建服务器监控实战:Prometheus + Grafana 从零搭起生产级告警体系

服务器跑了一堆服务,心里却一直不踏实——哪天…

服务器跑了一堆服务,心里却一直不踏实——哪天磁盘满了、内存爆了、服务挂了,等用户反馈才知道,那太被动了。这大概是每个自部署玩家的必经阶段:从”能跑就行”到”我得知道它现在怎样”。

今天这篇就把我自用的监控方案完整走一遍:Prometheus 采集指标、Grafana 可视化展示、Alertmanager 告警通知,三件套全部 Docker 部署,你只要有一台 Linux 服务器就能跟着搭。

为什么是 Prometheus + Grafana?

市面上监控方案不少,Netdata 开箱即用但数据出不去、Zabbix 功能强大但太重、云厂商的监控服务是付费不说,数据还得往外送。Prometheus 这个组合是我折腾一圈后留下的方案,理由就三条:

  • Pull 模型——被监控端不用主动上报,Prometheus Server 按间隔去拉数据,安全可控,单个节点挂了不影响其他节点
  • 生态极广——几乎所有主流中间件(Nginx、MySQL、Redis、Docker、Kubernetes)都有现成的 Exporter,装上就能采集
  • Grafana 的仪表盘太好看——这不是开玩笑,可视化的美观程度直接影响你巡检的意愿

整体架构

先脑子里过一遍各个组件的关系:

  • Prometheus Server:核心,负责拉取和存储指标数据,按标签组织时间序列
  • Exporters:部署在各节点/服务上的采集器,把系统指标暴露成 HTTP 端点给 Prometheus 拉
  • Grafana:从 Prometheus 读数据,画仪表盘,支持告警面板
  • Alertmanager:处理告警规则触发的通知,推送到钉钉、微信、邮件、Telegram

我们要的就是一个 docker-compose.yml 把这几样全部拉起来,后续加节点只需要在被监控机上跑一个 Exporter 容器。

第一步:准备目录结构和配置文件

先在服务器上建个目录,后面所有配置都放这:

mkdir -p /opt/monitoring/{prometheus,grafana,alertmanager}
cd /opt/monitoring

然后写 Prometheus 的配置文件。这是核心,告诉 Prometheus 去哪里拉数据:

# /opt/monitoring/prometheus/prometheus.yml
global:
  scrape_interval: 15s       # 默认采集间隔
  evaluation_interval: 15s   # 告警规则评估间隔

alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - alertmanager:9093

rule_files:
  - "rules/*.yml"

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

  # 本机节点监控 (node_exporter)
  - job_name: 'node'
    static_configs:
      - targets: ['node_exporter:9100']

  # Docker 容器监控 (cadvisor)
  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

再建一个告警规则文件,定义什么时候触发告警:

mkdir -p /opt/monitoring/prometheus/rules
cat > /opt/monitoring/prometheus/rules/node_alerts.yml << 'EOF'
groups:
  - name: node_alerts
    rules:
      - alert: HighCpuUsage
        expr: (1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance)) * 100 > 80
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "CPU 使用率超过 80% ({{ $value }}%)"

      - alert: DiskSpaceLow
        expr: node_filesystem_avail_bytes{mountpoint="/",fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{mountpoint="/",fstype!~"tmpfs|overlay"} * 100 < 10
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "磁盘剩余空间不足 10%"

      - alert: MemoryPressure
        expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 90
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "内存使用率超过 90% ({{ $value }}%)"

      - alert: NodeDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "节点 {{ $labels.instance }} 已离线"
EOF

再配一下 Alertmanager,让它把告警推到钉钉(你也可以换 Telegram 或邮件):

# /opt/monitoring/alertmanager/alertmanager.yml
global:
  resolve_timeout: 5m

route:
  group_wait: 10s
  group_interval: 2m
  repeat_interval: 4h
  receiver: 'dingtalk'

receivers:
  - name: 'dingtalk'
    webhook_configs:
      - url: 'http://dingtalk-webhook:8060/dingtalk/webhook1/send'
        send_resolved: true

如果不用钉钉,换 Telegram 更简单,直接设一个 bot:

# Alertmanager Telegram 示例
receivers:
  - name: 'telegram'
    telegram_configs:
      - bot_token: '你的BOT_TOKEN'
        chat_id: 你的CHAT_ID
        parse_mode: 'HTML'
        send_resolved: true

第二步:Docker Compose 一键拉起

这是最爽的一步,一个 docker-compose.yml 搞定所有组件:

# /opt/monitoring/docker-compose.yml
version: '3.8'

networks:
  monitoring:
    driver: bridge

volumes:
  prometheus_data:
  grafana_data:

services:
  # Prometheus 核心
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - ./prometheus:/etc/prometheus
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=30d'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
    ports:
      - "9090:9090"
    networks:
      - monitoring
    restart: unless-stopped

  # 节点指标采集
  node_exporter:
    image: prom/node-exporter:latest
    container_name: node_exporter
    command:
      - '--path.rootfs=/host'
    pid: host
    volumes:
      - '/:/host:ro,rslave'
    ports:
      - "9100:9100"
    networks:
      - monitoring
    restart: unless-stopped

  # Docker 容器指标采集
  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    container_name: cadvisor
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
      - /dev/disk/:/dev/disk:ro
    devices:
      - /dev/kmsg
    ports:
      - "8080:8080"
    networks:
      - monitoring
    restart: unless-stopped

  # 可视化面板
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin123
      - GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
    ports:
      - "3000:3000"
    networks:
      - monitoring
    restart: unless-stopped

  # 告警管理
  alertmanager:
    image: prom/alertmanager:latest
    container_name: alertmanager
    volumes:
      - ./alertmanager:/etc/alertmanager
    command:
      - '--config.file=/etc/alertmanager/alertmanager.yml'
      - '--storage.path=/alertmanager'
    ports:
      - "9093:9093"
    networks:
      - monitoring
    restart: unless-stopped

直接启动:

cd /opt/monitoring
docker compose up -d

# 查看启动状态
docker compose ps

# 检查日志确认都跑起来了
docker compose logs --tail=20

启动后访问 http://你的服务器IP:9090/targets,应该能看到所有 targets 都是 UP 状态。如果有标红的,说明对应的 Exporter 没起来或者网络不通,检查一下容器日志。

第三步:配置 Grafana 仪表盘

Grafana 默认账号 admin / admin123(刚才环境变量里设的),登录后第一步是加数据源:

  • 左侧齿轮 → Data Sources → Add data source → Prometheus
  • URL 填 http://prometheus:9090(因为在同一个 Docker 网络里,容器名就是主机名)
  • 点 Save & Test,看到绿色提示就通上了

然后导入现成的仪表盘。不用自己从头画,Grafana 社区有几千个现成的模板,输入 ID 就直接导入:

  • Node Exporter Full(ID: 1860)—— 服务器概览,CPU、内存、磁盘、网络流量一张图全看
  • Docker Monitoring(ID: 179)—— 容器级别的 CPU/内存/网络/块 IO 监控

导入方式:左侧 + 号 → Import → 输入模板 ID → 选择 Prometheus 数据源 → Import。几十秒就有一套漂亮的板子。

第四步:给被监控节点装 Exporter(远程节点扩展)

如果你不止一台服务器(比如你有多台 VPS 或者家里还有 NAS),要在每台被监控的机器上也跑一个 node_exporter。每台机器上执行:

docker run -d \
  --name node_exporter \
  --net="host" \
  --pid="host" \
  -v "/:/host:ro,rslave" \
  --restart unless-stopped \
  prom/node-exporter:latest \
  --path.rootfs=/host

然后在 Prometheus 的配置文件里加上这个节点(记得防火墙放行 9100 端口):

# 加到 prometheus.yml 的 scrape_configs 里
  - job_name: 'node_vps2'
    static_configs:
      - targets: ['VPS2的IP:9100']

改完配置后不需要重启 Prometheus,它支持热加载:

# 或者直接给 Prometheus 发 SIGHUP
kill -HUP $(docker exec prometheus cat /prometheus/supervisor.pid 2>/dev/null)

# 最简单的热加载方式
curl -X POST http://localhost:9090/-/reload

然后去看 http://localhost:9090/targets,新节点应该会自动出现。

第五步:告警接入钉钉/Telegram

光有仪表盘不够——凌晨三点磁盘写满了你也不会盯着屏幕看。得让告警主动找你。

钉钉机器人:创建一个钉钉群 → 群设置 → 智能群助手 → 添加机器人 → 自定义(Webhook),拿到 Webhook 地址后,用 prometheus-webhook-dingtalk 这个桥接工具:

# 加到 docker-compose.yml
  dingtalk-webhook:
    image: timonwong/prometheus-webhook-dingtalk:latest
    container_name: dingtalk-webhook
    command:
      - '--ding.profile=webhook1=https://oapi.dingtalk.com/robot/send?access_token=你的TOKEN'
    ports:
      - "8060:8060"
    networks:
      - monitoring
    restart: unless-stopped

Telegram Bot:找 @BotFather 创建一个 bot 拿到 token,然后找 @userinfobot 拿到你的 chat_id。在 Alertmanager 配置里直接配 telegram_configs 即可(上面已经给出了示例)。

告警一旦触发,你的手机就会弹出”磁盘空间不足 10%”或者”节点离线”这样实实在在的推送,不用再等到用户来骂你才知道。

你可能遇到的坑

这方案我踩了不少坑,列几个高频的:

  • 防火墙端口问题:Prometheus、node_exporter、Grafana 各自有不同的端口。如果 targets 老是 DOWN,检查一下防火墙或安全组有没有放行 9100/9090/3000
  • 磁盘空间暴涨:Prometheus 默认保留 15 天数据,对于单机监控来说够用。如果节点很多,建议在启动参数里设 --storage.tsdb.retention.time=7d 缩减存储周期
  • Grafana 忘了密码:执行 docker exec grafana grafana-cli admin reset-admin-password 新密码 就能重置
  • 容器时间不同步:所有监控容器的时区一定要和宿主机一致,否则时间序列数据会乱。在 docker-compose 里加上 environment: - TZ=Asia/Shanghai

写在最后

这套方案我跑了快一年,三台 VPS 加两台家里的机器,全部通过这一个 Grafana 面板统览。半夜被钉钉叫醒过几次去看磁盘扩容,也靠 NodeDown 告警发现过某台低价 VPS 偷偷重启了。说实话,监控这件事做完了你不会觉得多了什么,但没做的时候,心里总悬着。

Prometheus + Grafana 的好处是”一次搭建,长期受益”。后续你想监控 Nginx 连接数、MySQL 慢查询、Redis 命中率,基本就是加一个 Exporter 容器、配一条 scrape_config 的事,不用改架构。

你的服务器在跑什么服务?欢迎留言聊聊你的监控方案。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注