2148 字
11 分钟
Linux 服务器监控完全指南 2026:Prometheus + Grafana + Alertmanager 实战部署
服务器”裸奔”是每个运维工程师都曾经历过的阶段——CPU 爆满、磁盘满了、OOM 了,全靠用户投诉才发现。建立监控体系,是从被动救火转向主动运维的关键一步。
本文用 Docker Compose 一键部署完整的 Prometheus + Grafana + Alertmanager 监控栈,覆盖从安装到告警的全流程。
一、架构总览
┌─────────────────────────────────────────────────────┐│ 被监控服务器 ││ Node Exporter :9100 ← 系统指标(CPU/内存/磁盘) ││ cAdvisor :8080 ← 容器指标 ││ App Exporter :xxxx ← 应用自定义指标 │└─────────────────────────┬───────────────────────────┘ │ HTTP Pull(每15秒拉取)┌─────────────────────────▼───────────────────────────┐│ 监控服务器 ││ ││ Prometheus :9090 ← 存储时序数据 + 评估告警规则 ││ │ ││ ├─→ Grafana :3000 ← 可视化 Dashboard ││ └─→ Alertmanager :9093 ← 告警路由 + 通知 │└─────────────────────────────────────────────────────┘二、Docker Compose 一键部署
# 目录结构:# monitoring/# ├── docker-compose.yml# ├── prometheus/# │ ├── prometheus.yml# │ └── rules/# │ └── alerts.yml# └── alertmanager/# └── alertmanager.yml
services: prometheus: image: prom/prometheus:v2.53.0 container_name: prometheus restart: unless-stopped ports: - "9090:9090" volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro - ./prometheus/rules:/etc/prometheus/rules:ro - prometheus_data:/prometheus command: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.path=/prometheus" - "--storage.tsdb.retention.time=30d" # 数据保留30天 - "--web.enable-lifecycle" # 允许热重载配置 - "--web.enable-admin-api" networks: [monitoring]
grafana: image: grafana/grafana:11.1.0 container_name: grafana restart: unless-stopped ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_USER=admin - GF_SECURITY_ADMIN_PASSWORD=changeme123 # 部署后立即修改! - GF_USERS_ALLOW_SIGN_UP=false - GF_SERVER_DOMAIN=monitor.example.com volumes: - grafana_data:/var/lib/grafana networks: [monitoring] depends_on: [prometheus]
alertmanager: image: prom/alertmanager:v0.27.0 container_name: alertmanager restart: unless-stopped ports: - "9093:9093" volumes: - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro - alertmanager_data:/alertmanager command: - "--config.file=/etc/alertmanager/alertmanager.yml" - "--storage.path=/alertmanager" networks: [monitoring]
node-exporter: image: prom/node-exporter:v1.8.1 container_name: node-exporter restart: unless-stopped ports: - "9100:9100" volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/rootfs:ro command: - "--path.procfs=/host/proc" - "--path.rootfs=/rootfs" - "--path.sysfs=/host/sys" - "--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)" network_mode: host # 直接使用宿主机网络,采集更准确
cadvisor: image: gcr.io/cadvisor/cadvisor:v0.49.1 container_name: cadvisor restart: unless-stopped ports: - "8080:8080" volumes: - /:/rootfs:ro - /var/run:/var/run:ro - /sys:/sys:ro - /var/lib/docker:/var/lib/docker:ro networks: [monitoring]
volumes: prometheus_data: grafana_data: alertmanager_data:
networks: monitoring: driver: bridge# 启动监控栈docker compose up -d
# 验证各服务curl http://localhost:9090/-/healthy # Prometheuscurl http://localhost:9100/metrics # Node Exporter(查看原始指标)curl http://localhost:3000 # Grafana Web UI三、Prometheus 配置
global: scrape_interval: 15s # 每15秒拉取一次指标 evaluation_interval: 15s # 每15秒评估一次告警规则 scrape_timeout: 10s
# 告警规则文件rule_files: - "rules/*.yml"
# Alertmanager 配置alerting: alertmanagers: - static_configs: - targets: ["alertmanager:9093"]
# 采集目标scrape_configs: # 监控 Prometheus 自身 - job_name: "prometheus" static_configs: - targets: ["localhost:9090"]
# 本机 Node Exporter - job_name: "node-local" static_configs: - targets: ["localhost:9100"] labels: instance: "monitor-server" env: "production"
# 远程服务器(静态配置) - job_name: "node-remote" static_configs: - targets: - "192.168.1.10:9100" - "192.168.1.11:9100" labels: env: "production" - targets: - "192.168.2.10:9100" labels: env: "staging"
# Docker 容器指标 - job_name: "cadvisor" static_configs: - targets: ["cadvisor:8080"]
# 应用服务(示例:FastAPI 暴露的 /metrics 端点) - job_name: "myapp" metrics_path: /metrics static_configs: - targets: ["myapp:8000"] relabel_configs: - source_labels: [__address__] target_label: instance# 热重载配置(无需重启)curl -X POST http://localhost:9090/-/reload四、PromQL 核心查询
4.1 系统资源查询
# CPU 使用率(百分比,5分钟平均)100 - (avg by (instance) ( rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 各 CPU 核心使用率(识别单核热点)100 - (rate(node_cpu_seconds_total{mode="idle"}[5m]) * 100)
# 内存使用率(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100
# 内存使用量(GB)(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / 1024^3
# 磁盘使用率(排除 tmpfs)( node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}) / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} * 100
# 磁盘 IO(读写速度 MB/s)rate(node_disk_read_bytes_total[5m]) / 1024 / 1024rate(node_disk_written_bytes_total[5m]) / 1024 / 1024
# 网络流量(MB/s)rate(node_network_receive_bytes_total{device!="lo"}[5m]) / 1024 / 1024rate(node_network_transmit_bytes_total{device!="lo"}[5m]) / 1024 / 1024
# 系统负载node_load1 # 1分钟负载node_load5 # 5分钟负载node_load15 # 15分钟负载
# TCP 连接数node_netstat_Tcp_CurrEstab4.2 容器指标
# 容器 CPU 使用率rate(container_cpu_usage_seconds_total{name!=""}[5m]) * 100
# 容器内存使用container_memory_usage_bytes{name!=""} / 1024 / 1024
# 容器网络流量rate(container_network_receive_bytes_total{name!=""}[5m])4.3 PromQL 常用函数速查
| 函数 | 用途 | 示例 |
|---|---|---|
rate(v[d]) | Counter 增长速率(推荐,处理 reset) | rate(http_requests_total[5m]) |
irate(v[d]) | 瞬时速率(最近2个点) | 突发流量监控 |
increase(v[d]) | 区间内增量 | increase(errors_total[1h]) |
avg_over_time(v[d]) | 时间区间平均值 | CPU 平均负载 |
max_over_time(v[d]) | 时间区间最大值 | 峰值内存 |
histogram_quantile(φ, v) | 计算分位数(P99延迟) | histogram_quantile(0.99, rate(http_duration_seconds_bucket[5m])) |
topk(n, v) | 最大的 N 个 | topk(5, rate(http_requests_total[5m])) |
predict_linear(v[d], t) | 线性预测 | 预测磁盘何时满 |
五、告警规则配置
groups: - name: system.rules interval: 1m # 覆盖全局 evaluation_interval rules:
# ── CPU 告警 ──────────────────────────────────────────── - alert: HighCPUUsage expr: | 100 - (avg by (instance) ( rate(node_cpu_seconds_total{mode="idle"}[5m]) ) * 100) > 85 for: 5m # 持续5分钟才告警(避免尖刺误报) labels: severity: warning annotations: summary: "{{ $labels.instance }} CPU 使用率过高" description: "CPU 使用率 {{ $value | humanize }}%,已持续5分钟"
- alert: CriticalCPUUsage expr: | 100 - (avg by (instance) ( rate(node_cpu_seconds_total{mode="idle"}[5m]) ) * 100) > 95 for: 2m labels: severity: critical annotations: summary: "🔴 {{ $labels.instance }} CPU 严重告警" description: "CPU 使用率 {{ $value | humanize }}%,需要立即处理"
# ── 内存告警 ──────────────────────────────────────────── - alert: HighMemoryUsage expr: | (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 90 for: 5m labels: severity: warning annotations: summary: "{{ $labels.instance }} 内存使用率过高" description: "内存使用率 {{ $value | humanize }}%"
# ── 磁盘告警 ──────────────────────────────────────────── - alert: DiskUsageHigh expr: | (node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}) / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} * 100 > 85 for: 10m labels: severity: warning annotations: summary: "{{ $labels.instance }} 磁盘空间不足" description: "挂载点 {{ $labels.mountpoint }} 使用率 {{ $value | humanize }}%"
- alert: DiskWillFillIn24h expr: | predict_linear( node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}[6h], 24 * 3600 ) < 0 for: 30m labels: severity: warning annotations: summary: "⚠️ {{ $labels.instance }} 磁盘预计24小时内耗尽" description: "按当前写入速率,{{ $labels.mountpoint }} 将在24小时内写满"
# ── 主机存活 ──────────────────────────────────────────── - alert: InstanceDown expr: up == 0 for: 1m labels: severity: critical annotations: summary: "🔴 {{ $labels.instance }} 已下线" description: "Prometheus 无法连接到 {{ $labels.instance }}"
# ── 系统负载 ──────────────────────────────────────────── - alert: HighSystemLoad expr: node_load5 > count by (instance) (node_cpu_seconds_total{mode="idle"}) * 2 for: 10m labels: severity: warning annotations: summary: "{{ $labels.instance }} 系统负载过高" description: "5分钟负载 {{ $value | humanize }}(CPU 核数 2倍以上)"六、Alertmanager 配置
global: resolve_timeout: 5m # SMTP 配置(全局) smtp_smarthost: "smtp.example.com:587" smtp_from: "alertmanager@example.com" smtp_auth_username: "alertmanager@example.com" smtp_auth_password: "email_password"
# 消息模板templates: - "/etc/alertmanager/templates/*.tmpl"
# 路由树route: receiver: "default" # 默认接收者 group_by: ["alertname", "instance"] group_wait: 30s # 等待同组告警聚合 group_interval: 5m # 同组告警再次发送间隔 repeat_interval: 4h # 相同告警重复发送间隔
routes: # critical 告警发给紧急渠道 - matchers: - severity = "critical" receiver: "wechat-critical" repeat_interval: 30m # 严重告警每30分钟重复
# warning 告警发给普通渠道 - matchers: - severity = "warning" receiver: "telegram-warning"
# 接收者定义receivers: - name: "default" email_configs: - to: "ops-team@example.com" send_resolved: true
# 企业微信机器人 - name: "wechat-critical" webhook_configs: - url: "http://wechat-webhook-adapter:5000/send" send_resolved: true
# Telegram - name: "telegram-warning" telegram_configs: - bot_token: "your_telegram_bot_token" chat_id: -1001234567890 # 群组 chat_id(负数) message: | {{ range .Alerts }} *{{ .Labels.alertname }}* {{ if eq .Status "resolved" }}✅ 已恢复{{ else }}🔴 触发{{ end }} *实例*: {{ .Labels.instance }} *详情*: {{ .Annotations.description }} {{ end }} send_resolved: true
# 抑制规则(critical 触发时,抑制同实例的 warning)inhibit_rules: - source_matchers: - severity = "critical" target_matchers: - severity = "warning" equal: ["instance"]七、Grafana Dashboard 配置
7.1 添加 Prometheus 数据源
- 登录 Grafana → Connections → Data Sources → Add data source
- 选择 Prometheus
- URL 填:
http://prometheus:9090(Docker 网络内访问) - 点击 Save & Test → 看到绿色 ✓
7.2 导入预制 Dashboard
最快的方式是导入社区 Dashboard(grafana.com/dashboards):
| Dashboard | ID | 用途 |
|---|---|---|
| Node Exporter Full | 1860 | 服务器全面监控 |
| Docker + Containers | 893 | Docker 容器监控 |
| Kubernetes Cluster | 7249 | K8s 集群监控 |
| PostgreSQL | 9628 | PostgreSQL 监控 |
| Redis Dashboard | 763 | Redis 监控 |
导入步骤:Dashboards → New → Import → 输入 Dashboard ID → Load → 选择数据源 → Import
7.3 关键面板 PromQL
# Gauge:CPU 使用率(当前值)100 - (avg(rate(node_cpu_seconds_total{mode="idle",instance="$instance"}[5m])) * 100)
# Time series:内存使用趋势node_memory_MemTotal_bytes{instance="$instance"}- node_memory_MemAvailable_bytes{instance="$instance"}
# Stat:磁盘剩余空间node_filesystem_avail_bytes{instance="$instance",mountpoint="/"}
# Table:各挂载点磁盘使用率sort_desc( (node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}) / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"} * 100)八、应用自定义指标(Python 示例)
# pip install prometheus-clientfrom prometheus_client import Counter, Histogram, Gauge, start_http_serverimport timeimport random
# 定义指标http_requests_total = Counter( "http_requests_total", "HTTP 请求总数", ["method", "endpoint", "status_code"])http_request_duration = Histogram( "http_request_duration_seconds", "HTTP 请求延迟", ["method", "endpoint"], buckets=[0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0])active_connections = Gauge( "active_connections", "当前活跃连接数")
# 在 FastAPI 中使用from fastapi import FastAPI, Requestfrom prometheus_client import make_asgi_appimport time
app = FastAPI()
# 将 /metrics 挂载为独立 ASGI 应用metrics_app = make_asgi_app()app.mount("/metrics", metrics_app)
@app.middleware("http")async def prometheus_middleware(request: Request, call_next): start = time.time() active_connections.inc() try: response = await call_next(request) duration = time.time() - start
# 记录请求指标 http_requests_total.labels( method=request.method, endpoint=request.url.path, status_code=response.status_code ).inc() http_request_duration.labels( method=request.method, endpoint=request.url.path ).observe(duration)
return response finally: active_connections.dec()九、常用运维命令
# ── Prometheus ──────────────────────────────────────────────# 热重载配置curl -X POST http://localhost:9090/-/reload
# 检查配置文件语法docker exec prometheus promtool check config /etc/prometheus/prometheus.yml
# 检查告警规则语法docker exec prometheus promtool check rules /etc/prometheus/rules/alerts.yml
# 查看当前 targets 状态curl http://localhost:9090/api/v1/targets | python3 -m json.tool
# ── Alertmanager ────────────────────────────────────────────# 查看当前活跃告警curl http://localhost:9093/api/v2/alerts | python3 -m json.tool
# 热重载curl -X POST http://localhost:9093/-/reload
# ── Grafana ─────────────────────────────────────────────────# 重置 admin 密码docker exec grafana grafana-cli admin reset-admin-password newpassword123
# ── 数据维护 ────────────────────────────────────────────────# 查看 Prometheus 存储大小docker exec prometheus du -sh /prometheus
# 删除指定 metric(需要 --web.enable-admin-api)curl -X POST \ 'http://localhost:9090/api/v1/admin/tsdb/delete_series?match[]={job="test_job"}' \ && curl -X POST http://localhost:9090/api/v1/admin/tsdb/clean_tombstones相关文章:
- Linux 服务器初始化安全配置:买完 VPS 必做的 12 件事
- Docker 完全指南 2026:Compose 多服务编排与生产部署
- Nginx 进阶完全指南 2026:反向代理 + HTTPS + 负载均衡
- Kubernetes 入门完全指南 2026:核心概念 + kubectl + Helm
- PostgreSQL 完全指南 2026:SQL 进阶 + 索引优化 + 分区表
本文基于 Prometheus 2.53 / Grafana 11.1 / Alertmanager 0.27 验证。版本升级时部分配置字段可能变更,以官方文档为准。
Linux 服务器监控完全指南 2026:Prometheus + Grafana + Alertmanager 实战部署
https://971918.xyz/posts/docs/linux-monitoring-guide/