传统监控方案在扩展性上存在明显局限,难以满足云原生环境对多维标签监控的需求。Prometheus 凭借多维数据模型、强大的 PromQL 查询语言、主动拉取机制以及丰富的 Exporter 生态,原生支持 Kubernetes,已然成为云原生监控领域的主流方案。
架构与组件方面,Prometheus 监控体系的整体架构由以下核心组件协同构成:
- Prometheus Server:负责采集与存储监控数据,并执行规则计算;
- Exporters:负责暴露系统与业务指标,如 node_exporter、Spring Boot Actuator、Nginx Exporter;
- Alertmanager:负责告警的去重、分组与路由分发;
- Grafana:负责监控数据的可视化展示;
- Pushgateway:用于短生命周期任务的指标推送;
- Service Discovery:负责动态发现监控目标,支持静态文件、Consul、Kubernetes 等多种方式。
官方架构图:

本文主要介绍容器化部署方案,各工具的详细使用将在后续篇章中详细介绍。
一、创建默认桥接网络
相同容器使用同一网络时,相互间可直接通过容器名访问,也可减少对外暴露的端口。
创建默认桥接网络:
bash
docker network create -d bridge my-bridge
二、Prometheus 搭建
1、prometheus.yml
文件默认位置:/etc/prometheus/prometheus.yml
bash
# my global config
global:
scrape_interval: 10s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 10s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ["127.0.0.1:9090"]
# The label name is added as a label `label_name=<label_value>` to any timeseries scraped from this config.
labels:
svc: "prometheus"
- job_name: "cim"
metrics_path: /metrics
relabel_configs:
- source_labels: [__address__]
target_label: instance
file_sd_configs:
- files:
- scrape/cim-local.yml
refresh_interval: 5s
cim-local.yml
bash
- targets:
- 10.0.2.15:9100
labels:
svc: nodb
type: node
- targets:
- 10.0.2.15:8082
labels:
svc: nodb
type: jvm
__metrics_path__: "/actuator/prometheus"
2、修改宿主机数据目录权限
确认容器运行用户
bash
# 容器已存在时
$ docker exec -it prom id
# 还没有容器,直接通过镜像查看
$ docker run -it --name prometheus --rm --entrypoint /bin/sh prom/prometheus:v3
/prometheus $ id
uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
# 更简洁写法
$ docker run -it --rm --entrypoint id prom/prometheus:v3
uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
输出一般是
uid=65534(nobody)或者uid=1001。
修改宿主机数据目录权限
假设将宿主机目录
/data/volumes/prometheus/data映射到容器内/prometheus
bash
# 方式A:修改目录属主为prometheus运行uid,示例uid=65534
$ sudo chown -R 65534:65534 /data/volumes/prometheus
# 方式B:宽松权限(测试环境可用,生产优先chown)
$ sudo chmod -R 775 /data/volumes/prometheus
若不修改,很可能出现如下报错:
bash
open /prometheus/queries.active: permission denied
failed to initialize active query tracker
3、启动服务
bash
docker run -d --name prometheus \
--restart=always \
--network my-bridge \
-p 9090:9090 \
-e TZ="Asia/Shanghai" \
-v /data/volumes/prometheus:/etc/prometheus \
-v /data/volumes/prometheus/data:/prometheus \
prom/prometheus:v3 \
--config.file=/etc/prometheus/prometheus.yml \
--web.enable-lifecycle
注意:
添加
--web.enable-lifecycle参数时,一定要显式指定--config.file
4、验证配置文件是否正确
调整配置文件后,先验证配置是否正确,避免因配置问题导致服务异常。
验证通过后再重新加载配置。
bash
$ docker exec -it prometheus promtool check config /etc/prometheus/prometheus.yml
Checking /etc/prometheus/prometheus.yml
SUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntax
5、热加载配置
bash
$ curl -XPOST http://127.0.0.1:9090/-/reload
Lifecycle API is not enabled.
出于安全考虑,HTTP 重载接口默认不启用,需要先在启动命令中添加 --web.enable-lifecycle 参数,才能开启 /-/reload 接口。接口开启后,向 /-/reload 发送 HTTP POST 请求即可触发配置重载。
6、单节点资源配置参考
| 监控规模 | 建议监控的 Spring Boot 应用数 | CPU (核心) | 内存 (RAM) | SSD 存储 | 适用场景与说明 | | --- | --- | --- | --- | --- | --- | | 中小规模生产 | 5 - 25 个 | 2 - 4 核 | 4 - 8 GB | 50 - 100 GB | 适合小型团队或轻量级生产环境。数据保留建议 30 天。 | | 大规模生产 | 25 - 100+ 个 | 4 - 8+ 核 | 8 - 32+ GB | 100 - 500+ GB | 适合较大规模的监控需求。数据保留可根据需要设置为 30-90 天。 | | 高性能/极限场景 | 约 500 个 (估算) | 8+ 核 | 32+ GB | 1+ TB | 这是一个理论上限,前提是每个应用指标数较少且采集间隔较长(如 15s)。单节点 Prometheus 理论可支持千级监控目标。 |
⚠️ 注意:监控自身 :务必监控 Prometheus 容器自身的资源使用情况,特别是 process_resident_memory_bytes(内存占用)和磁盘使用率。
7、几个核心概念
为方便对后续篇章的理解,请提前熟悉以下概念,并注意相互间的区别。
1)数据模型
| 概念 | 说明 | 示例/格式 | 关键点 | | --- | --- | --- | --- | | 指标 Metric | 表示"测什么" | http_requests_total | 指标名是时间序列的一部分 | | 标签 Label | 键值对,用于多维区分 | method="GET", status="200" | 标签组合决定时间序列的唯一性 | | 时间序列 Time Series | 指标名 + 一组标签唯一确定一条序列 | http_requests_total{method="GET", status="200"} | 同一指标不同标签就是不同序列 | | 样本 Sample | 时间序列在某个时间点的值 | <时间戳(ms)> <值>,如 1710000000000 1027 | Prometheus 实际存储的是"序列 + 时间戳 + 值" | | 抓取文本格式 | /metrics 暴露的文本格式 | http_requests_total{method="GET"} 1027 | 时间戳通常省略,由服务端补当前时间 |
2)采集与目标
| 概念 | 说明 | 示例 | 关键点 | | --- | --- | --- | --- | | Target | 被采集的目标 | 10.0.0.1:9100 | Prometheus 主动拉取目标 /metrics | | Scrape | 一次抓取行为 | 按 scrape_interval 周期执行 | 默认 15s,可在 global 配置 | | Job | 一组同类目标的逻辑名称 | job_name: node | 来自 scrape_configs | | Instance | 具体目标地址 | instance="10.0.0.1:9100" | 抓取时自动附加 job 和 instance 标签 |
三、Grafana 搭建
启动服务
bash
docker run -d --name=grafana \
--restart=no \
--network my-bridge \
-p 3000:3000 \
-e TZ="Asia/Shanghai" \
-e GF_USERS_DEFAULT_TIMEZONE=Asia/Shanghai \
-v /data/volumes/grafana:/var/lib/grafana \
grafana/grafana:13.0.7-ubuntu
若需要导出图片,请参考《Grafana 开源版导出 Dashboard PDF 教程:Docker 部署 Image Renderer 完整指南》
四、Alertmanager
1、alertmanager.yml
bash
# Alertmanager 配置示例
# 覆盖:邮件 / Slack / 企业微信 三类接收器
# 路由策略:
# 1. 先按 job 分组,不同系统(job)的告警聚合在一起
# 2. 子路由再按 severity 分发:Warning → 邮件,Critical → 企业微信
# 3. Slack 作为全量告警的备选/备份通道
# 使用方式:替换 <占位符> 后,挂载到 Alertmanager 的 --config.file 路径
global:
# SMTP 全局配置(邮件)
smtp_smarthost: 'smtp.aliyun.com:465'
smtp_from: '*****@aliyun.com'
smtp_auth_username: '*****@aliyun.com'
smtp_auth_password: '123456'
smtp_require_tls: false
# Slack 全局配置
slack_api_url: 'https://hooks.slack.com/services/T0BM91K2H2P/B0BMBUKN40M/th4U2ouK2lGzSCeye'
# 抑制重复告警
resolve_timeout: 5m
# 通知模板(可选,自定义标题和内容格式)
templates:
- '/etc/alertmanager/templates/*.tmpl'
# 路由树:先按 job 分组,子路由按 severity 分发
route:
# 根路由:按 job 分组,同一系统的告警聚合在一起
group_by: ['job']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default'
routes:
# ============================================================
# VM
# ============================================================
- matchers:
- job = "vm"
group_by: ['job']
group_wait: 1m
group_interval: 10m
repeat_interval: 1h
receiver: 'slack-all'
continue: false
# ============================================================
# 接收器定义
# ============================================================
receivers:
# 默认兜底接收器
- name: 'default'
email_configs:
- to: '******@aliyun.com'
headers:
Subject: '[Prometheus][{{ .GroupLabels.severity }}] {{ .GroupLabels.job }} 告警'
html: |
{{ range .Alerts }}
<b>告警名称:</b> {{ .Labels.alertname }}<br>
<b>Job:</b> {{ .Labels.job }}<br>
<b>Svc:</b> {{ .Labels.svc }}<br>
<b>Instance:</b> {{ .Labels.instance }}<br>
<b>级别:</b> {{ .Labels.severity }}<br>
<b>摘要:</b> {{ .Annotations.summary }}<br>
<b>描述:</b> {{ .Annotations.description }}<br>
<b>开始时间:</b> {{ .StartsAt.Format "2006-01-02 15:04:05" }}<br>
<hr>
{{ end }}
# -------------------- Slack 接收器 --------------------
- name: 'slack-all'
slack_configs:
- channel: '#ph'
username: 'Alertmanager'
icon_emoji: ':warning:'
title: |
[{{ .Status | toUpper }}] {{ .GroupLabels.job }} - {{ .GroupLabels.severity }}
text: |
{{ range .Alerts }}
*Alert:* {{ .Labels.alertname }}
*Job:* {{ .Labels.job }}
*Svc:* {{ .Labels.svc }}
*Instance:* {{ .Labels.instance }}
*Severity:* {{ .Labels.severity }}
*Summary:* {{ .Annotations.summary }}
*Description:* {{ .Annotations.description }}
*Started:* {{ .StartsAt.Format "2006-01-02 15:04:05" }}
{{ end }}
# ============================================================
# 抑制规则:Critical 触发时抑制同 job+instance 的 Warning(避免轰炸)
# ============================================================
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['job', 'instance']
2、启动服务
bash
docker run -d --name alertmanager \
--rm \
--restart=no \
--network my-bridge \
-p 9093:9093 \
-e TZ=Asia/Shanghai \
-v /data/volumes/alertmanager:/etc/alertmanager \
prom/alertmanager:v0.33.1
配置文件位置:/etc/alertmanager/alertmanager.yml。
3、验证配置文件是否正确
调整配置文件后,先验证配置是否正确,避免因配置问题导致服务异常。
验证通过后再重新加载配置。
bash
$ docker exec -it alertmanager amtool check-config /etc/alertmanager/alertmanager.yml
Checking '/etc/alertmanager/alertmanager.yml' SUCCESS
Found:
- global config
- route
- 1 inhibit rules
- 2 receivers
- 1 templates
SUCCESS
- 输出
SUCCESS= yaml 语法、路由、接收器、抑制规则全部校验通过 - 若有错误,会直接打印行号和错误原因,并以非 0 退出码退出。
- 如果用到模板文件,会一并校验模板。
4、热加载配置
bash
curl -XPOST http://127.0.0.1:9093/-/reload
五、Docker Compose 方式部署
注意:
docker-compose:独立二进制旧版本,Python 编写docker compose:Docker Engine 内置插件(推荐,无短横线),Go 编写,用法基本一致
Docker 19.03 版本开始引入
docker compose命令作为一项实验性功能。Docker 20.10 及更高版本开始被广泛认为"自动集成了 Compose"。
Docker 22.06+ 版本明确内置了
docker compose插件。
1、docker-compose.yml 文件示例
bash
services:
prometheus:
image: prom/prometheus:v3
container_name: prometheus
restart: always
networks:
- my-bridge
ports:
- "9090:9090"
environment:
- TZ="Asia/Shanghai"
volumes:
- /data/volumes/prometheus:/etc/prometheus
- /data/volumes/prometheus/data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--web.enable-lifecycle'
grafana:
image: grafana/grafana:13.0.7-ubuntu
container_name: grafana
restart: no
networks:
- my-bridge
ports:
- "3000:3000"
environment:
- TZ="Asia/Shanghai"
- GF_USERS_DEFAULT_TIMEZONE=Asia/Shanghai
volumes:
- /data/volumes/grafana:/var/lib/grafana
alertmanager:
image: prom/alertmanager:v0.33.1
container_name: alertmanager
restart: no
networks:
- my-bridge
ports:
- "9093:9093"
environment:
- TZ="Asia/Shanghai"
volumes:
- /data/volumes/alertmanager:/etc/alertmanager
networks:
my-bridge:
external: true
2、启动服务
bash
$ docker compose up -d
[+] up 3/3
✔ Container grafana Created 1.3s
✔ Container alertmanager Created 1.2s
✔ Container prometheus Created 1.2s
基础操作
bash
# 启动所有服务(后台运行,推荐)
docker compose up -d
# 启动并打印日志(前台)
docker compose up
# 重启指定服务
docker compose restart 服务名
# 停止服务,不删除容器、网络、卷
docker compose stop
# 启动已停止的服务
docker compose start
# 停止并删除容器、网络(保留数据卷)
docker compose down
# 停止并删除容器、网络、数据卷(⚠️会丢数据)
docker compose down -v