【Prometheus+Grafana实战:搭建监控系统(含告警配置)】
什么是Prometheus和Grafana?
- Prometheus:一款开源的监控告警工具,擅长时序数据存储和多维度查询(通过PromQL),采用Pull模型主动抓取目标指标。
- Grafana:数据可视化平台,支持多种数据源(如Prometheus),通过丰富的仪表盘展示监控数据。
- 核心协作流程:
- Exporters(如Node Exporter)采集指标 → Prometheus存储并计算 → Grafana可视化展示 → Alertmanager触发告警。
监控系统核心流程:
- 数据采集
📥 Exporters(如node_exporter
、mysqld_exporter
)从目标系统(主机、MySQL等)收集指标。 - 数据存储与计算
🗃️ Prometheus 定期从 Exporters 拉取(Pull) 数据,存储为时序数据,并通过 PromQL 进行实时计算。 - 可视化展示
📊 Grafana 从 Prometheus 读取数据,通过预定义仪表盘(如ID 1860)展示监控图表。 - 告警触发与通知
🔔 Prometheus 根据告警规则(如CPU > 85%)触发告警 → Alertmanager 分组、路由告警 → 通过邮件/Slack通知用户。
与Zabbix的对比与优势
- 数据模型:Prometheus的多维标签比Zabbix的扁平键值更灵活。
- 扩展性:通过Exporters轻松集成新系统,无需定制脚本。
- 云原生支持:天然适配Kubernetes,适合容器化环境。
建议从监控主机和现有Docker服务入手,逐步扩展至MySQL、Tomcat,最终实现全栈监控+告警闭环。
组件介绍
1、数据采集类(Exporters)
组件名称 | 核心功能 | 适用场景 | 官方文档 |
---|---|---|---|
Node Exporter | 采集主机基础指标(CPU、内存、磁盘、网络等) | 监控物理机/虚拟机性能 | GitHub |
cAdvisor | 采集容器资源使用指标(CPU、内存、网络、文件系统) | 监控 Docker 容器 | GitHub |
MySQL Exporter | 采集 MySQL 数据库性能指标(查询数、连接数等) | 监控 MySQL 数据库状态 | GitHub |
JMX Exporter | 将 Java 应用的 JMX 指标转换为 Prometheus 格式 | 监控 Tomcat、Kafka 等 Java 应用 | GitHub |
Blackbox Exporter | 通过 HTTP/HTTPS、TCP、ICMP 探测服务可用性 | 监控网站可用性、端口存活状态 | GitHub |
SNMP Exporter | 采集网络设备(交换机、路由器)的 SNMP 指标 | 监控网络设备性能 | GitHub |
- cAdvisor google镜像
gcr.io/cadvisor/cadvisor
网络无法pull
可使用bitnami/cadvisor:0.52.1
2、数据存储与处理类
组件名称 | 核心功能 | 适用场景 |
---|---|---|
Prometheus Server | 时序数据库,存储监控数据,支持 PromQL 查询 | 核心组件,必选 |
Thanos | 提供 Prometheus 高可用、长期存储和全局查询 | 大规模监控集群数据聚合 |
VictoriaMetrics | 高性能时序数据库,兼容 Prometheus 协议 | 替代 Prometheus TSDB,适合海量数据 |
3、可视化与告警类
组件名称 | 核心功能 | 适用场景 |
---|---|---|
Grafana | 可视化平台,支持多种数据源和仪表盘模板 | 数据展示,必选 |
Alertmanager | 告警路由、去重、静默,支持邮件/Slack/Webhook | 集中管理告警通知 |
Grafana Loki | 日志聚合系统,与 Prometheus 指标联动 | 监控日志数据(需搭配 Promtail) |
4、辅助工具类
组件名称 | 核心功能 | 适用场景 |
---|---|---|
Pushgateway | 接收短期任务(如批处理作业)的指标推送 | 监控 Cron 任务、一次性脚本 |
Prometheus Operator | 在 Kubernetes 中自动化管理 Prometheus 配置 | Kubernetes 环境监控部署 |
Grafana Tempo | 分布式追踪系统,与 Prometheus 指标联动 | 链路追踪与性能分析 |
一、Server端配置
1. 配置文件目录结构
root@host4:/opt/monitor# tree
.
├── alertmanager.yml # Alertmanager配置
├── alert_rules.yml # 告警规则
├── docker-compose.yml # Compose主文件
└── prometheus.yml # Prometheus主配置
├── grafana-provisioning
│ ├── alerting #存储告警规则配置文件,用于预定义告警条件与通知策略
│ ├── dashboards #存放仪表板JSON配置文件,支持自动加载/更新仪表板(无需手动创建)
│ ├── datasources #配置数据源连接信息,支持多数据源并行配置(Prometheus/MySQL等)
│ │ └── prometheus.yml
│ ├── notifiers #定义告警通知渠道(邮件/钉钉/Slack等),与alerting/目录规则联动实现告警推送
│ └── plugins #放置预安装插件(如可视化插件或数据源插件),容器启动时自动加载插件二进制文
2. 关键配置文件示例
docker-compose.yml
- Compose主文件
services:# Prometheus核心服务prometheus:image: prom/prometheus:v3.4.0container_name: prometheusrestart: unless-stoppednetworks:- monitor-netports:- "9090:9090"volumes:- prometheus_data:/prometheus # 时序数据库持久化存储- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro # 主配置文件注入- ./alert_rules.yml:/etc/prometheus/alert_rules.yml:ro # 告警规则注入command:- --config.file=/etc/prometheus/prometheus.yml- --storage.tsdb.retention.time=30d # 数据保留30天- --web.enable-lifecycle # 启用配置热加载environment:- TZ=Asia/Shanghai # 时区设置deploy:resources:limits:cpus: '1.0'memory: 2G# Grafana可视化grafana:image: grafana/grafana:10.1.5container_name: grafanarestart: unless-stoppednetworks:- monitor-netports:- "3000:3000"volumes:- grafana_data:/var/lib/grafana # 配置/仪表盘持久化- ./grafana-provisioning:/etc/grafana/provisioning # 预配置仪表盘environment:- GF_SECURITY_ADMIN_PASSWORD=L1L7WxZ443iyZd #必须修改为复杂密码
# - GF_SERVER_DOMAIN=monitor.yourcompany.com # 生产域名,若没有域名可注释或删除此行- GF_SERVER_SERVE_FROM_SUB_PATH=true # 强制使用IP访问(可选)- GF_SERVER_ENABLE_GZIP=true- GF_USERS_ALLOW_SIGN_UP=false # 禁用公开注册- GF_AUTH_DISABLE_LOGIN_FORM=false # SSO登录,需正确配置代理认证(需后端支持)- GF_AUTH_PROXY_ENABLED=false #代理认证
# - GF_AUTH_PROXY_HEADER_NAME=X-WEBAUTH-USER #代理认证- GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=false- GF_DATABASE_TYPE=postgres- GF_DATABASE_HOST=postgres- GF_DATABASE_USER=grafana- GF_DATABASE_PASSWORD=L1L7WxZ443iyZd- GF_LIVE_ENABLED=false- GF_PLUGINS_DISABLE_AUTOLOAD=true # 禁用插件自动加载
# - GF_PATHS_PLUGINS=/var/lib/grafana/plugins # 显式指定插件路径
# - GF_DEFAULT_PLUGINS_PATH=/dev/null # 禁用默认插件路径depends_on:postgres:condition: service_healthy # 等待 PostgreSQL 健康检查通过prometheus:condition: service_started # 确保 Prometheus 已启动deploy:resources:limits:cpus: '0.5'memory: 1G# Node Exporter示例 (按需部署到各主机)node-exporter:image: prom/node-exporter:v1.9.1container_name: node-exporterrestart: unless-stoppednetworks:- monitor-netports:- "9100:9100"volumes:- /proc:/host/proc:ro- /run/udev:/run/udev:ro #获取磁盘设备信息- /sys:/host/sys:ro- /:/rootfs:rocommand:- --path.procfs=/host/proc- --path.sysfs=/host/sysdeploy:resources:limits:cpus: '0.2'memory: 256M# 容器监控(可选)cadvisor:image: bitnami/cadvisor:0.52.1
# image: google/cadvisor:v0.33.0user: "0:996" # root 用户 + docker 组 GIDcontainer_name: cadvisorrestart: unless-stoppednetworks:- monitor-netports:- "8080:8080"volumes:- /:/rootfs:ro,rslave # 只读挂载防止篡改- /var/run:/var/run:ro,rslave- /sys:/sys:ro,rslave- /var/lib/docker:/var/lib/docker:ro,rslave #解决日志中 Failed to get system UUID 警告- /etc/machine-id:/etc/machine-id:ro #挂载 /dev/disk:更精确的磁盘监控- /dev/disk:/dev/disk:roprivileged: true # 必须权限
# command:
# - --docker_only=true #仅监控 Docker 容器(隐式禁用 CRI-O/Podman 检测)
# - --disable_metrics=hugetlb,advtcp,udp # 可选:禁用不常用指标(减少日志干扰)deploy:resources:limits:cpus: '0.5'memory: 1Gpostgres:image: postgres:15restart: alwayshealthcheck:test: ["CMD-SHELL", "pg_isready -U grafana -d grafana || exit 1"]interval: 5stimeout: 5sretries: 10networks:- monitor-netenvironment:POSTGRES_USER: grafanaPOSTGRES_PASSWORD: L1L7WxZ443iyZdPOSTGRES_DB: grafanaPOSTGRES_HOST_AUTH_METHOD: scram-sha-256 # 启用加密认证POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256 --auth-local=scram-sha-256" #安全加固volumes:- postgres_data:/var/lib/postgresql/datadeploy:resources:limits:memory: 512M# 自定义网络隔离监控系统流量
networks:monitor-net:driver: bridgeattachable: truevolumes:prometheus_data: {} # Prometheus时序数据持久化grafana_data: {} # Grafana配置/仪表盘数据持久化postgres_data: {}
核心必选模块
服务名 | 必要性 | 说明 |
---|---|---|
prometheus | 必选 | 监控数据存储与计算核心,不可缺失 |
grafana | 必选 | 可视化必备组件 |
node-exporter | 必选 | 采集主机基础指标(CPU/内存/磁盘等) |
按需选装模块
服务名 | 必要性 | 场景建议 |
---|---|---|
cadvisor | 可选 | 需监控Docker容器时启用 |
alertmanager | 可选 | 需告警通知时启用(初期可跳过,后续添加) |
① prometheus.yml
- Prometheus抓取目标配置
global: # 全局采集参数scrape_interval: 15s # 抓取间隔evaluation_interval: 15s # 告警规则评估间隔# 告警规则加载
rule_files: # 告警规则文件路径- "/etc/prometheus/alert_rules.yml"# 抓取目标配置
scrape_configs: # 监控目标定义- job_name: "node" # 监控组名称 static_configs:- targets: ["node-exporter:9100"] # 监控本机node-exporter- job_name: "docker"static_configs:- targets: ["cadvisor:8080"] # 监控容器# 示例:添加其他主机监控(需对应主机部署node-exporter)- job_name: "host1-node" # 监控其他主机示例static_configs:- targets: ["192.168.0.221:9100"] # 修改为host1的实际IP(需确保host1的node_exporter已运行)# 监控 MySQL Exporter- job_name: "mysql" # MySQL监控示例(需先部署mysqld_exporter)scrape_interval: 30s # 降低抓取频率(根据负载调整)static_configs:- targets: ["192.168.0.221:9104"]params:collect[]: # 指定需要收集的指标组(减少冗余数据)- standard- engine_innodb
# scheme: https # 若启用HTTPStls_config:insecure_skip_verify: true # 跳过证书验证(生产环境建议配置CA)
② alert_rules.yml
- 告警规则定义
groups:
- name: host-alertsrules:- alert: HighCpuUsageexpr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85for: 5mlabels:severity: criticalannotations:summary: "High CPU usage on {{ $labels.instance }}"
③ alertmanager.yml
- 告警通知配置
route:group_by: ['alertname'] # 按告警名称分组group_wait: 30s # 同一组告警等待时间group_interval: 5m # 发送新告警间隔repeat_interval: 4h # 重复发送相同告警间隔receiver: 'email-notice' # 默认接收器receivers:
- name: 'email-notice'email_configs:- to: 'admin@yourcompany.com' # 修改为实际接收邮箱from: 'alert@monitor.com'smarthost: 'smtp.yourcompany.com:587' # 根据邮箱服务商修改auth_username: 'alert@monitor.com' # 发件邮箱账号auth_password: 'your-smtp-password' # 邮箱SMTP授权码(非登录密码)send_resolved: true
④ grafana-provisioning/datasources/prometheus.yml
- Grafana数据源预配置
apiVersion: 1
datasources:- name: Prometheustype: prometheusurl: http://prometheus:9090access: proxyisDefault: true
3. 部署前准备
# 创建配置文件目录
mkdir -p /opt/monitor/{grafana-provisioning/dashboards,grafana-provisioning/datasources,grafana-provisioning/alerting,grafana-provisioning/notifiers,grafana-provisioning/plugins}# 生成配置文件(手动填充上述示例内容)
touch /opt/monitor/docker-compose.yml
touch /opt/monitor/prometheus.yml
touch /opt/monitor/alert_rules.yml
touch /opt/monitor/alertmanager.yml
touch /opt/monitor/grafana-provisioning/datasources/prometheus.yml# 设置文件权限(防止容器权限问题)
chmod -R 755 /opt/monitor/grafana-provisioning
4. 启动服务
cd /opt/monitor
docker compose up -d # 后台启动
5. 部署后验证
-
检查容器状态:
docker compose ps # 确保所有服务状态为 "Up" docker compose logs #查看全部日志 docker compose logs --no-color | grep -i -E "error|fail|exception|warning|timeout"
-
访问服务:
- Grafana:
http://host4-ip:3000
(默认账号admin/YourStrongPassword
) - Prometheus:
http://host4-ip:9090/targets
查看抓取目标状态
- Grafana:
-
导入仪表盘:
- Grafana中导航至
Create > Import
,输入仪表盘ID(如1860
) - 选择Prometheus数据源
- Grafana中导航至
二、客户端配置
我这里准备在host1:192.168.0.221配置客户端,上面已安装mysql, tomcat
1. 配置Node Exporter(监控主机资源)
在每台客户端主机(host1)创建以下 docker-compose.node.yml
文件:
services:node-exporter:image: prom/node-exporter:v1.9.1container_name: node-exporterrestart: unless-stoppedports:- "9100:9100"volumes:- /proc:/host/proc:ro- /sys:/host/sys:ro- /:/rootfs:ro- /run/udev:/run/udev:ro #获取磁盘设备信息command:- --path.procfs=/host/proc- --path.sysfs=/host/sysnetworks:- app_ry-networkdeploy:resources:limits:cpus: '0.2'memory: 256Mnetworks:app_ry-network:driver: bridgeexternal: true
启动服务:
docker-compose -f docker-compose.node.yml up -d
检查是否有数据: 192.168.0.221:9100/metrics
2. 配置MySQL Exporter(监控MySQL)
创建 MySQL 监控专用用户
-
登录 MySQL
在 MySQL 所在的主机(host1)上,使用管理员账号登录 MySQL:mysql -u root -p
-
创建监控用户并授权
执行以下 SQL 语句,创建exporter
用户并授予最小必要权限:CREATE USER 'exporter'@'%' IDENTIFIED BY 'your.secure.password1' WITH MAX_USER_CONNECTIONS 3; GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'%'; FLUSH PRIVILEGES; mysql -uexporter -pyour.secure.password1
your.secure.password
:替换为强密码(需与后续mysqld-exporter
配置一致)。MAX_USER_CONNECTIONS 3
:限制最大连接数,防止监控占用过多资源。
在MySQL所在主机(host1)创建 docker-compose.mysql-exporter.yml
:
创建my.cnf
cat my.cnf
[client]
user = exporter
password = your.secure.password1
host = ry-mysql # 关键:指定 MySQL 容器的主机名
port = 3306 # 可选:显式指定端口
#[client.servers] #可配置多个连接
#user = bar
#password = bar123
services:mysqld-exporter:image: prom/mysqld-exporter:v0.17.2container_name: mysqld-exporterrestart: unless-stoppedports:- "9104:9104"networks:- app_ry-network #与mysql同一网络volumes:- ./my.cnf:/.my.cnfdeploy:resources:limits:cpus: '0.5'memory: 512Mnetworks:app_ry-network:driver: bridgeexternal: true # 关键:声明为外部网络
启动服务:
docker-compose -f docker-compose.mysql-exporter.yml up -d
验证: 192.168.0.221:9104/metrics 是否有数据
3. 配置Tomcat JMX Exporter(监控Tomcat)
集成 JMX Exporter 到 Tomcat 容器:
- 创建JMX配置文件
jmx-config.yml
:
nano jmx-config.yml
rules:- pattern: ".*"
- 下载 JMX Exporter 文件
Release 1.3.0 / 2025-05-16 · prometheus/jmx_exporter
- 修改Tomcat的
docker-compose.yml
,添加JMX Exporter参数:
services:ry-tomcat:image: harbor.host3/ruoyi/ry-tomcat:39environment:CATALINA_OPTS: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.rmi.port=12346 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.0.221 -javaagent:/jmx/jmx_prometheus_javaagent-1.3.0.jar=9404:/jmx/jmx-config.yml"volumes:- ./jmx-config.yml:/jmx/jmx-config.yml # 挂载配置文件- ./jmx_prometheus_javaagent-1.3.0.jar:/jmx/jmx_prometheus_javaagent-1.3.0.jar # 挂载 Agentports:- "9404:9404" # 新增:暴露 JMX Exporter 的 HTTP 端口
测试连接
192.168.0.221:9404/metrics 搜索应有mysql_up 1
-
确认 Prometheus 抓取配置:
- job_name: "tomcat"static_configs:- targets: ["192.168.0.221:9404"]
热加载(推荐):
Prometheus 支持通过 API 热加载配置,无需重启:curl -X POST http://prometheus-host:9090/-/reload curl -X POST http://192.168.0.224:9090/-/reload
前提:启动 Prometheus 时需添加
--web.enable-lifecycle
参数(已在您的docker-compose.yml
中配置)。
参数 | 必要性 | 作用 |
---|---|---|
-Dcom.sun.management.jmxremote | 必要 | 启用 JMX 远程管理功能,无此参数无法通过 JMX 连接。 |
-Dcom.sun.management.jmxremote.port=12345 | 必要 | 指定 JMX 连接的端口,Prometheus 通过此端口访问 JMX 数据。 |
-Dcom.sun.management.jmxremote.rmi.port=12346 | 可选 | 指定 RMI 通信端口,仅在需要远程方法调用(RMI)时使用,通常与 JMX 端口一致可省略。 |
-Dcom.sun.management.jmxremote.ssl=false | 可选 | 禁用 SSL 加密。生产环境建议启用 SSL(设置为 true ),测试环境可禁用。 |
-Dcom.sun.management.jmxremote.authenticate=false | 可选 | 禁用认证。生产环境必须启用认证(设置为 true ),测试环境可禁用。 |
-Djava.rmi.server.hostname=192.168.0.221 | 必要 | 指定 RMI 通信的主机名,容器化环境中必须设置为宿主机 IP 或可解析的域名。 |
启用 JMX 认证的步骤(生产环境建议配置)
-
生成密码文件:
创建jmxremote.password
文件(示例内容):monitor password123 # 用户名和密码
-
设置文件权限:
chmod 600 jmxremote.password # 仅允许所有者读写
-
修改 Tomcat 配置:
environment:CATALINA_OPTS: "...-Dcom.sun.management.jmxremote.authenticate=true-Dcom.sun.management.jmxremote.password.file=/etc/prometheus/ssl/jmxremote.password" volumes:- ./jmxremote.password:/etc/prometheus/ssl/jmxremote.password
Prometheus 是否需要调整配置?
- 无需调整:JMX Exporter 在 HTTP 模式下会将 JMX 数据转换为 Prometheus 兼容的指标,认证由 JMX Exporter 处理。
- 例外情况:如果直接通过 JMX 协议抓取(非 HTTP 模式),需在 Prometheus 配置中提供凭据。但您当前使用 HTTP 模式,无需额外配置。
4. 配置Prometheus服务端(host4)
修改 prometheus.yml
,添加新的抓取目标:
scrape_configs:# 原有配置...- job_name: "host1-node" # 监控host1static_configs:- targets: ["192.168.0.221:9100"] # 修改为host1的实际IP(需确保host1的node_exporter已运行)# 监控 MySQL Exporter- job_name: "mysql" # MySQL监控示例(需先部署mysqld_exporter)scrape_interval: 30s # 降低抓取频率(根据负载调整)static_configs:- targets: ["192.168.0.221:9104"]params:collect[]: # 指定需要收集的指标组(减少冗余数据)- standard- engine_innodb # 监控 MySQL Exporter- job_name: "tomcat"static_configs:- targets: ["192.168.0.221:9404"]
热加载配置(或重启Prometheus):
curl -X POST http://192.168.0.224:9090/-/reload
前提:启动 Prometheus 时需添加 --web.enable-lifecycle
参数(已在您的 docker-compose.yml
中配置)。
网页上可查看状态
http://192.168.0.224:9090/targets
5. Grafana操作步骤
- 登录Grafana:访问
http://192.168.0.221:3000
,使用管理员账号登录。 - 导入仪表板:
- 点击左侧菜单 ➔ Dashboards ➔ New➔ Import。
- 输入仪表板ID(例如:
8919
用于Node Exporter,11323
用于MySQL)。load
- 选择数据源为
Prometheus
,Import
。
- 验证数据:
- 在仪表板中选择对应的监控目标,查看指标是否正常显示。
6.更多 Grafana 仪表板模板
- 官方模板库:
Grafana 官方提供了丰富的仪表板模板,涵盖 MySQL、Node Exporter、JVM 等各类监控场景。访问 Grafana Dashboards,搜索关键词如MySQL
、Node Exporter
、Prometheus
,筛选高评分模板。例如:- MySQL 监控:ID
7362
(更详细的性能分析)、12826
(分库分表监控)。 - 主机监控:ID
1860
(Node Exporter 增强版)、11074
(多维度资源展示)。 - 容器监控:ID
315
(Docker 容器资源使用)。
- MySQL 监控:ID
- 社区推荐模板:
部分模板针对特定场景优化,例如:- 综合监控:ID
10000
(集成主机、MySQL、Redis 等指标)。 - 告警关联视图:ID
6663
(展示告警与指标的关联性)。
- 综合监控:ID
- 自定义模板:
若现有模板不满足需求,可基于已有模板修改或自行创建。Grafana 支持通过 JSON 文件导入导出,结合 PromQL 灵活定制。
三、配置告警规则
- 配置Alertmanager:
定义告警规则(如CPU>80%),集成邮件、Slack等通知渠道。
1. 安装 Alertmanager
推荐安装位置:与 Prometheus 同Server主机(host4),确保网络互通。
使用 Docker Compose 安装:在现有的 docker-compose.yml
中添加 Alertmanager 服务:
alertmanager:profiles:- alertmanagerimage: prom/alertmanager:v0.28.1container_name: alertmanagerrestart: unless-stoppednetworks:- monitor-netports:- "9093:9093"volumes:- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:rocommand:- --config.file=/etc/alertmanager/alertmanager.yml- --cluster.advertise-address=alertmanager:9093depends_on:- prometheusdeploy:resources:limits:cpus: '0.3'memory: 512M
启动服务
#profiles:
# - alertmanager
#使用profiles需指定名称启动,也可去除同时启动
docker compose --profile alertmanager up -d alertmanager
2. 配置 Alertmanager 邮件通知
步骤 1:创建 alertmanager.yml
文件
qq邮箱示例
https://mail.qq.com/–>登录
–>设置
–>账号
–>POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务
开启服务获取授权码
route:group_by: ['alertname'] # 按告警名称分组group_wait: 30s # 同一组告警等待时间group_interval: 5m # 发送新告警间隔repeat_interval: 4h # 重复发送相同告警间隔receiver: 'email-notice' # 默认接收器retry_interval: 1m # 重试间隔,默认 5mreceivers:
- name: 'email-notice'email_configs:- to: 'aaa@qq.com' # 接收告警的邮箱from: 'xxx@qq.com' # SMTP 服务器地址(根据邮箱服务商修改)smarthost: 'smtp.qq.com:465' # 根据邮箱服务商修改auth_username: 'xx@qq.com' # SMTP 登录账号auth_password: 'xxxxx' # 邮箱SMTP授权码(非登录密码)send_resolved: true # 发送告警恢复通知require_tls: false # 禁用 STARTTLShello: 'qq.com' # 指定 SMTP 服务器的 HELO 标识tls_config:insecure_skip_verify: true # 忽略证书验证(可选)(测试环境)# server_name: smtp.qq.com # 生产环境建议填写
常见邮箱 SMTP 配置示例:
邮箱服务商 | SMTP 地址 | 端口 | 加密方式 |
---|---|---|---|
Gmail | smtp.gmail.com | 587 | STARTTLS |
QQ 邮箱 | smtp.qq.com | 465 | SSL |
企业邮箱 | smtp.yourcompany.com | 25 | 无 |
3. 配置 Prometheus 告警规则
步骤 1:创建告警规则文件 alert_rules.yml
groups:
- name: host-alertsrules:- alert: HighCpuUsageexpr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85for: 5mlabels:severity: criticalannotations:summary: "实例 {{ $labels.instance }} CPU 使用率过高"description: "CPU 使用率持续5分钟超过85%,当前值为 {{ $value }}%"- alert: LowMemoryAvailableexpr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100) < 10for: 10mlabels:severity: warningannotations:summary: "实例 {{ $labels.instance }} 可用内存不足"description: "可用内存低于10%,当前剩余 {{ $value | humanize }}%"- name: mysql-alertsrules:- alert: MysqlDownexpr: mysql_up == 0for: 1mlabels:severity: criticalannotations:summary: "MySQL 服务不可用"description: "MySQL 实例 {{ $labels.instance }} 已宕机超过1分钟"
步骤 2:在 prometheus.yml
中引用告警规则
rule_files:- "/etc/prometheus/alert_rules.yml" # 容器内路径(需挂载)alerting:alertmanagers:- static_configs:- targets: ['alertmanager:9093'] # Alertmanager 服务地址
步骤 3:重启 Prometheus 服务
docker compose restart prometheus
4. 验证告警配置
步骤 1:访问 Prometheus 告警页面
打开 http://192.168.0.224:9090/alerts
,检查告警规则是否加载成功,状态是否为正常。
步骤 2:触发测试告警
-
模拟高 CPU 使用率:
stress -c 2 # 在监控的主机上运行(需安装 stress 工具)
-
手动停止 MySQL 服务:
docker stop ry-mysql
步骤 3:查看 Alertmanager 界面
访问 http://host4:9093
,确认告警是否显示,并检查邮件是否收到通知。
5. 其他告警配置选项
1. 多通知渠道集成
Alertmanager 支持以下通知方式(需在 alertmanager.yml
中配置):
-
Slack:
- name: 'slack-notice'slack_configs:- api_url: 'https://hooks.slack.com/services/XXXX/YYYY/ZZZZ'channel: '#alerts'
-
Webhook(对接企业微信、钉钉):
- name: 'webhook-notice'webhook_configs:- url: 'http://webhook-server:5000/alert'
-
PagerDuty:
- name: 'pagerduty-notice'pagerduty_configs:- service_key: 'your-pagerduty-key'
2. 告警分组与抑制
-
分组(Grouping):将相似告警合并发送,减少通知噪音。
-
抑制(Inhibition):当某类告警触发时,抑制其他相关告警。
inhibit_rules: - source_match:severity: 'critical'target_match:severity: 'warning'equal: ['instance']
3. 静默(Silence)
在 Alertmanager 界面中设置临时静默,屏蔽特定时间段或条件的告警。
4.其他告警通知方式(短信/钉钉/企业微信)
若需发送短信,可通过以下方式集成:
1. 通过短信网关 API
receivers:
- name: 'sms-notice'webhook_configs:- url: 'http://sms-gateway-api:8080/send'send_resolved: truehttp_config:basic_auth:username: 'api-user'password: 'api-password'
2. 通过钉钉机器人
receivers:
- name: 'dingtalk-notice'webhook_configs:- url: 'https://oapi.dingtalk.com/robot/send?access_token=xxxx'send_resolved: true
3. 通过企业微信
receivers:
- name: 'wecom-notice'wechat_configs:- corp_id: 'your-corp-id'to_party: '2'agent_id: '1000002'api_secret: 'your-api-secret'
6.故障排查指南
问题现象 | 排查步骤 |
---|---|
告警未触发 | 检查 Prometheus 的 /alerts 页面,确认规则语法正确且表达式返回值符合预期。 |
邮件未收到 | 验证 SMTP 配置,检查 Alertmanager 日志 docker logs alertmanager 。 |
Alertmanager 无法连接 Prometheus | 确认 Prometheus 的 alerting 配置中地址正确,网络互通。 |
1. 部署与配置问题
问题1:Prometheus 配置文件语法错误
-
日志错误示例:
level=error ts=2024-03-01T12:00:00Z caller=main.go:123 err="error loading config from \"/etc/prometheus/prometheus.yml\": parsing YAML file: yaml: line 5: did not find expected key"
-
解决方案:
使用promtool
工具验证配置文件语法:docker exec prometheus promtool check config /etc/prometheus/prometheus.yml
修复提示的语法错误(如缩进、冒号缺失)。
问题2:Grafana 数据源配置错误
-
日志错误示例:
t=2024-03-01T12:00:00Z lvl=eror msg="Failed to query Prometheus" error="client_error: client error: 404"
-
解决方案:
检查grafana-provisioning/datasources/prometheus.yml
的url
配置:# 确保地址为 Prometheus 容器名称(容器内通信) url: http://prometheus:9090
重启 Grafana 服务:
docker compose restart grafana
问题3:Alertmanager 集群通信失败
-
错误日志:
time=2025-05-26T21:33:45.119Z level=ERROR source=main.go:259 msg="unable to initialize gossip mesh" err="create memberlist: Failed to get final advertise address: Failed to parse advertise address \"alertmanager\""
-
原因:
- 单机部署 Alertmanager 时未禁用集群模式,导致尝试初始化 Gossip 协议失败。
- 容器名
alertmanager
无法解析为有效 IP。
-
解决方案:
禁用集群模式:# docker-compose.yml 中 Alertmanager 的配置 services:alertmanager:command:- --config.file=/etc/alertmanager/alertmanager.yml- --cluster.listen-address= # 禁用集群模式
问题一:JMX Exporter 参数格式错误导致 Tomcat 启动失败
-
错误日志:
java.lang.ClassNotFoundException: org.apache.juli.ClassLoaderLogManager
-
原因:
CATALINA_OPTS
参数未正确使用 YAML 多行语法。- JMX Exporter 的 Agent 路径或配置文件未挂载。
-
解决方案:
修正参数格式和挂载路径:# docker-compose.yml 中 Tomcat 的配置 services:ry-tomcat:environment:CATALINA_OPTS: "-javaagent:/jmx/jmx_prometheus_javaagent-1.3.0.jar=9404:/jmx/jmx-config.yml"volumes:- ./jmx-config.yml:/jmx/jmx-config.yml- ./jmx_prometheus_javaagent-1.3.0.jar:/jmx/jmx_prometheus_javaagent-1.3.0.jar
问题二:Alertmanager TLS 配置冲突
-
错误日志:
level=WARN source=notify.go:866 msg="Notify attempt failed" err="'require_tls' is true but \"smtp.qq.com:465\" does not advertise STARTTLS"
-
原因:
- QQ 邮箱的 465 端口使用 SSL 加密,但 Alertmanager 默认要求 STARTTLS。
-
解决方案:
显式禁用 TLS 并指定 SSL 端口:# alertmanager.yml 中的 SMTP 配置 email_configs: - smarthost: 'smtp.qq.com:465'require_tls: false # 禁用 STARTTLS
2. 网络与连接问题
问题3:Prometheus 无法连接 Exporter(Targets 显示 DOWN)
-
日志错误示例:
level=error ts=2024-03-01T12:00:00Z caller=scrape.go:1320 msg="Error scraping target" target="http://192.168.0.221:9100/metrics" err="Get \"http://192.168.0.221:9100/metrics\": context deadline exceeded"
-
解决方案:
-
检查 Exporter 端口是否暴露:
docker ps --filter "name=node-exporter" --format "{{.Ports}}"
-
测试网络连通性:
curl http://192.168.0.221:9100/metrics # 在 Prometheus 容器内执行
-
确保 Docker 网络配置一致(使用同一自定义网络)。
-
问题4:Alertmanager 无法接收 Prometheus 告警
-
日志错误示例(Prometheus 日志):
level=error ts=2024-03-01T12:00:00Z caller=notifier.go:256 component=notifier alertmanager=http://alertmanager:9093/api/v2/alerts count=1 msg="Error sending alert" err="Post \"http://alertmanager:9093/api/v2/alerts\": dial tcp: lookup alertmanager on 127.0.0.11:53: no such host"
-
解决方案:
在prometheus.yml
中确认 Alertmanager 地址正确:alerting:alertmanagers:- static_configs:- targets: ['alertmanager:9093'] # 使用容器名称而非IP
确保
docker-compose.yml
中 Alertmanager 与 Prometheus 共享同一网络。
3. 数据采集与指标问题
问题5:Exporter 未暴露指标(/metrics 端点无数据)
-
日志错误示例(Node Exporter 日志):
level=error ts=2024-03-01T12:00:00Z caller=collector.go:123 msg="collector failed" name=meminfo err="could not get meminfo: open /host/proc/meminfo: no such file or directory"
-
解决方案:
检查 Exporter 的挂载路径是否正确(如 Node Exporter):volumes:- /proc:/host/proc:ro # 必须挂载宿主机 /proc- /sys:/host/sys:ro
重启 Exporter 并验证:
curl http://localhost:9100/metrics | grep "node_"
问题6:Grafana 仪表盘显示 “No Data”
-
日志错误示例(Grafana 日志):
t=2024-03-01T12:00:00Z lvl=eror msg="Query error" error="invalid parameter 'query': parse error at char 15: syntax error: unexpected IDENT, expecting string or number"
-
解决方案:
-
检查 PromQL 语法(如
node_memory_MemAvailable_bytes
是否拼写正确)。 -
确认 Prometheus 中存在对应指标:
curl http://prometheus:9090/api/v1/label/__name__/values | jq # 列出所有指标名
-
4. 告警配置与通知问题
问题7:告警规则未触发(Prometheus 无告警)
-
日志错误示例(Prometheus 日志):
level=warn ts=2024-03-01T12:00:00Z caller=manager.go:654 component="rule manager" msg="Evaluating rule failed" rule="alert=HighCpuUsage" err="invalid expression type \"\" for range query, must be Scalar or instant Vector"
-
解决方案:
检查告警规则的expr
表达式是否为合法 PromQL(需返回瞬时向量):# 错误示例(缺少聚合函数) expr: node_cpu_seconds_total{mode="idle"} > 85# 正确示例(使用 avg 聚合) expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100 > 85
问题8:Alertmanager 发送邮件失败
-
日志错误示例(Alertmanager 日志):
level=error ts=2024-03-01T12:00:00Z caller=notify.go:674 component=dispatcher msg="Error on notify" err="*email.loginAuth auth: 550 User has no permission"
-
解决方案:
检查alertmanager.yml
的 SMTP 配置(以 QQ 邮箱为例):receivers:- name: 'email-notice'email_configs:- to: 'user@qq.com'from: 'sender@qq.com'smarthost: 'smtp.qq.com:465'auth_username: 'sender@qq.com'auth_password: 'xxxxx' # 使用 SMTP 授权码,非登录密码require_tls: false # 禁用 STARTTLStls_config:insecure_skip_verify: true # 测试环境跳过证书验证
确保邮箱已开启 SMTP 服务并生成授权码。
5. 权限与安全设置问题
问题9:容器因权限问题无法启动
-
日志错误示例(cAdvisor 日志):
F0301 12:00:00.000000 1 cadvisor.go:175] Failed to start container manager: inotify_add_watch /sys/fs/cgroup/cpuacct,cpu: permission denied
-
解决方案:
在docker-compose.yml
中为 cAdvisor 添加特权模式:cadvisor:privileged: true # 必须开启特权模式volumes:- /:/rootfs:ro,rslave- /var/run:/var/run:ro,rslave
问题10:Grafana 登录失败(权限不足)
-
日志错误示例:
t=2024-03-01T12:00:00Z lvl=eror msg="Failed to login" error="invalid username or password"
-
解决方案:
重置管理员密码(通过环境变量或配置文件):environment:- GF_SECURITY_ADMIN_PASSWORD=NewPassword123 # 在 docker-compose.yml 中设置
重启 Grafana 后使用新密码登录。
问题一:MySQL 用户权限不足
-
错误日志:
time=2025-05-26T19:02:01.678Z level=ERROR source=exporter.go:131 msg="Error opening connection to database" err="Access denied for user 'exporter'@'%'"
-
原因:
exporter
用户缺少PROCESS
、REPLICATION CLIENT
、SELECT
权限。
-
解决方案:
授予权限并刷新:-- 在 MySQL 中执行 GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'%'; FLUSH PRIVILEGES;
6. 容器化环境中的特殊问题
问题11:Docker 容器间网络不通
-
日志错误示例(Prometheus Targets 页面显示
Connection refused
)。 -
解决方案:
确保所有服务使用同一 Docker 网络:# docker-compose.yml networks:monitor-net:driver: bridgeservices:prometheus:networks:- monitor-netgrafana:networks:- monitor-net
检查容器 IP:
docker network inspect monitor-net
问题12:容器挂载卷权限错误
-
日志错误示例(Grafana 日志):
t=2024-03-01T12:00:00Z lvl=eror msg="Failed to provision plugins" error="mkdir /var/lib/grafana/plugins: permission denied"
-
解决方案:
调整宿主机目录权限(确保容器用户可读写):chmod -R 755 /opt/monitor/grafana-provisioning # 宿主目录权限
或在
docker-compose.yml
中指定用户:grafana:user: "472:472" # Grafana 默认用户ID
7.完整实例文档
global:# The smarthost and SMTP sender used for mail notifications.smtp_smarthost: 'localhost:25'smtp_from: 'alertmanager@example.org'# The root route on which each incoming alert enters.
route:# The root route must not have any matchers as it is the entry point for# all alerts. It needs to have a receiver configured so alerts that do not# match any of the sub-routes are sent to someone.receiver: 'team-X-mails'# The labels by which incoming alerts are grouped together. For example,# multiple alerts coming in for cluster=A and alertname=LatencyHigh would# be batched into a single group.## To aggregate by all possible labels use '...' as the sole label name.# This effectively disables aggregation entirely, passing through all# alerts as-is. This is unlikely to be what you want, unless you have# a very low alert volume or your upstream notification system performs# its own grouping. Example: group_by: [...]group_by: ['alertname', 'cluster']# When a new group of alerts is created by an incoming alert, wait at# least 'group_wait' to send the initial notification.# This way ensures that you get multiple alerts for the same group that start# firing shortly after another are batched together on the first# notification.group_wait: 30s# When the first notification was sent, wait 'group_interval' to send a batch# of new alerts that started firing for that group.group_interval: 5m# If an alert has successfully been sent, wait 'repeat_interval' to# resend them.repeat_interval: 3h# All the above attributes are inherited by all child routes and can# overwritten on each.# The child route trees.routes:# This route performs a regular expression match on alert labels to# catch alerts that are related to a list of services.- matchers:- service=~"^(foo1|foo2|baz)$"receiver: team-X-mails# The service has a sub-route for critical alerts, any alerts# that do not match, i.e. severity != critical, fall-back to the# parent node and are sent to 'team-X-mails'routes:- matchers:- severity="critical"receiver: team-X-pager- matchers:- service="files"receiver: team-Y-mailsroutes:- matchers:- severity="critical"receiver: team-Y-pager# This route handles all alerts coming from a database service. If there's# no team to handle it, it defaults to the DB team.- matchers:- service="database"receiver: team-DB-pager# Also group alerts by affected database.group_by: [alertname, cluster, database]routes:- matchers:- owner="team-X"receiver: team-X-pager- matchers:- owner="team-Y"receiver: team-Y-pager# Inhibition rules allow to mute a set of alerts given that another alert is
# firing.
# We use this to mute any warning-level notifications if the same alert is
# already critical.
inhibit_rules:
- source_matchers:- severity="critical"target_matchers:- severity="warning"# Apply inhibition if the alertname is the same.# CAUTION: # If all label names listed in `equal` are missing # from both the source and target alerts,# the inhibition rule will apply!equal: ['alertname']receivers:
- name: 'team-X-mails'email_configs:- to: 'team-X+alerts@example.org, team-Y+alerts@example.org'- name: 'team-X-pager'email_configs:- to: 'team-X+alerts-critical@example.org'pagerduty_configs:- routing_key: <team-X-key>- name: 'team-Y-mails'email_configs:- to: 'team-Y+alerts@example.org'- name: 'team-Y-pager'pagerduty_configs:- routing_key: <team-Y-key>- name: 'team-DB-pager'pagerduty_configs:- routing_key: <team-DB-key>
四、配置 HTTPS 及认证授权(nginx)
推荐 Prometheus 使用 HTTP,TLS 交由 NGINX 的主要原因:
✅ 1:职责分离,简化配置和维护
组件 | 主要职责 |
---|---|
Prometheus | 专注于数据抓取、存储与查询 |
NGINX | 专注于反向代理、TLS 终端、访问控制 |
让 NGINX 负责 TLS 意味着你只需配置一次 HTTPS,不管后端是 Prometheus、Grafana 还是其他服务,都可以共用这套 TLS 配置。这符合**“单一职责原则”**。
✅ 2:HTTPS 配置在 Prometheus 中更复杂、可维护性差
如果你坚持在 Prometheus 中启用 TLS,你需要:
- 生成/维护一份有效证书(哪怕是自签名)
- 配置
web.config.file
,并将证书和私钥挂载进去 - 每次证书更新要重启容器或 reload Prometheus
而在 NGINX 中,TLS 是它的第一职责,证书热重载也更成熟。
✅ 3:Prometheus 并非为生产 HTTPS 暴露而优化
Prometheus 的官方文档中对 HTTPS 支持是 “experimental(实验性)”,其主要目标是供后端服务抓取数据,而不是作为前端暴露 HTTPS 服务。反而用反向代理(如 NGINX 或 Traefik)是更常见的部署方式。
✅4:Docker 容器内部使用 HTTPS 是性能浪费
容器之间通信时,TLS 加密并没有太多意义(因为已经在同一个网络或通过 Kubernetes 网络策略隔离),使用 HTTPS 会带来额外的:
- CPU 消耗(TLS 握手和加解密)
- 连接复杂度
- 不必要的证书信任验证问题(如自签名证书总是出 warning)
✅ 5:统一入口便于做访问控制和认证
你可以在 NGINX 统一做这些事情:
- 基于路径的认证(例如 Grafana 加认证,Prometheus 只读)
- IP 限制、速率限制、防火墙策略
- OAuth 或 LDAP 等集成
这让整个系统更加安全、集中控制。
如果你有特殊安全需求(比如 Prometheus 暴露在公网且不能使用 NGINX),那确实可以考虑启用 Prometheus 自带的 TLS,但默认建议就是走 NGINX。
4.1.自定义 Host + 自签名证书的(测试环境)
#域名映射
# Linux
echo "192.168.0.224 monitor.host4" | sudo tee -a /etc/hosts
Windows:
-
C:\Windows\system32\drivers\etc\hosts
-
添加一行
192.168.0.224 monitor.host4
#证书存放目录
mkdir -p /opt/monitor/ssl && cd /opt/monitor/ssl
# 生成证书和私钥
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes \-subj "/CN=monitor.host4" \-addext "subjectAltName=DNS:monitor.host4,IP:192.168.0.224"
sudo chmod 644 /opt/monitor/ssl/*.pem
# 生成的 cert.pem 和 key.pem 用于后续配置
1. 修改配置文件
grafana-provisioning/datasources/prometheus.yml
apiVersion: 1
datasources:- name: Prometheustype: prometheusurl: http://prometheus:9090/prometheusaccess: proxyisDefault: true
docker-compose.yml
# Prometheusprometheus:command:- --web.route-prefix=/prometheus #- --web.external-url=/prometheus ## Grafanagrafana:environment:- GF_SERVER_ROOT_URL=https://monitor.host4/grafana/- GF_SERVER_SERVE_FROM_SUB_PATH=true
参数/变量 | 组件 | 含义 |
---|---|---|
--web.route-prefix=/prometheus | Prometheus | 指定 Prometheus 在 HTTP 服务端挂载的路径前缀。 所有内置页面和 API(如 /api/v1/query 、/graph )都将自动变为 /prometheus/api/v1/... 、/prometheus/graph 。 |
--web.external-url=/prometheus | Prometheus | 告诉 Prometheus 当它生成跳转链接或 HTML 静态资源 URL 时,以此路径为根。 通常与 --web.route-prefix 配合使用,确保它发出的 <a href> 、<script src> 正确指向子路径。 |
GF_SERVER_ROOT_URL=https://monitor.host4/grafana/ | Grafana | 配置 Grafana 自身生成的所有绝对跳转和资源链接的根 URL。 例如登录后重定向、仪表盘中的静态文件等,都以这个地址开头。末尾的 / 很关键,要与 NGINX 的子路径对应。 |
GF_SERVER_SERVE_FROM_SUB_PATH=true | Grafana | 告诉 Grafana “我部署在子路径下,请在内部路由中自动加上你在 GF_SERVER_ROOT_URL 里指定的那个子路径”。 只有开启后,Grafana 才会识别并正确处理 /grafana/... 这类 URI。 |
Prometheus
- 外层 NGINX 反代到
/prometheus/
,然后转发到容器内部的同一路径。 - Prometheus 内部页面、API 都挂到这个子路径下,生成链接也会带上该前缀。
Grafana
- 外层 NGINX 反代到
/grafana/
,容器内部同样映射到/grafana/
。 GF_SERVER_ROOT_URL
定义了用户在浏览器看到的根地址;GF_SERVER_SERVE_FROM_SUB_PATH=true
让 Grafana 的内部路由和静态文件请求都带上子路径。
2. 安装 Nginx
宿主机直接安装(推荐)
sudo apt install -y nginx
-
优点
- 证书自动续期(Certbot + Cron)。
- 性能更优,适合生产环境。
-
缺点:
- 依赖宿主机环境,可能与其他服务冲突。
通过Docker 部署 Nginx
# docker-compose.yml
services:nginx:image: nginx:latestports:- "80:80"- "443:443"volumes:- ./nginx.conf:/etc/nginx/nginx.conf- /opt/monitor/ssl/cert.pem:/etc/nginx/cert.pem- /opt/monitor/ssl/key.pem:/etc/nginx/key.pem- /etc/letsencrypt:/etc/letsencrypt:ro # 若用 Let's Encryptnetworks:- monitor-net
-
优点:
- 环境隔离,配置独立。
- 与 Prometheus/Grafana 容器网络互通。
-
缺点:
- 证书续期需手动处理(需挂载 Certbot 容器或宿主机路径)。
- 性能略低于宿主机直接安装。
3. 配置 Nginx HTTPS 反向代理
创建配置文件 /etc/nginx/sites-available/monitor.conf
:
nano /etc/nginx/sites-available/monitor.conf
server {listen 80;server_name monitor.host4;return 301 https://$host$request_uri;
}server {listen 443 ssl;server_name monitor.host4;ssl_certificate /opt/monitor/ssl/cert.pem;ssl_certificate_key /opt/monitor/ssl/key.pem;# 强制 TLS 1.2+ 并优化加密套件ssl_protocols TLSv1.2 TLSv1.3;ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;ssl_prefer_server_ciphers on;# /grafana 不带斜杠时补全location = /grafana {return 301 /grafana/;}# 根路径直接跳到 /grafana/location = / {return 302 /grafana/;}# Grafana 子路径代理——保持后端同样的 /grafana/ 前缀location /grafana/ {# 直接把 /grafana/… → 后端的 /grafana/…proxy_pass http://192.168.0.224:3000/grafana/;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;# WebSocket 支持proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";# 自签证书时可关验证proxy_ssl_verify off;# 不做任何 Location 改写proxy_redirect off;}# Prometheus 代理配置location /prometheus/ {proxy_pass http://192.168.0.224:9090/prometheus/;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";# 自签证书时可关验证proxy_ssl_verify off;proxy_redirect off;}
}
3. 启用配置并重启 Nginx
sudo ln -s /etc/nginx/sites-available/monitor.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl restart nginx
4.浏览器导入证书
- 导入证书:
- 下载
cert.pem
到本地。 - Edge 浏览器:设置 → 隐私 →安全性 → 管理证书 → 导入(右下角选择所有文件) → 选择
cert.pem
。 - 选择
受信任的根证书颁发机构
- 下载
- 访问测试:
- 输入
https://monitor.host4
,忽略安全警告(或信任证书)。
- 输入
4.2.有域名并配置公网解析
1. 使用 Let’s Encrypt 证书(必须提供合法域名)
# 1. 安装 Certbot
sudo apt update
sudo apt install -y snapd
sudo snap install core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot# 2. 申请证书(需替换为你的域名)
sudo certbot --nginx \-d monitor.host4 \--agree-tos \--redirect \--no-eff-email \-m your-email@example.com
#验证与续期
sudo certbot renew --dry-run
#如果没有报错,系统会自动在到期前续期,并在续期后自动重载 NGINX(Certbot 会安装好相应的 systemd / cron 钩子)。
--nginx
:Certbot 会自动检测你的 NGINX 配置并插入新的 ssl_certificate
/ssl_certificate_key
指令。
-d monitor.host4
:确保 DNS 已经把 monitor.host4
指向你的服务器公网 IP。
--redirect
:自动把 HTTP 跳到 HTTPS。
-m
:你注册的邮箱,会在续期失败时给你警告。
2. 强化 NGINX 安全头
在你的 server { … }
块(listen 443)内,添加:
# HSTS:强制浏览器只用 HTTPS,180 天add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload" always;# 防点击劫持add_header X-Frame-Options "SAMEORIGIN" always;# 防止 MIME 类型嗅探add_header X-Content-Type-Options "nosniff" always;# 防止跨站脚本add_header X-XSS-Protection "1; mode=block" always;# 引用来源策略add_header Referrer-Policy "no-referrer-when-downgrade" always;
保存后:
sudo nginx -t && sudo systemctl reload nginx
3. 访问控制与认证
3.1 对 Grafana 启用 Basic Auth(可选二次认证)
在 location /grafana/ { … }
前面添加一段:
auth_basic "Monitoring";auth_basic_user_file /etc/nginx/.grafana_htpasswd;
生成密码文件(Ubuntu 自带 apache2-utils
):
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.grafana_htpasswd admin
# 系统提示输入密码
然后 reload NGINX。
3.2 Prometheus 层面 IP 白名单
在 location /prometheus/ { … }
中加入:
allow 10.0.0.0/8; # 允许内网allow 192.168.0.0/16; # 允许局域网deny all; # 其它一律拒绝
4. 日志集中与监控
4.1 NGINX 日志格式
在 http { … }
中定义:
log_format monitor '$remote_addr - $remote_user [$time_local] ''"$request" $status $body_bytes_sent ''"$http_referer" "$http_user_agent" ''rt=$request_time ua="$upstream_addr" us="$upstream_status" ut="$upstream_response_time"';
access_log /var/log/nginx/monitor-access.log monitor;
reload NGINX。
4.2 收集到集中系统
- 如果用 ELK/EFK/Loki,请在日志集中系统里配置对应的 Filebeat/Promtail 采集
/var/log/nginx/monitor-access.log
,并做字段解析。 - 设置关键 URL(
/grafana/login
、/prometheus/query
)的 5xx/401/429 报警。
5. 服务自身监控与告警
5.1 安装 NGINX Exporter
在 Prometheus 下加入 NGINX Exporter(Docker 示例):
services:nginx-exporter:image: nginx/nginx-prometheus-exporter:0.13.0ports:- "9113:9113"env:- NGINX_STATUS_URL=http://host.docker.internal/nginx_status
并在主 NGINX 加入 stub_status
:
location /nginx_status {stub_status on;allow 127.0.0.1;deny all;
}
5.2 在 Prometheus 抓取
- job_name: 'nginx'static_configs:- targets: ['nginx-exporter:9113']
5.3 告警示例
在 alert_rules.yml
中加入:
groups:- name: nginx_alertsrules:- alert: NginxHigh5xxRateexpr: rate(nginx_http_requests_total{status=~"5.."}[5m]) > 0.1for: 5mlabels:severity: criticalannotations:summary: "High HTTP 5xx rate on NGINX"
6. 备份与恢复
6.1 Grafana Dashboards
docker exec grafana grafana-cli dashboards export-all --output /var/lib/grafana/dashboards-backup.json
定时把 /var/lib/grafana/dashboards-backup.json
同步到备份存储。
6.2 Prometheus TSDB 快照
curl -XPOST http://localhost:9090/api/v1/admin/tsdb/snapshot
# 会在 data/snapshots 目录生成快照,定时拷贝到远程存储
7. 自动化与 CI/CD
- 把 NGINX 配置、Docker Compose 文件 放到 Git 仓库;
- 使用 GitLab CI / GitHub Actions 在合并后自动执行 lint 检查 (
nginx -t
、docker-compose config
)、推送到测试环境、通过 Smoke Test 再部署到生产。 - 版本控制:打标签、打版本包;部署时记录变更日志。
最终验证清单
- 浏览器打开
https://monitor.host4/
→ 自动跳/grafana/
或/prometheus/
,页面无 Mixed‑Content 警告。 - 查看浏览器开发者工具:所有资源都走 HTTPS。
curl -I https://monitor.host4/grafana/
- 302 →
/grafana/login
- 包含
Strict-Transport-Security
头。
- 302 →
- Prometheus 路径、Grafana 路径都做了访问认证与 IP/Basic Auth 控制。
- 日志被正确收集到集中系统,且已有告警规则生效。
- 证书续期脚本通过
certbot renew --dry-run
。 - 定时备份脚本落地、可恢复。