DevOps 四大支柱的最后一根:监控(Monitoring)和可观测性(Observability)。前 8 课教你构建和部署,这一课教你知道系统还活着。
| 层次 | 回答什么问题 | 工具 |
|---|---|---|
| Metrics(指标) | 「系统整体怎么样?」CPU、内存、请求速率、错误率 | Prometheus |
| Logs(日志) | 「具体发生了什么?」某次请求的详细信息、错误堆栈 | Loki / ELK |
| Traces(链路追踪) | 「一个请求经过了哪些服务?」微服务间的调用链 | Jaeger / Tempo |
这节课聚焦 Metrics——最基础也最重要的监控层。学会 Metrics,你就覆盖了 80% 的日常监控需求。
你的服务器 ──→ Node Exporter(采集系统指标)
你的应用 ──→ 暴露 /metrics 端点
↓ scrape(定期抓取)
Prometheus(存储 + 查询)
↓ 数据源
Grafana(可视化仪表盘 + 告警)
mkdir /tmp/monitoring && cd /tmp/monitoring
cat > docker-compose.yml << 'EOF'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prom_data:/prometheus
ports:
- "9090:9090"
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
ports:
- "9100:9100"
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
volumes:
prom_data:
grafana_data:
EOF
cat > prometheus.yml << 'EOF'
global:
scrape_interval: 15s # 每 15 秒抓一次
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node'
static_configs:
- targets: ['node-exporter:9100'] # Docker 内部 DNS
EOF
docker compose up -d
# 验证
curl http://localhost:9090 # Prometheus UI
curl http://localhost:9100/metrics | head -20 # 裸指标数据(看着吓人但不用你读)
curl http://localhost:3000 # Grafana(admin / admin)
打开 http://localhost:9090,在 Graph 标签页里试试这些查询:
# CPU 使用率(所有核心平均)
rate(node_cpu_seconds_total{mode="user"}[5m]) * 100
# 内存使用百分比
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
# 磁盘可用空间(GB)
node_filesystem_avail_bytes / 1024 / 1024 / 1024
# 网络接收速率(bytes/sec)
rate(node_network_receive_bytes_total[5m])
| PromQL 函数 | 作用 |
|---|---|
rate(metric[5m]) | 计算 5 分钟内的每秒增长率(最常用) |
avg(metric) | 平均值 |
sum(metric) | 求和 |
{job="node"} | 按 job 标签过滤 |
> 80 | 只显示值大于 80 的 |
打开 http://localhost:3000(admin/admin),三步创建仪表盘:
http://prometheus:9090 → Save & test1860(Node Exporter Full 模板 ID)→ 选 Prometheus 数据源 → Import监控让你能看到问题。告警让问题来找你。
# alert.rules.yml(放在 prometheus.yml 同目录,在 prometheus.yml 里引用它)
groups:
- name: node-alerts
rules:
- alert: HighCPUUsage
expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m # 持续 5 分钟才告警(防止抖动)
labels:
severity: warning
annotations:
summary: "High CPU usage on {{ $labels.instance }}"
description: "CPU usage is {{ $value }}% for 5 minutes"
- alert: DiskAlmostFull
expr: (node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 < 10
for: 1m
labels:
severity: critical
annotations:
summary: "Disk almost full on {{ $labels.instance }}"
description: "Only {{ $value }}% space left"
告警可以推到 Slack、钉钉、邮件、PagerDuty。在 Grafana 里也能配告警——但 Prometheus Alertmanager 更专业(去重、分组、静默、升级)。
Node Exporter 监控的是服务器。你自己的应用也需要暴露指标:
// Node.js 示例:用 prom-client 库
const prometheus = require('prom-client');
const http = require('http');
// 创建一个计数器:记录 HTTP 请求总数
const httpRequestsTotal = new prometheus.Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'status']
});
// 在你的请求处理里
app.use((req, res, next) => {
res.on('finish', () => {
httpRequestsTotal.inc({ method: req.method, status: res.statusCode });
});
next();
});
// 暴露 /metrics 端点(Prometheus 来 scrape 这个端点)
app.get('/metrics', async (req, res) => {
res.set('Content-Type', prometheus.register.contentType);
res.end(await prometheus.register.metrics());
});
然后在 prometheus.yml 里加一个 scrape target 指向你的应用端口,Prometheus 就开始收集你的业务指标了。