Prometheus + Grafana + Loki 全链路监控平台搭建指南(持续更新)
前言
全链路监控是什么?
想象一下:你是一家大型医院的管理者。你需要知道:
- 哪个科室排队最长?(监控指标)
- 哪个医生的诊室有异常?(日志分析)
- 病人从挂号到取药全流程是否顺畅?(链路追踪)
全链路监控就是医院的"智慧大脑",它能帮你:实时看健康状态、快速定位问题、提前发现隐患。
在微服务架构时代,一个请求可能跨越多个服务节点。全链路监控就是让运维工程师能够看清每一个请求的完整旅程,出了问题能快速定位。
本文档会告诉你:
- Prometheus 如何采集和存储指标数据
- Grafana 如何可视化展示监控数据
- Loki 如何存储和查询日志
- 如何搭建完整的监控告警体系
- 如何实现日志溯源
目录
核心概念详解
1. 监控指标(Metrics)
什么是监控指标?
想象一下:你每天早上测体温、量血压、称体重。这些"数字"就是你的身体健康指标。
监控指标就是服务器的"体检报告",用数字告诉你服务器"健不健康"。
三大指标类型:
| 类型 | 通俗解释 | 示例 | 使用场景 |
|---|---|---|---|
| Counter(计数器) | 只增不减的值 | 访问次数、下单数量 | 统计总量 |
| Gauge(仪表) | 可上可下的值 | CPU使用率、内存占用 | 瞬时状态 |
| Histogram(直方图) | 统计分布 | 请求延迟分布 | 分析性能 |
示例:
# 👀 Counter 示例:网站访问次数
# 理解:访问次数只会增加,不会减少
http_requests_total{method="GET", status="200"} 1024
# 👀 Gauge 示例:当前 CPU 使用率
# 理解:CPU使用率会忽高忽低
cpu_usage_percent 45.5
# 👀 Histogram 示例:请求延迟分布
# 理解:记录请求耗时,帮你了解性能分布
http_request_duration_seconds{method="GET", le="0.1"} 850
http_request_duration_seconds{method="GET", le="0.5"} 950
http_request_duration_seconds{method="GET", le="+Inf"} 1000
2. 日志(Logs)
什么是日志?
想象一下:飞机上有个"黑匣子",它记录了飞机飞行过程中的所有对话和操作。出事之后,我们可以通过黑匣子还原发生了什么。
日志就是服务器的"黑匣子",记录了程序运行过程中发生的一切。
日志级别:
| 级别 | 通俗解释 | 严重程度 | 例子 |
|---|---|---|---|
| DEBUG | 详细信息,开发调试用 | 最低 | “进入函数 foo()” |
| INFO | 正常操作记录 | 低 | “用户登录成功” |
| WARNING | 警告,可能有问题 | 中 | “连接超时,重试中” |
| ERROR | 错误,功能受影响 | 高 | “数据库连接失败” |
| FATAL | 致命错误,服务崩溃 | 最高 | “内存不足,服务终止” |
日志格式示例:
# 👀 JSON 格式日志(推荐)
{
"timestamp": "2024-01-15T10:30:00Z",
"level": "ERROR",
"service": "order-service",
"message": "Database connection failed",
"trace_id": "abc123",
"error": "Connection refused"
}
# 👀 普通文本格式
2024-01-15 10:30:00 ERROR [order-service] Database connection failed - trace_id=abc123
3. 链路追踪(Tracing)
什么是链路追踪?
想象一下:你给快递公司打电话问"我的快递到哪了?“,客服说"已经在派送途中了”。但你想知道:从哪里发出的、中间经过了哪些中转站、预计什么时候到。
链路追踪就是"快递追踪系统",能看清请求的完整旅程。
链路追踪核心概念:
| 概念 | 通俗解释 | 类比 |
|---|---|---|
| Trace | 一次完整的请求链路 | 快递的完整物流记录 |
| Span | 请求中的一个步骤 | 快递经过的一个中转站 |
| Parent Span | 上一个步骤 | 上一个中转站 |
| Trace ID | 唯一标识 | 快递单号 |
链路示例:
# 👀 Trace ID = abc123 的请求旅程
Span 1: [网关] 入口 (0ms - 5ms)
Span 2: [认证服务] 验证 (5ms - 20ms)
Span 3: [用户服务] 查询 (20ms - 35ms)
Span 4: [订单服务] 创建 (35ms - 80ms)
Span 5: [库存服务] 扣减 (40ms - 60ms)
Span 6: [支付服务] 扣款 (60ms - 75ms)
4. 三大金刚对比
| 工具 | 职责 | 数据类型 | 特点 |
|---|---|---|---|
| Prometheus | 监控指标采集存储 | Metrics(指标) | 时序数据库、Pull 模式 |
| Grafana | 可视化展示 | 指标/日志/链路 | Dashboard 强大 |
| Loki | 日志存储查询 | Logs(日志) | 低成本、类 SQL 查询 |
三者关系:
Prometheus = 体温计、血压计(测量指标)
Loki = 黑匣子记录(存储日志)
Grafana = 仪表盘(把所有数据可视化)
Prometheus 详解
Prometheus 是什么?
Prometheus 是什么?
想象一下:医院里有很多检测设备(被监控目标),每个设备都能测一些指标。但这些设备不会主动报告,你得一个个去问。
Prometheus 就是医院里的"巡房护士",它会定期到每个设备那里问:"你现在怎么样?"然后把数据记录下来。
核心特点:
| 特点 | 说明 |
|---|---|
| Pull 模式 | Prometheus 主动去拉取数据,而不是等被监控对象上报 |
| 时序数据库 | 专门存储按时间顺序的数据 |
| 多维度数据模型 | 数据有标签(Label),方便筛选 |
| 强大的查询语言 | PromQL,灵活查询数据 |
| 生态丰富 | 各种Exporter,接入各种系统 |
Prometheus 架构
┌─────────────────────────────────────────────────────────────┐
│ Prometheus Server │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Service │ │ Storage │ │ HTTP API │ │
│ │ Discovery │ │ Engine │ │ Server │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ ▲
│ Pull Metrics │
▼ │
┌─────────────────────────────────────────────────────────────┐
│ 被监控目标 (Targets) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Node │ │ MySQL │ │ Nginx │ │ Redis │ │
│ │ Exporter │ │ Exporter │ │ Exporter │ │ Exporter │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
组件说明:
| 组件 | 通俗解释 |
|---|---|
| Service Discovery | 自动发现要监控的目标(就像自动发现新员工入职) |
| Storage Engine | 时序数据库,存储监控数据 |
| HTTP API Server | 提供查询接口 |
| ** exporters** | 适配器,把各种系统的指标转成 Prometheus 格式 |
Prometheus 安装
Docker 方式安装(推荐)
# 👀 创建数据目录
mkdir -p /data/prometheus
# 👀 创建配置文件
cat > /data/prometheus/prometheus.yml << 'EOF'
global:
scrape_interval: 15s # 每15秒采集一次
evaluation_interval: 15s # 每15秒执行一次规则
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
rule_files:
- /etc/prometheus/rules/*.yml
scrape_configs:
# 监控 Prometheus 自己
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
EOF
# 👀 启动 Prometheus
docker run -d \
--name prometheus \
-p 9090:9090 \
-v /data/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus:latest
二进制方式安装
# 👀 下载 Prometheus
wget https://github.com/prometheus/prometheus/releases/download/v2.45.0/prometheus-2.45.0.linux-amd64.tar.gz
# 👀 解压
tar -xzf prometheus-2.45.0.linux-amd64.tar.gz
cd prometheus-2.45.0.linux-amd64
# 👀 创建配置目录
mkdir -p /etc/prometheus /data/prometheus
# 👀 移动二进制文件
mv prometheus /usr/local/bin/
mv promtool /usr/local/bin/
# 👀 配置文件
cat > /etc/prometheus/prometheus.yml << 'EOF'
global:
scrape_interval: 15s
evaluation_interval: 15s
EOF
# 👀 启动 Prometheus
prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /data/prometheus \
--web.enable-lifecycle
Prometheus 配置文件详解
# 👀 prometheus.yml 完整示例
global:
# 全局采集间隔(默认15秒)
scrape_interval: 15s
# 全局规则评估间隔
evaluation_interval: 15s
# 外部标签,所有指标都会带上这个标签
external_labels:
cluster: 'prod'
env: 'beijing'
# 告警管理器配置
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
# 规则文件路径
rule_files:
- /etc/prometheus/rules/*.yml
# 采集目标配置
scrape_configs:
# 👀 示例1:监控 Prometheus 自己
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# 👀 示例2:监控 Linux 服务器(使用 node_exporter)
- job_name: 'linux-servers'
static_configs:
- targets:
- '192.168.1.10:9100'
- '192.168.1.11:9100'
labels:
group: 'web'
# 👀 示例3:监控 MySQL(使用 mysqld_exporter)
- job_name: 'mysql'
static_configs:
- targets: ['192.168.1.20:9104']
# 👀 示例4:服务发现模式(自动发现 Kubernetes)
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__meta_kubernetes_node_name]
target_label: instance
PromQL 查询语言
PromQL 是什么?
就像 SQL 用于查询数据库,PromQL 用于查询 Prometheus 中的监控数据。
基础查询
# 👀 查询所有指标
{__name__=~".+"}
# 👀 查询指标名称(类似 SELECT *)
node_cpu_seconds_total
# 👀 查询特定标签的指标
node_cpu_seconds_total{mode="user"}
# 👀 查询所有 CPU 模式的指标
node_cpu_seconds_total{mode=~".*"}
操作符
# 👀 数学运算:计算 CPU 使用率
# (用户态CPU + 系统态CPU) / 总CPU * 100
(sum(increase(node_cpu_seconds_total{mode!="idle"}[5m])) by (instance) /
sum(increase(node_cpu_seconds_total[5m])) by (instance)) * 100
# 👀 比较运算:找出 CPU 使用率 > 80% 的机器
node_cpu_usage_percent > 80
# 👀 逻辑运算:找出特定服务且 CPU > 50%
node_cpu_usage_percent{service="api"} > 50
聚合函数
# 👀 sum:求和(总请求数)
sum(http_requests_total)
# 👀 avg:平均值(平均响应时间)
avg(http_request_duration_seconds)
# 👀 max:最大值(最大并发数)
max(node_load1)
# 👀 min:最小值
min(node_memory_MemAvailable_bytes)
# 👀 rate:计算增长率(每秒请求数)
rate(http_requests_total[5m])
# 👀 increase:计算增长量
increase(http_requests_total[1h])
时间序列选择器
# 👀 即时向量:当前值
node_cpu_seconds_total
# 👀 范围向量:最近5分钟的值
node_cpu_seconds_total[5m]
# 👀 时间偏移:5分钟前的值
node_cpu_seconds_total offset 5m
常用 Exporter
Exporter 是什么?
想象一下:你不会说外语,但你想和外国人交流。Exporter 就像"翻译官",它把你的系统指标"翻译"成 Prometheus 能理解的语言。
Node Exporter(监控服务器)
# 👀 启动 Node Exporter(监控 Linux 服务器)
docker run -d \
--name node-exporter \
-p 9100:9100 \
prom/node-exporter:latest
# 👀 常用指标
# node_cpu_seconds_total CPU 使用时间
# node_memory_MemAvailable_bytes 可用内存
# node_disk_read_bytes_total 磁盘读取字节
# node_disk_written_bytes_total 磁盘写入字节
# node_network_receive_bytes_total 网络接收字节
# node_network_transmit_bytes_total 网络发送字节
MySQL Exporter
# 👀 先确保 MySQL 有监控用户
docker exec mysql mysql -uroot -proot123 -e "
CREATE USER IF NOT EXISTS 'exporter'@'%' IDENTIFIED BY 'exporter123';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'exporter'@'%';
GRANT SELECT ON performance_schema.* TO 'exporter'@'%';
FLUSH PRIVILEGES;
"
# 👀 启动 MySQL Exporter
docker run -d \
--name mysql-exporter \
-p 9104:9104 \
-e DATA_SOURCE_NAME="exporter:exporter123@(mysql:3306)/" \
prom/mysqld-exporter:latest
Redis Exporter
# 👀 启动 Redis Exporter
docker run -d \
--name redis-exporter \
-p 9121:9121 \
-e REDIS_ADDR="redis:6379" \
-e REDIS_PASSWORD="your_redis_password" \
oliver006/redis_exporter:latest
Nginx Exporter
# 👀 确保 Nginx 已启用 stub_status 模块
# 在 Nginx 配置中添加:
# location /stub_status {
# stub_status on;
# access_log off;
# allow 127.0.0.1;
# deny all;
# }
# 👀 启动 Nginx Exporter
docker run -d \
--name nginx-exporter \
-p 9113:9113 \
nginx/nginx-prometheus-exporter:latest \
-nginx.scrape-uri=http://nginx:80/stub_status
Grafana 详解
Grafana 是什么?
Grafana 是什么?
想象一下:你有很多检测设备,每个都显示一堆数字。这些数字很有用,但看多了头疼。
Grafana 就是"数据可视化大屏",把枯燥的数字变成漂亮的图表,让你一眼就能看出问题在哪里。
核心特点:
| 特点 | 说明 |
|---|---|
| 多数据源支持 | Prometheus、Loki、Elasticsearch 等都能接入 |
| 可视化丰富 | 折线图、仪表盘、热力图、饼图… |
| Dashboard 市场 | 海量现成模板,一键导入 |
| 告警功能 | 可以设置阈值告警 |
| 权限管理 | 支持团队协作 |
Grafana 安装
Docker 方式安装(推荐)
# 👀 启动 Grafana
docker run -d \
--name grafana \
-p 3000:3000 \
-v /data/grafana:/var/lib/grafana \
grafana/grafana:latest
# 👀 默认账号密码
# 用户名:admin
# 密码:admin(首次登录会要求修改)
Grafana 数据源配置
添加 Prometheus 数据源
# 👀 访问 http://localhost:3000
# 1. 点击左侧齿轮图标 ⚙️ → Data Sources
# 2. 点击 "Add data source"
# 3. 选择 "Prometheus"
# 4. 填写配置:
# - URL: http://prometheus:9090
# - Access: Server (default)
# 5. 点击 "Save & Test"
添加 Loki 数据源
# 👀 同上步骤,但在第3步选择 "Loki"
# 配置:
# - URL: http://loki:3100
# - Save & Test
Dashboard 使用
导入 Dashboard
# 👀 方法1:通过 Dashboard ID 导入
# 1. 访问 https://grafana.com/dashboards
# 2. 找到想要的 Dashboard,记住 ID
# 3. 在 Grafana 中:+ → Import → 输入 ID → Load
# 👀 常用 Dashboard 推荐
# Node Exporter: ID 11074 (服务器监控)
# Prometheus: ID 3662 (Prometheus 状态)
# Redis: ID 763 (Redis 监控)
# MySQL Overview: ID 7362 (MySQL 监控)
创建自定义 Dashboard
👀 创建 Dashboard 步骤:
1. 点击左侧 + 图标 → Dashboard
2. 点击 "Add visualization"
3. 选择数据源(Prometheus/Loki)
4. 在 Query 区域编写查询
5. 在右侧 Panel options 设置标题
6. 点击右上角 "Save"
常用 Panel 配置
Panel 1:CPU 使用率
# 👀 查询 CPU 使用率
(sum(increase(node_cpu_seconds_total{mode!="idle"}[5m])) by (instance) /
sum(increase(node_cpu_seconds_total[5m])) by (instance)) * 100
# 👀 设置:
# - Legend: {{instance}}
# - Min: 0, Max: 100
# - Unit: Percent (0-100)
Panel 2:内存使用率
# 👀 查询内存使用率
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
# 👀 设置:
# - Legend: {{instance}}
# - Min: 0, Max: 100
Panel 3:磁盘使用率
# 👀 查询磁盘使用率
(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) / node_filesystem_size_bytes{mountpoint="/"} * 100
Panel 4:网络流量
# 👀 入口流量
rate(node_network_receive_bytes_total[5m])
# 👀 出口流量
rate(node_network_transmit_bytes_total[5m])
Grafana 变量
变量是什么?
就像 Excel 的筛选器,用变量可以让一个 Dashboard 适用于多台服务器。
创建变量步骤:
1. Dashboard Settings → Variables → Add variable
2. 配置变量:
- Name: instance
- Type: Query
- Query: label_values(node_cpu_seconds_total, instance)
3. 在 Panel 中使用:$instance
常用变量语法:
# 👀 所有主机
label_values(node_cpu_seconds_total, instance)
# 👀 所有模式
label_values(node_cpu_seconds_total{mode!="idle"}, mode)
# 👀 动态过滤
# 在查询中使用:node_cpu_seconds_total{instance=~"$instance"}
Loki 日志系统
Loki 是什么?
Loki 是什么?
想象一下:医院每天产生成千上万的病历本(日志),如果把每本病历都完整保存,需要巨大空间。
Loki 就像"病历本索引系统",它不保存完整病历,而是保存:谁(哪个服务)、什么时候(时间戳)、在哪个科室(标签)。当你需要查看详情时,再根据索引去查找。
这样做的好处:成本低、查询快!
Loki vs ELK:
| 对比项 | Loki | ELK (Elasticsearch) |
|---|---|---|
| 存储成本 | 低(日志压缩存储) | 高(完整 JSON 存储) |
| 查询速度 | 快(类 SQL) | 快 |
| 运维复杂度 | 低(Prometheus 生态) | 高(多个组件) |
| 适用场景 | 日志聚合 | 全文搜索 |
Loki 架构
┌─────────────────────────────────────────────────────────────┐
│ Loki 架构 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Promtail │───▶│ Distributor │───▶│ Ingester │ │
│ │ (日志收集) │ │ (日志分发) │ │ (日志写入) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ Chunks │ │
│ │ (存储) │ │
│ └──────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Querier │◀───│ Query │◀───│ Index │ │
│ │ (查询) │ │ Frontend │ │ (索引) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
组件说明:
| 组件 | 通俗解释 |
|---|---|
| Promtail | 日志收集器,类似日志的"快递员" |
| Distributor | 日志分发器,类似"分拣中心" |
| Ingester | 日志写入器,负责把日志写入存储 |
| Querier | 日志查询器,类似"图书管理员" |
| Chunks | 日志数据块,真正存储的地方 |
| Index | 索引,类似"目录" |
Loki 安装
Docker 方式安装(推荐)
# 👀 创建 Loki 配置文件
cat > /data/loki/loki-config.yml << 'EOF'
auth_enabled: false
server:
http_listen_port: 3100
ingester:
lifecycler:
address: 127.0.0.1
ring:
kvstore:
store: inmemory
replication_factor: 1
wal:
enabled: false
chunk_idle_period: 1h
max_chunk_age: 1h
schema_config:
configs:
- from: 2024-01-01
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
storage_config:
boltdb_shipper:
active_index_directory: /loki/index
cache_location: /loki/index_cache
filesystem:
directory: /loki/chunks
limits_config:
reject_old_samples: true
reject_old_samples_max_age: 168h
EOF
# 👀 创建目录
mkdir -p /data/loki
# 👀 启动 Loki
docker run -d \
--name loki \
-p 3100:3100 \
-v /data/loki/loki-config.yml:/etc/loki/loki-config.yml \
-v /data/loki:/loki \
grafana/loki:latest \
-config.file=/etc/loki/loki-config.yml
Promtail 安装(日志收集)
# 👀 创建 Promtail 配置文件
cat > /data/promtail/promtail-config.yml << 'EOF'
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /var/log/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
# 👀 采集 Docker 日志
- job_name: docker
static_configs:
- targets:
- localhost
labels:
job: docker
__path__: /var/lib/docker/containers/*/*.log
# 👀 采集系统日志
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: system
host: ${HOSTNAME}
__path__: /var/log/**/*.log
# 👀 采集 Nginx 日志
- job_name: nginx
static_configs:
- targets:
- localhost
labels:
job: nginx
__path__: /var/log/nginx/*.log
EOF
# 👀 启动 Promtail
docker run -d \
--name promtail \
-p 9080:9080 \
-v /data/promtail/promtail-config.yml:/etc/promtail/promtail-config.yml \
-v /var/run/docker.sock:/var/run/docker.sock \
grafana/promtail:latest \
-config.file=/etc/promtail/promtail-config.yml
Loki 日志查询
LogQL 是什么?
就像 PromQL 用于查询指标,LogQL 用于查询 Loki 中的日志。
基础查询
# 👀 查询所有日志
{job="docker"}
# 👀 按标签筛选
{job="docker", container="nginx"}
# 👀 按内容搜索
{job="docker"} |= "error"
# 👀 多条件搜索
{job="docker"} |= "error" != "timeout"
过滤器
# 👀 | = 包含(AND)
{job="docker"} |= "error"
# 👀 | != 不包含(NOT)
{job="docker"} != "timeout"
# 👀 | | 正则匹配
{job="docker"} |~ "error.*"
# 👀 | __error__ 排除解析错误的行
{job="docker"} != "__error__"
解析日志
# 👀 解析 JSON 格式日志
{job="docker"} | json | level="error"
# 👀 解析带标签的日志
{job="nginx"} | logfmt | status_code="500"
# 👀 使用正则提取
{job="nginx"} | regexp "(?P<ip>\\d+\\.\\d+\\.\\d+\\.\\d+) .*"
与指标结合
# 👀 统计每分钟错误日志数量
count_over_time({job="docker"} |= "error"[1m])
# 👀 统计每秒请求数
rate({job="nginx"}[5m])
# 👀 统计延迟分布
histogram_quantile(0.95,
rate({job="nginx"}[5m])
)
AlertManager 告警配置
AlertManager 是什么?
AlertManager 是什么?
想象一下:医院的监控中心发现某个病人体温异常(告警触发),但它不只是发出警报,还会决定:通知谁?用什么方式通知?通知多次没人接怎么办?
AlertManager 就是 Prometheus 的"告警分发中心",负责把告警发送给正确的人。
告警工作流程:
┌────────────┐ 告警规则 ┌────────────┐ 路由匹配 ┌────────────┐
│ Prometheus │ ──────────────▶ │ AlertManager│ ──────────────▶ │ 接收人 │
│ │ │ │ │ Email/Slack│
│ (触发告警) │ │ (处理告警) │ │ Webhook │
└────────────┘ └────────────┘ └────────────┘
AlertManager 安装
# 👀 创建 AlertManager 配置文件
cat > /data/alertmanager/alertmanager.yml << 'EOF'
global:
smtp_smarthost: 'smtp.gmail.com:587'
smtp_from: 'alert@example.com'
smtp_auth_username: 'alert@example.com'
smtp_auth_password: 'your_password'
route:
group_by: ['alertname', 'severity']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
receiver: 'email'
receivers:
- name: 'email'
email_configs:
- to: 'admin@example.com'
send_resolved: true
- name: 'slack'
slack_configs:
- api_url: 'https://hooks.slack.com/services/XXX'
channel: '#alerts'
send_resolved: true
- name: 'webhook'
webhook_configs:
- url: 'http://webhook:5000/alerts'
send_resolved: true
EOF
# 👀 创建目录
mkdir -p /data/alertmanager
# 👀 启动 AlertManager
docker run -d \
--name alertmanager \
-p 9093:9093 \
-v /data/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml \
prom/alertmanager:latest \
--config.file=/etc/alertmanager/alertmanager.yml
Prometheus 告警规则
# 👀 prometheus-rules.yml
groups:
- name: node_alerts
interval: 30s
rules:
# 👀 CPU 使用率过高
- alert: HighCPUUsage
expr: |
(sum(increase(node_cpu_seconds_total{mode!="idle"}[5m])) by (instance) /
sum(increase(node_cpu_seconds_total[5m])) by (instance)) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "CPU 使用率过高"
description: "实例 {{ $labels.instance }} 的 CPU 使用率已超过 80% (当前: {{ $value }}%)"
# 👀 内存使用率过高
- alert: HighMemoryUsage
expr: |
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "内存使用率过高"
description: "实例 {{ $labels.instance }} 的内存使用率已超过 85%"
# 👀 磁盘空间不足
- alert: DiskSpaceLow
expr: |
(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) /
node_filesystem_size_bytes{mountpoint="/"} * 100 > 90
for: 5m
labels:
severity: critical
annotations:
summary: "磁盘空间不足"
description: "实例 {{ $labels.instance }} 的根分区使用率已超过 90%"
# 👀 服务宕机
- alert: TargetDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "目标服务宕机"
description: "{{ $labels.instance }} 已离线超过 1 分钟"
告警路由配置
# 👀 告警路由示例:根据严重程度发送给不同的人
route:
# 按严重程度分组
group_by: ['alertname', 'severity']
# 等待时间(避免告警风暴)
group_wait: 10s
group_interval: 10s
# 重复告警间隔
repeat_interval: 12h
# 默认接收者
receiver: 'default-receiver'
# 路由树
routes:
# critical 级别:立即通知
- match:
severity: critical
receiver: 'critical-receiver'
group_wait: 0s
repeat_interval: 1h
# warning 级别:普通通知
- match:
severity: warning
receiver: 'warning-receiver'
# 特定告警:发给特定团队
- match:
service: database
receiver: 'database-team'
receivers:
- name: 'default-receiver'
# ...
- name: 'critical-receiver'
slack_configs:
- channel: '#critical-alerts'
email_configs:
- to: 'oncall@example.com'
webhook_configs:
- url: 'http://pagerduty:8090/signals/nalice'
- name: 'warning-receiver'
slack_configs:
- channel: '#warnings'
Docker Compose 一键部署
docker-compose.yml
# 👀 创建 docker-compose.yml
cat > /data/monitoring/docker-compose.yml << 'EOF'
version: '3.8'
services:
# 👀 Prometheus:指标采集存储
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- ./prometheus/rules:/etc/prometheus/rules
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.enable-lifecycle'
networks:
- monitoring
# 👀 AlertManager:告警管理
alertmanager:
image: prom/alertmanager:latest
container_name: alertmanager
ports:
- "9093:9093"
volumes:
- ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml
networks:
- monitoring
# 👀 Grafana:可视化展示
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=admin123
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
networks:
- monitoring
# 👀 Loki:日志存储
loki:
image: grafana/loki:latest
container_name: loki
ports:
- "3100:3100"
volumes:
- ./loki/loki-config.yml:/etc/loki/loki-config.yml
- loki_data:/loki
command: -config.file=/etc/loki/loki-config.yml
networks:
- monitoring
# 👀 Promtail:日志收集
promtail:
image: grafana/promtail:latest
container_name: promtail
volumes:
- ./promtail/promtail-config.yml:/etc/promtail/promtail-config.yml
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
command: -config.file=/etc/promtail/promtail-config.yml
networks:
- monitoring
# 👀 Node Exporter:服务器监控
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
ports:
- "9100:9100"
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
networks:
- monitoring
networks:
monitoring:
driver: bridge
volumes:
prometheus_data:
grafana_data:
loki_data:
EOF
启动监控平台
# 👀 创建目录
mkdir -p /data/monitoring/{prometheus/{rules},alertmanager,loki,promtail,grafana/provisioning}
# 👀 启动所有服务
cd /data/monitoring
docker-compose up -d
# 👀 查看服务状态
docker-compose ps
# 👀 查看日志
docker-compose logs -f
访问地址
| 服务 | 地址 | 默认账号 |
|---|---|---|
| Grafana | http://localhost:3000 | admin / admin123 |
| Prometheus | http://localhost:9090 | - |
| AlertManager | http://localhost:9093 | - |
| Loki | http://localhost:3100 | - |
| Node Exporter | http://localhost:9100/metrics | - |
实战案例
案例 1:监控 Nginx
步骤 1:确保 Nginx 开启 stub_status
# 👀 在 Nginx 配置中添加
server {
listen 80;
server_name localhost;
# 👀 启用状态监控
location /stub_status {
stub_status on;
access_log off;
# 只允许本地访问
allow 127.0.0.1;
deny all;
}
}
步骤 2:重启 Nginx
# 👀 测试配置
nginx -t
# 👀 重载配置
nginx -s reload
步骤 3:配置 Prometheus
# 👀 prometheus.yml 添加
scrape_configs:
- job_name: 'nginx'
static_configs:
- targets: ['nginx:80']
metrics_path: /stub_status
步骤 4:Prometheus 查询
# 👀 Nginx 活跃连接数
nginx_connections_active
# 👀 Nginx 已处理的连接数
nginx_connections_handled
# 👀 每秒请求数
rate(nginx_connections_handled[5m])
步骤 5:创建 Grafana Dashboard
👀 Dashboard 配置示例:
Panel 1: 活跃连接数
- Query: nginx_connections_active
- Visualization: Stat
Panel 2: 每秒请求数
- Query: rate(nginx_connections_handled[5m])
- Visualization: Time series
Panel 3: 连接状态分布
- Query: nginx_connections_active by (state)
- Visualization: Pie chart
案例 2:监控 MySQL
步骤 1:创建监控用户
# 👀 在 MySQL 中执行
CREATE USER IF NOT EXISTS 'exporter'@'%' IDENTIFIED BY 'exporter123' WITH MAX_USER_CONNECTIONS 3;
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'exporter'@'%';
GRANT SELECT ON performance_schema.* TO 'exporter'@'%';
FLUSH PRIVILEGES;
步骤 2:启动 MySQL Exporter
# 👀 docker-compose.yml 添加
mysql-exporter:
image: prom/mysqld-exporter:latest
container_name: mysql-exporter
environment:
- DATA_SOURCE_NAME="exporter:exporter123@(mysql:3306)/"
networks:
- monitoring
步骤 3:Prometheus 查询
# 👀 QPS(每秒查询数)
rate(mysql_global_status_questions[5m])
# 👀 连接数使用率
(mysql_global_status_threads_connected / mysql_global_variables_max_connections) * 100
# 👀 慢查询数
rate(mysql_global_status_slow_queries[5m])
# 👀 InnoDB 缓存命中率
(mysql_global_status_innodb_row_lock_waits / mysql_global_status_innodb_rows_read) * 100
案例 3:Loki 日志聚合
场景:追踪用户登录错误
步骤 1:查看错误日志
# 👀 LogQL 查询
{job="app"} |= "login" |= "error"
# 👀 统计每分钟错误数
count_over_time({job="app"} |= "error"[1m])
步骤 2:关联 Trace ID
# 👀 查询特定 Trace ID 的所有日志
{job="app"} |= "trace_id=abc123"
# 👀 查看错误前后的日志
{job="app"} | json | trace_id="abc123"
步骤 3:Grafana Explore 联动
👀 Grafana Explore 使用步骤:
1. 点击左侧 Explore 图标
2. 选择 Loki 数据源
3. 输入查询:
{job="app"} |= "error"
4. 选择时间范围
5. 点击 Log browser 查看完整日志
6. 点击某条日志,选择 "Show in metrics" 关联指标
常见问题排查
问题 1:Prometheus 无法采集到数据
现象: Prometheus 页面能看到 targets,但指标显示"No data"
排查步骤:
# 👀 1. 检查 target 是否 up
# 访问 http://prometheus:9090/targets
# 👀 2. 检查 Exporter 是否正常运行
docker ps | grep exporter
# 👀 3. 检查 Exporter 指标接口
curl localhost:9100/metrics | head -20
# 👀 4. 检查 Prometheus 日志
docker logs prometheus | grep -i error
解决方案:
| 可能原因 | 解决方法 |
|---|---|
| Exporter 未启动 | docker-compose up -d exporter-name |
| 端口不通 | 检查防火墙/容器网络 |
| 配置错误 | 检查 prometheus.yml 的 targets |
| 指标路径错误 | 确认 metrics_path 配置 |
问题 2:Grafana Dashboard 显示"No data"
现象: Dashboard 创建成功但没有数据显示
排查步骤:
👀 排查顺序:
1. 检查数据源配置
- Grafana → Configuration → Data Sources → 选择 Prometheus → Test
2. 检查 Query 是否正确
- 在 Explore 中手动执行 Query
3. 检查时间范围
- 确认选择了正确的时间范围
4. 检查变量配置
- 确认变量 Query 能返回数据
解决方案:
# 👀 测试 Prometheus Query
curl 'http://localhost:9090/api/v1/query?query=up'
# 👀 测试 Prometheus Targets
curl 'http://localhost:9090/api/v1/targets'
问题 3:AlertManager 告警没收到
现象: 告警触发但没收到通知
排查步骤:
# 👀 1. 检查 AlertManager 状态
curl http://localhost:9093/api/v1/status
# 👀 2. 查看 AlertManager 日志
docker logs alertmanager
# 👀 3. 查看 Prometheus 告警规则
curl http://prometheus:9090/api/v1/rules | jq '.data.groups[].rules[] | select(.type=="alerting")'
# 👀 4. 查看未发送的告警
curl http://localhost:9093/api/v1/alerts | jq '.data[]
解决方案:
| 可能原因 | 解决方法 |
|---|---|
| 告警规则未触发 | 检查 for 时间窗口 |
| 路由配置错误 | 检查 alertmanager.yml 的 route |
| 通知渠道配置错误 | 检查 receiver 配置 |
| 网络问题 | 检查邮件/Slack 配置 |
问题 4:Loki 查询不到日志
现象: 日志查询返回空结果
排查步骤:
# 👀 1. 检查 Promtail 是否运行
docker logs promtail
# 👀 2. 检查 Loki 是否正常接收
curl http://localhost:3100/loki/api/v1/label | jq
# 👀 3. 检查 Promtail 配置
cat /data/promtail/promtail-config.yml
# 👀 4. 查看 Promtail 发现的目标
docker exec promtail promtail --dry-run --config.file=/etc/promtail/promtail-config.yml
解决方案:
| 可能原因 | 解决方法 |
|---|---|
| 日志文件路径错误 | 确认 path 配置正确 |
| 权限问题 | 检查日志文件读取权限 |
| 标签过滤错误 | 确认标签值正确 |
| 时间范围错误 | 扩大时间查询范围 |
问题 5:监控服务启动失败
现象: Docker Compose 启动失败
排查步骤:
# 👀 1. 查看所有容器状态
docker-compose ps
# 👀 2. 查看失败容器的日志
docker-compose logs service-name
# 👀 3. 检查配置文件语法
docker-compose config
# 👀 4. 清理后重新启动
docker-compose down
docker-compose up -d
总结
全链路监控架构
┌─────────────────────────────────────────────────────────────┐
│ 全链路监控平台 │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Prometheus │◀──│ Grafana │──▶│ AlertManager│ │
│ │ (指标存储) │ │ (可视化) │ │ (告警) │ │
│ └──────┬──────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Loki │ │ Promtail │ │ Exporters │ │
│ │ (日志存储) │◀──│ (日志收集) │──▶│ (被监控目标) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
核心要点
| 组件 | 职责 | 关键配置 |
|---|---|---|
| Prometheus | 指标采集存储 | scrape_configs, PromQL |
| Grafana | 可视化展示 | Dashboard, Panel |
| Loki | 日志聚合 | LogQL, Promtail |
| AlertManager | 告警分发 | route, receiver |
| Exporters | 指标暴露 | 各种_exporter |
黄金法则
- 先跑起来再说 - 先用 Docker Compose 部署,再按需优化
- 从下往上排查 - 指标/日志/链路,层层定位问题
- 告警要克制 - 告警太多等于没告警,只告真正重要的
- Dashboard 要简洁 - 一个 Dashboard 只展示一类信息
持续更新中… 如有问题或建议,欢迎交流讨论!
评论区