侧边栏壁纸
  • 累计撰写 16 篇文章
  • 累计创建 1 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Prometheus + Grafana + Loki 全链路监控平台搭建指南(持续更新)

Prometheus + Grafana + Loki 全链路监控平台搭建指南(持续更新)

前言

全链路监控是什么?

想象一下:你是一家大型医院的管理者。你需要知道:

  • 哪个科室排队最长?(监控指标)
  • 哪个医生的诊室有异常?(日志分析)
  • 病人从挂号到取药全流程是否顺畅?(链路追踪)

全链路监控就是医院的"智慧大脑",它能帮你:实时看健康状态、快速定位问题、提前发现隐患。

在微服务架构时代,一个请求可能跨越多个服务节点。全链路监控就是让运维工程师能够看清每一个请求的完整旅程,出了问题能快速定位。

本文档会告诉你:

  • Prometheus 如何采集和存储指标数据
  • Grafana 如何可视化展示监控数据
  • Loki 如何存储和查询日志
  • 如何搭建完整的监控告警体系
  • 如何实现日志溯源

目录

  1. 核心概念详解
  2. Prometheus 详解
  3. Grafana 详解
  4. Loki 日志系统
  5. AlertManager 告警配置
  6. Docker Compose 一键部署
  7. 实战案例
  8. 常见问题排查

核心概念详解

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

黄金法则

  1. 先跑起来再说 - 先用 Docker Compose 部署,再按需优化
  2. 从下往上排查 - 指标/日志/链路,层层定位问题
  3. 告警要克制 - 告警太多等于没告警,只告真正重要的
  4. Dashboard 要简洁 - 一个 Dashboard 只展示一类信息

持续更新中… 如有问题或建议,欢迎交流讨论!

0

评论区