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 一键部署#

docker-compose.yml
# 目录结构:
# 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
Terminal window
# 启动监控栈
docker compose up -d
# 验证各服务
curl http://localhost:9090/-/healthy # Prometheus
curl http://localhost:9100/metrics # Node Exporter(查看原始指标)
curl http://localhost:3000 # Grafana Web UI

三、Prometheus 配置#

prometheus/prometheus.yml
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
Terminal window
# 热重载配置(无需重启)
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 / 1024
rate(node_disk_written_bytes_total[5m]) / 1024 / 1024
# 网络流量(MB/s)
rate(node_network_receive_bytes_total{device!="lo"}[5m]) / 1024 / 1024
rate(node_network_transmit_bytes_total{device!="lo"}[5m]) / 1024 / 1024
# 系统负载
node_load1 # 1分钟负载
node_load5 # 5分钟负载
node_load15 # 15分钟负载
# TCP 连接数
node_netstat_Tcp_CurrEstab

4.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)线性预测预测磁盘何时满

五、告警规则配置#

prometheus/rules/alerts.yml
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 配置#

alertmanager/alertmanager.yml
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 数据源#

  1. 登录 Grafana → Connections → Data Sources → Add data source
  2. 选择 Prometheus
  3. URL 填:http://prometheus:9090(Docker 网络内访问)
  4. 点击 Save & Test → 看到绿色 ✓

7.2 导入预制 Dashboard#

最快的方式是导入社区 Dashboard(grafana.com/dashboards):

DashboardID用途
Node Exporter Full1860服务器全面监控
Docker + Containers893Docker 容器监控
Kubernetes Cluster7249K8s 集群监控
PostgreSQL9628PostgreSQL 监控
Redis Dashboard763Redis 监控

导入步骤: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-client
from prometheus_client import Counter, Histogram, Gauge, start_http_server
import time
import 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, Request
from prometheus_client import make_asgi_app
import 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()

九、常用运维命令#

Terminal window
# ── 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

相关文章

本文基于 Prometheus 2.53 / Grafana 11.1 / Alertmanager 0.27 验证。版本升级时部分配置字段可能变更,以官方文档为准。

Linux 服务器监控完全指南 2026:Prometheus + Grafana + Alertmanager 实战部署
https://971918.xyz/posts/docs/linux-monitoring-guide/
作者
九所长
发布于
2026-08-09
许可协议
CC BY-NC-SA 4.0