Prometheus存储实战 && HTTPS认证 && 黑盒监控

Prometheus存储实战 && HTTPS认证 && 黑盒监控
[TOC]
环境规划
前三篇打通了 Linux 主机 + 中间件 + 中间件 exporter + 自定义监控 + 服务发现 + 联邦模式 本篇收尾六个方向:
- VictoriaMetrics:单机部署 + Prometheus remote_write 远端存储
- HTTPS & 认证:自建 CA + Basic Auth
- 黑白名单:客户端(node-exporter)+ 服务端(Prometheus)
- 标签管理:relabel_configs / metric_relabel_configs
- blackbox-exporter:HTTP / ICMP / TCP 黑盒探测
- Grafana MySQL 存储:SQLite → MySQL 后端切换
| 虚拟机 | IP | 系统 | 本篇角色 |
|---|---|---|---|
| Prom | 10.0.0.10 | Ubuntu | Prometheus server(HTTPS+认证)+ Grafana(MySQL后端) |
| node1 | 10.0.0.2 | Rocky | node-exporter(黑白名单实验) |
| node2 | 10.0.0.11 | Rocky | node-exporter(黑白名单/探测实验) |
| node3 | 10.0.0.12 | Rocky | node-exporter + VictoriaMetrics + blackbox-exporter |
| Docker | 10.0.0.9 | Ubuntu | MySQL 8.0.36 容器(Grafana存储后端) |
VictoriaMetrics单机部署

为什么要用远端存储?
Prometheus 本地 TSDB 在数据量大时面临磁盘瓶颈和单点风险 VictoriaMetrics 是一个高性能时序数据库,支持 Prometheus remote_write 协议,可以把数据”投递”到远端存储
📌 VictoriaMetrics 的优势
- 比 Prometheus 本地存储压缩率更高,节省磁盘
- 支持 PromQL 兼容查询,Grafana 可直接当数据源
- 单机版免费开源(Apache 2.0),社区活跃

单点部署参考链接:https://docs.victoriametrics.com/victoriametrics/quick-start/#starting-vm-single-from-a-binary
部署VictoriaMetrics

VictoriaMetrics 部署在 node3(10.0.0.12)
1)下载软件包'官方社区版,Apache 2.0 许可'jiuzhao@Ubuntu 下载$ wget -P /home/jiuzhao/下载 https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.150.0/victoria-metrics-linux-amd64-v1.150.0.tar.gzjiuzhao@Ubuntu 下载$ scp /home/jiuzhao/下载/victoria-metrics-linux-amd64-v1.150.0.tar.gz node3:/tmp# 拷贝到 /tmp 目录
2)解压二进制到 /usr/local/bin/[root@node3 ~]# tar tf /tmp/victoria-metrics-linux-amd64-v1.150.0.tar.gzvictoria-metrics-prod[root@node3 ~]# tar xf /tmp/victoria-metrics-linux-amd64-v1.150.0.tar.gz -C /usr/local/bin/[root@node3 ~]# ls /usr/local/bin/victoria-metrics-prod/usr/local/bin/victoria-metrics-prod# 直接解压出单个二进制,不需要额外依赖
3)创建数据目录[root@node3 ~]# mkdir -p /var/lib/victoria-metrics
4)创建 systemd 服务文件[root@node3 ~]# cat > /etc/systemd/system/victoria-metrics.service <<'EOF'[Unit]Description=VictoriaMetrics ServerDocumentation=https://docs.victoriametrics.com/# 等待网络就绪后再启动After=network-online.target# 主动声明依赖网络在线目标Wants=network-online.target
[Service]# 前台常驻进程:拉起即算成功Type=simple# 异常退出时自动重启Restart=on-failure# 重启间隔 3 秒RestartSec=3# 文件描述符上限LimitNOFILE=65536ExecStart=/usr/local/bin/victoria-metrics-prod \ -httpListenAddr=0.0.0.0:8428 \ -storageDataPath=/var/lib/victoria-metrics \ -retentionPeriod=3# -httpListenAddr: 监听地址和端口# -storageDataPath: 数据存储路径# -retentionPeriod=3: 数据保留3个月
[Install]WantedBy=multi-user.targetEOF
5)启动并设置开机自启[root@node3 ~]# systemctl daemon-reload[root@node3 ~]# systemctl enable --now victoria-metrics.service[root@node3 ~]# systemctl status victoria-metrics.service● victoria-metrics.service - VictoriaMetrics Server Loaded: loaded (/etc/systemd/system/victoria-metrics.service; enabled; ...) Active: active (running) since ... Main PID: 12345 (victoria-metrics)✅️ 状态 active (running),启动成功
6)验证端口[root@node3 ~]# ss -ntl | grep 8428LISTEN 0 4096 0.0.0.0:8428 0.0.0.0:*# 8428 端口正常监听 ✅️
7)验证 WebUIhttp://10.0.0.12:8428/# VictoriaMetrics 自带简洁的 Web 界面
配置Prometheus remote_write
在 Prom(10.0.0.10)上修改 Prometheus 配置,开启 remote_write 投递数据到 VictoriaMetrics
1)修改 prometheus.yml,添加 remote_writeroot@Prom ~# vim /etc/prometheus/prometheus.yml...# 在顶级字段中添加 remote_write(与 scrape_configs 同级)remote_write: - url: http://10.0.0.12:8428/api/v1/write# remote_write 使用 VM 的 write 接口root@Prom ~# egrep -v '^[[:space:]]*$|^[[:space:]]*#' /etc/prometheus/prometheus.ymlglobal: scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.alerting: alertmanagers: - static_configs: - targets:rule_files:scrape_configs: - job_name: "prometheus" static_configs: - targets: ["localhost:9090"] labels: app: "prometheus" - job_name: "kpyun-node-exporter" # job 名称自定义 metrics_path: "/metrics" # 被监控路径 scheme: "http" # 协议 static_configs: - targets: ["10.0.0.2:9100","10.0.0.11:9100","10.0.0.12:9100"] # 后端地址remote_write: - url: http://10.0.0.12:8428/api/v1/write
2)检查配置文件语法root@Prom ~# promtool check config /etc/prometheus/prometheus.ymlChecking /etc/prometheus/prometheus.yml SUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntax
3)重启 Prometheusroot@Prom ~# systemctl restart prometheus# remote_write 是顶级字段,需要重启才能生效
4)验证 Prometheus 日志,确认 remote_write 已连接root@Prom ~# tail -f /var/log/prometheus/prometheus.log"msg":"Done replaying WAL","component":"remote","url":"http://10.0.0.12:8428/api/v1/write"✅ remote_watcher 已完成 WAL 重放(启动完成)✅ 目标地址:http://10.0.0.12:8428/api/v1/write(VictoriaMetrics)📌 数据存储架构:本地 + 远端双写
依据我们当前的配置,Prometheus 数据同时存储在两个位置:
| 存储位置 | 配置来源 | 用途 | 优势 |
|---|---|---|---|
| 本地 TSDB | --storage.tsdb.path=/var/lib/prometheus | 快速查询最近数据 | 延迟低,Prometheus 原生格式 |
| VictoriaMetrics | remote_write: url: http://10.0.0.12:8428/api/v1/write | 长期存储 + 备份 | 压缩率高,节省磁盘,支持 PromQL |
-
本地存储是必须的:Prometheus 核心功能依赖本地 TSDB,无法禁用
-
remote_write 是额外的:在本地存储基础上,额外把数据副本发送到远端
-
本地 + VictoriaMetrics 是最完整的方案:本地保证实时告警和近期低延迟查询,远端负责海量历史数据的高性能分析+备份,保证数据持久化
-
本地 TSDB在处理海量历史数据扫描时,性能很差且内存占用极高,容易 OOM
-
VictoriaMetrics 拥有更好的压缩算法和面向扫描的索引结构,在长周期、大数据量查询上,VM 的性能和资源消耗远优于原生 Prometheus
验证数据写入
在 VictoriaMetrics 的 WebUI 中查询数据,确认所有 target 都在写入
1)在 VictoriaMetrics WebUI 查询2)测试查询语句# 查询负载(三个node-exporter)node_load15
# 查询 target 状态up`验证要点`:应该看到 '4 个 target' (Prometheus 自身 + 3 台 node-exporter)都在

在 Grafana 中添加 VictoriaMetrics 作为数据源,并导入 Node Exporter Full 模板
1)添加 VictoriaMetrics 数据源# Grafana WebUI → 连接 → 数据源 → 添加数据源# 选择 Prometheus 类型# URL 填写: http://10.0.0.12:8428# Name 自定义: kpyun-victoria-metrics# 点击 Save & Test✅️ 绿色 'Successfully queried the Prometheus API.' 表示连接成功
2)导入 Grafana 模板# Grafana WebUI → Dashboards → Import# 输入模板 ID: 1860 (Node Exporter Full)# 选择刚创建的 kpyun-victoria-metrics 数据源# 点击 Import✅️ 模板加载成功,可以看到所有节点的详细监控面板集群架构远端存储

1)VirctoriaMetrics集群架构概述集群部署参考链接: https://docs.victoriametrics.com/victoriametrics/quick-start/#starting-vm-cluster-from-binaries https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/#architecture-overview
2)下载软件包jiuzhao@Ubuntu ~$ wget -P /home/jiuzhao/下载https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.150.0/victoria-metrics-linux-amd64-v1.150.0-cluster.tar.gzjiuzhao@Ubuntu ~$ tar tf ~/下载/victoria-metrics-linux-amd64-v1.150.0-cluster.tar.gzvminsert-prodvmstorage-prodvmselect-prod`软件包会提供3个程序,该程序对应了集群的3个组件`VictoriaMetrics 集群三大组件总结
| 组件 (程序) | 角色定位 | 核心职责 | 关键技术细节 | 默认监听端口 (参考) |
|---|---|---|---|---|
| vminsert | 数据写入网关 (无状态) | 接受数据摄入,根据指标名+标签的一致性哈希,将数据分发到不同的 vmstorage 节点 | 无状态,可水平扩展。支持数据副本机制(-replicationFactor),如果副本数>1,会同时写入多个存储节点 | 8480 |
| vmstorage | 数据存储节点 (有状态) | 存储原始时序数据,响应查询时返回指定时间段的数据 | 有状态,需要挂载持久化磁盘。负责数据去重、压缩和保留策略(Retention) | 8482 (接收写入) 8401 (接收查询) |
| vmselect | 数据查询网关 (无状态) | 接收查询请求,向所有 vmstorage 节点拉取数据,合并、去重后排重后返回结果 | 无状态,可水平扩展。查询性能取决于 vmstorage 的数量,并发拉取时加速明显 | 8481 |
Prometheus启用HTTPS及认证
为什么需要HTTPS ?
Prometheus 默认 HTTP 明文传输,生产环境中暴露指标数据存在安全风险
启用 HTTPS + Basic Auth 后,访问 Prometheus WebUI 和 API 都需要证书认证 + 用户名密码
生成 Root CA
生产环境使用权威机构颁发的证书,这里用自签名证书做实验
本实验统一使用 4096 位 RSA 私钥,Root CA、Intermediate CA 和 Prometheus Server Certificate 保持相同的密钥强度 生产环境可根据性能、兼容性和证书机构策略选择 2048、3072 或 4096 位
1)创建证书工作区root@Prom ~# mkdir -p /etc/prometheus/certsroot@Prom ~# cd /etc/prometheus/certsroot@Prom certs# mkdir private certs# private: 存放 Root CA、Intermediate CA 和服务器私钥# certs: 存放各种证书和证书链root@Prom certs# chmod 700 private# 私钥目录只允许 root 访问
2)生成 Root CA 私钥root@Prom certs# openssl genrsa -out private/rootCA.key 4096# 4096 位 RSA 根私钥
3)生成 Root CA 自签名证书root@Prom certs# openssl req -x509 -new -nodes \ -key private/rootCA.key \ -sha256 \ -days 3650 \ -out certs/rootCA.crt \ -subj "/C=CN/ST=Beijing/L=Beijing/O=kpyun/CN=kpyun-RootCA"# rootCA.crt 是后续导入客户端信任库的根证书✅️ Root CA 生成完成生成 Intermediate CA
📌 为什么需要中间证书?
生产环境中 Root CA 通常离线保存(物理锁在保险柜里),不直接签发服务器证书 用 Intermediate CA 代替 Root CA 签发,即使泄露也只影响 Intermediate,吊销即可
1)生成 Intermediate CA 私钥root@Prom certs# openssl genrsa -out private/intermediate.key 4096# 4096 位 RSA Intermediate CA 私钥
2)生成 Intermediate CA 的 CSRroot@Prom certs# openssl req -new \ -key private/intermediate.key \ -out intermediate.csr \ -subj "/C=CN/ST=Beijing/L=Beijing/O=kpyun/CN=kpyun-IntermediateCA"
3)Root CA 签发 Intermediate CAroot@Prom certs# openssl x509 -req \ -in intermediate.csr \ -CA certs/rootCA.crt \ -CAkey private/rootCA.key \ -CAcreateserial \ -out certs/intermediate.crt \ -days 1825 \ -sha256 \ -extfile <(printf "basicConstraints=critical,CA:TRUE,pathlen:0\nkeyUsage=critical,keyCertSign,cRLSign")# pathlen:0 表示不允许继续签发下一级 Intermediate CA
4)验证 Intermediate CAroot@Prom certs# openssl x509 -in certs/intermediate.crt -noout -subject -issuersubject=C=CN, ST=Beijing, L=Beijing, O=kpyun, CN=kpyun-IntermediateCAissuer=C=CN, ST=Beijing, L=Beijing, O=kpyun, CN=kpyun-RootCA✅️ Intermediate CA 已由 Root CA 签发生成 Server Certificate
1)生成 Prometheus 服务器私钥root@Prom certs# openssl genrsa -out private/prometheus.kpyun.com.key 4096# 4096 位 RSA 服务器私钥
2)生成 Prometheus 服务器 CSRroot@Prom certs# openssl req -new \ -key private/prometheus.kpyun.com.key \ -out prometheus.kpyun.com.csr \ -subj "/C=CN/ST=Beijing/L=Beijing/O=kpyun/OU=Prometheus/CN=prometheus.kpyun.com"# 先生成服务器私钥和 CSR,再准备证书扩展信息
3)创建服务器证书扩展文件root@Prom certs# cat > prometheus-server.ext <<'EOF'authorityKeyIdentifier=keyid,issuerbasicConstraints=CA:FALSEkeyUsage=critical,digitalSignature,keyEnciphermentextendedKeyUsage=serverAuthsubjectAltName=@alt_names
[alt_names]DNS.1=kpyun.comDNS.2=prometheus.kpyun.comDNS.3=localhostIP.1=10.0.0.10IP.2=127.0.0.1EOF# SAN 中写入所有实际访问 Prometheus 的域名和 IP
4)Intermediate CA 签发 Prometheus 服务器证书root@Prom certs# openssl x509 -req \ -in prometheus.kpyun.com.csr \ -CA certs/intermediate.crt \ -CAkey private/intermediate.key \ -CAcreateserial \ -out certs/prometheus.kpyun.com.crt \ -days 365 \ -sha256 \ -extfile prometheus-server.ext# 这里用 Intermediate CA 签发,不是 Root CA 直接签发
5)合并完整证书链root@Prom certs# cat certs/prometheus.kpyun.com.crt certs/intermediate.crt > certs/fullchain.crt# fullchain.crt = Prometheus 服务器证书 + Intermediate CA 证书
6)验证完整证书链root@Prom certs# openssl verify \ -CAfile certs/rootCA.crt \ -untrusted certs/intermediate.crt \ certs/prometheus.kpyun.com.crtcerts/prometheus.kpyun.com.crt: OK✅️ Root CA → Intermediate CA → Prometheus Server Certificate 验证通过
7)查看最终目录root@Prom certs# tree ..├── certs│ ├── fullchain.crt│ ├── intermediate.crt│ ├── intermediate.srl│ ├── prometheus.kpyun.com.crt│ └── rootCA.crt├── intermediate.csr├── private│ ├── intermediate.key│ ├── prometheus.kpyun.com.key│ └── rootCA.key├── prometheus-server.ext├── prometheus.kpyun.com.csr└── rootCA.srl准备认证文件
1)生成 Basic Auth 用户密码'使用 htpasswd 工具生成 bcrypt 哈希'root@Prom ~# apt-get -y install apache2-utilsroot@Prom ~# htpasswd -Bbc /tmp/auth kpyun kpyun123-B # 强制使用 bcrypt 加密算法(当前推荐,安全性高)-b # 在命令行中直接提供密码(注意:此方式会暴露密码,生产环境慎用)-c # 创建新文件(若文件已存在则覆盖)Adding password for user kpyunroot@Prom ~# cat /tmp/authkpyun:$2y$05$F99Z4rJKrgrmKaJZt1pVi.NbfEo2KEInl0CCmRjy6RPFfM.kL.dmW# 用户名: kpyun,密码: kpyun123===================================`无需按装,直接生成(系统有 Python 3 和 bcrypt 库)`root@Prom ~# python3 -c 'import bcrypt; pwd="kpyun123"; print("kpyun: " + bcrypt.hashpw(pwd.encode(), bcrypt.gensalt(rounds=10)).decode())'kpyun: $2b$10$yLoDjSLYj5oLa64ptcv9JuFfCAGeKjHIyJGUM7G10Ob4glXn1ZiP2
2)创建 Prometheus 认证配置文件root@Prom ~# cat > /etc/prometheus/auth.yml <<'EOF'tls_server_config: cert_file: /etc/prometheus/certs/certs/fullchain.crt key_file: /etc/prometheus/certs/private/prometheus.kpyun.com.key
basic_auth_users: kpyun: $2y$05$F99Z4rJKrgrmKaJZt1pVi.NbfEo2KEInl0CCmRjy6RPFfM.kL.dmWEOF# cert_file: 使用 fullchain.crt(包含中间证书链)# key_file: private/ 下的 Prometheus 服务端私钥# ⚠️ 密码哈希要从 htpasswd 输出中复制完整⚠️ 认证文件格式注意
basic_auth_users下的密码是 bcrypt 哈希,不是明文- 用户名:
🔥空格🔥哈希(中间有个空格)
- 用户名:
- YAML 缩进必须用空格,不能用 Tab
- 证书路径要写绝对路径
HTTPS访问并抓取自身
1)修改 Prometheus 的 systemd 服务,添加 --web.config.file 参数root@Prom ~# vim /etc/systemd/system/prometheus.service.... --web.config.file=/etc/prometheus/auth.yml \# --web.config.file: 指定认证配置文件路径# ✅ 重点就加了这一行
2)重启 Prometheusroot@Prom ~# systemctl daemon-reloadroot@Prom ~# systemctl restart prometheusroot@Prom ~# ss -ntl | grep 9090LISTEN 0 4096 *:9090 *:*# 端口正常监听
3)浏览器访问# 打开 https://10.0.0.10:9090# 浏览器会提示"不安全"(自签名证书),点击"继续访问"# 弹出认证框,输入用户名: kpyun,密码: kpyun123✅️ 登录成功,看到 Prometheus WebUI
4)命令行验证root@Prom ~# curl -k -u kpyun:kpyun123 https://10.0.0.10:9090/-/healthyPrometheus Server is Healthy.✅️ HTTPS + Basic Auth 均正常
5)不带认证测试(应被拒绝)root@Prom ~# curl -k https://10.0.0.10:9090/-/healthy401 Unauthorized✅️ 未认证访问被正确拦截
https://10.0.0.10:9090/targets?search=prometheus
Prometheus 启用 HTTPS 后,需要配置它自己也通过 HTTPS 来抓取自身指标

官方配置说明:https://prometheus.io/docs/prometheus/3.13/configuration/configuration/
1)修改 prometheus.yml 中 prometheus jobroot@Prom ~# vim /etc/prometheus/prometheus.yml... - job_name: "prometheus" scheme: 'https' tls_config: insecure_skip_verify: true # 自签名证书,跳过校验 basic_auth: username: kpyun password: kpyun123 static_configs: - targets: ["10.0.0.10:9090"]# scheme: https → 使用 HTTPS 协议# insecure_skip_verify: true → 不校验证书(自签名场景)
2)热加载配置root@Prom ~# curl -k -u kpyun:kpyun123 -X POST https://10.0.0.10:9090/-/reload# -k: 跳过证书校验# -u: Basic Auth 认证
3)验证抓取状态# 浏览器访问 https://10.0.0.10:9090/targets?search=prometheus# Prometheus job 的 target 状态应为 UP ✅️
📌 热加载 vs 重启
| 方式 | 命令 | 影响 |
|---|---|---|
| 热加载 | curl -X POST http://localhost:9090/-/reload | 只更新配置,不中断服务(需要 --web.enable-lifecycle) |
| 重启 | systemctl restart prometheus | 重启进程,会短暂中断抓取 |
关键区别:
scrape_configs、alerting、rule_files等抓取相关字段:热加载即可生效remote_write、remote_read、global等顶级字段:必须重启才能生效,热加载无效
生产环境优先用热加载,只有修改顶级字段时才走重启
导入CA证书
1)拷贝到宿主机jiuzhao@Ubuntu 下载$ scp Prom:/etc/prometheus/certs/certs/rootCA.crt .
2)修改宿主机 hosts表jiuzhao@Ubuntu ~$ sudo vim /etc/hosts10.0.0.10 prometheus.kpyun.com kpyun.com`两个域名都可以进行访问`
3)CA证书导入浏览器edge://certificate-manager/localcerts/usercerts# 在“受信任的证书”栏目下,点击 “导入” (刚才拷贝的 rootCA.crt 文件)
4)测试访问https://prometheus.kpyun.com:9090# 地址栏应显示安全锁标志,不再提示“您的连接不是私密连接”

1)未导入系统证书root@Prom ~# curl -u kpyun:kpyun123 https://10.0.0.10:9090/-/healthycurl: (60) SSL certificate problem: unable to get local issuer certificate`SSL证书问题:无法获取本地颁发者证书`# 需要 -k 跳过 SSL 校验
2)根证书导入 Linux 系统信任库# 复制根证书到系统证书目录root@Prom ~# sudo cp /etc/prometheus/certs/certs/rootCA.crt /usr/local/share/ca-certificates/
# 更新系统证书库root@Prom ~# sudo update-ca-certificates
3)不再需要 -k(跳过校验)SSL 校验通过root@Prom ~# curl -u kpyun:kpyun123 https://10.0.0.10:9090/-/healthyPrometheus Server is Healthy.node-exporter黑白名单

黑白名单用于控制采集哪些指标,可以从客户端(exporter)或服务端(Prometheus)两个维度实现
| 维度 | 黑名单 | 白名单 |
|---|---|---|
| 客户端 | --no-collector.xxx | --collector.disable-defaults --collector.xxx |
| 服务端 | params: exclude[]: [xxx] | params: collect[]: [xxx] |
| 效果 | 该指标不暴露/不采集 | 只暴露/采集指定指标 |
客户端黑白名单
在 node1(10.0.0.2)上操作 node-exporter 进程
1)停止 node-exporter 服务[root@node1 ~]# systemctl stop node-exporter
2)【黑名单】禁用指定 collector[root@node1 ~]# node_exporter --version | head -1node_exporter, version 1.12.1[root@node1 ~]# node_exporter \ --no-collector.cpu \ --no-collector.meminfo \ --no-collector.loadavg# --no-collector.cpu: 不采集 CPU 指标# --no-collector.meminfo: 不采集内存信息# --no-collector.loadavg: 不采集负载信息
root@Prom ~# curl -s 10.0.0.2:9100/metrics | grep -c node_cpu_*0# 访问 http://10.0.0.2:9100/metrics 验证# node_cpu_* 指标: 🈚 不存在# node_memory_* 指标: 🈚 不存在# node_load* 指标: 🈚 不存在✅️ 黑名单生效,指定指标已隐藏
3)【白名单】只启用指定 collector[root@node1 ~]# node_exporter \ --collector.disable-defaults \ --collector.cpu \ --collector.uname \ --collector.diskstats# --collector.disable-defaults: 先禁用所有 collector# --collector.cpu: 只启用 CPU collector# --collector.uname: 只启用系统信息 collector# --collector.diskstats: 只启用磁盘统计 collector
root@Prom ~# curl -s 10.0.0.2:9100/metrics | grep -c node_disk_*98# 访问 http://10.0.0.2:9100/metrics 验证# 指标数量大幅减少,只保留 cpu/uname/diskstats 相关# node_cpu_seconds_total: ✅️ 存在# node_uname_info: ✅️ 存在# node_disk_*: ✅️ 存在root@Prom ~# curl -s 10.0.0.2:9100/metrics | grep -c node_memory_*0# node_memory_*: 🈚 不存在# node_load*: 🈚 不存在✅️ 白名单生效,只暴露指定指标
4)恢复默认配置并重启服务[root@node1 ~]# systemctl start node-exporter# 测试完毕恢复原状服务端黑白名单
在 Prom(10.0.0.10)上通过 Prometheus 配置控制采集
1)【黑名单】排除指定 collectorroot@Prom ~# vim /etc/prometheus/prometheus.yml... - job_name: "kpyun-blacklist" params: exclude[]: - cpu - meminfo static_configs: - targets: ["10.0.0.2:9100"]# exclude[]: 排除 cpu 和 meminfo collector
2)检查配置并热加载root@Prom ~# promtool check config /etc/prometheus/prometheus.ymlChecking /etc/prometheus/prometheus.yml SUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntaxroot@Prom ~# curl -k -u kpyun:kpyun123 -X POST https://10.0.0.10:9090/-/reload
3)验证黑名单# Prometheus WebUI 查询:node_cpu_seconds_total{job="kpyun-blacklist",instance="10.0.0.2:9100"}# 🈚 无数据(被 exclude 排除了)node_uname_info{job="kpyun-blacklist",instance="10.0.0.2:9100"}# ✅️ 有数据(uname 未被排除)✅️ 服务端黑名单生效
4)【白名单】只采集指定 collectorroot@Prom ~# vim /etc/prometheus/prometheus.yml... - job_name: "kpyun-whitelist" params: collect[]: - uname - diskstats static_configs: - targets: ["10.0.0.2:9100"]# collect[]: 只采集 uname 和 diskstats
5)检查配置并热加载root@Prom ~# promtool check config /etc/prometheus/prometheus.ymlroot@Prom ~# curl -k -u kpyun:kpyun123 -X POST https://10.0.0.10:9090/-/reload
6)验证白名单# Prometheus WebUI 查询:node_uname_info{job="kpyun-whitelist",instance="10.0.0.2:9100"}# ✅️ 有数据node_disk_io_now{job="kpyun-whitelist",instance="10.0.0.2:9100"}# ✅️ 有数据node_cpu_seconds_total{job="kpyun-whitelist",instance="10.0.0.2:9100"}# 🈚 无数据(collect 未包含 cpu)✅️ 服务端白名单生效💡 客户端 vs 服务端黑白名单的区别
- 客户端:直接控制 exporter 暴露哪些指标,减少网络传输量
- 服务端:Prometheus 侧过滤,exporter 仍然暴露全部指标
- 生产环境建议客户端优先,减少 exporter 的资源开销 ✅️
标签管理
Prometheus 的每一条**时间序列(time series)**都由两部分唯一确定:
- 指标名(如
node_cpu_seconds_total) - 一组标签(labels),也就是这条序列的”维度”,例如
job="node"、instance="10.0.0.2:9100"、cpu="0"
同一个指标名 + 不同的标签组合 = 不同的时间序列,换言之,标签就是用来区分、过滤、聚合数据的维度——没有标签,你就没法在 PromQL 里写 up{job="node"} 去按 job 筛选,也没法按 instance 看单台机器的曲线
📌 先认清”指标名”和”series(时间序列)”
- 指标名(metric name):如
node_cpu_seconds_total,只是一个名字(类别) - series(时间序列):
指标名 + 全部标签的唯一组合,才是真正落盘、能被查询的那条数据线 - 一个指标名下会有成百上千条 series(每个 CPU 核、每台机器各一条,标签不同就另算一条)
- 后面会看到
metric_relabel_configs里用source_labels: [__name__]+drop,是按指标名筛、一次性删掉该指标名下的所有 series——口语说”删掉整个指标”没错,但严谨的底层对象是 series(时间序列)
💡 一句话:指标名是”类别”,series(时间序列)是该类下带具体标签的一条条真实数据;后面所有 relabel 操作,本质都是在搬动、筛选这些 series 及其标签
Prometheus 的标签按来源和生命周期可以分为四类:
| 标签类型 | 格式/示例 | 生命周期 | 说明 |
|---|---|---|---|
| 自动注入标签(保留标签) | job、instance | 持久化存储 | 抓取时自动附加到每条时间序列:job=当前 job_name,instance=target 的 __address__(host这两个标签永远存在, action: labeldrop 对它们无效 |
| 内部标签(临时,双下划线) | __address__、__scheme__、__metrics_path__、__param_*、__scrape_interval__、__scrape_timeout__ | 抓取后丢弃 | 抓取前(relabel_configs 阶段)存在,用于定位目标与传递参数,不写入 TSDB,relabel_configs 结束后即被丢弃,只有被它映射到非 __ 标签才会保留 |
| 服务发现标签 | __meta_* | 抓取后丢弃 | 服务发现(consul/file_sd/k8s 等)产生的元数据标签,仅 relabel_configs 阶段可用,默认抓取后被丢弃,需在 relabel_configs 中用 keep/labelmap 才能保留 |
| 自定义标签 | 用户自定义(如 auther、school、class) | 持久化存储 | 在 static_configs 的 labels: 手动添加,或在 relabel 规则(relabel_configs / metric_relabel_configs)中用 replace/labelmap 生成 |
📌 job/instance 与 __address__ 的区别(重要)
__address__是内部临时标签,抓取完成后被丢弃instance是 Prometheus 从__address__自动固化出来的保留标签,会持久化- 同理
job来自job_name,也是自动注入并保留 - 所以”默认存在的标签”不是
__address__,而是job和instance,这也是为什么labeldrop删不掉它们——relabel_configs结束后会由__address__/job_name重新派生
📌 __meta_* 服务发现标签的生命周期(重要)
- 由服务发现(consul/k8s/file_sd 等)在发现 target 时附加,
static_configs静态配置没有__meta_* - 只在
relabel_configs阶段可用,常用labelmap把它映射成正式标签,或用keep/drop基于它筛选 target - 抓取完成后自动丢弃,不会写入 TSDB——想保留必须先在
relabel_configs阶段映射/保留出来
流程架构
一条时间序列从”被发现”到”落盘”,标签会经历下面这条流水线,先记住两个关键停靠点:relabel_configs(抓取前) 和 metric_relabel_configs(抓取后),后面会反复用到
两个 relabel 阶段的根本区别
这是整个标签管理最核心、也最容易混的概念,只在这里讲一次,后面实战不再重复
📌 relabel_configs vs metric_relabel_configs
relabel_configs:作用于抓取前,操作 target 的标签(如修改__address__、instance)metric_relabel_configs:作用于抓取后,操作已采集的指标标签(如删除某些指标)- ⚠️
relabel_configs阶段job/instance不能用labeldrop删除(relabel_configs结束后会由__address__/job_name重新派生),但可用replace等动作修改 - 📌
instance默认取值 =relabel_configs后__address__的值,所以改__address__会连带改instance,黑盒探测正是先改__address__为 blackbox 地址,再显式把instance设回真实目标,二者才被解耦
📌 两套 7 种 action 完全通用,但”对象”不同:下面列出的 7 种动作,relabel_configs 和 metric_relabel_configs 都能写,区别只在前者动 target、后者动已采集的样本——同一个 action: drop,在 relabel_configs 丢整条 target,在 metric_relabel_configs 只丢匹配的 series(时间序列)(target 早已抓取完,丢不掉了)。因此 action 只讲一次,实战里直接套用
action 速查
relabel_configs / metric_relabel_configs 都是基于正则对标签做”整形”,支持 7 种 action(其中 replace 是默认动作,省略 action: 即按 replace 处理),先按作用层级分成两类:target 级(整条保留/丢弃)和标签级(改/删某个 key)
| 动作 | 作用层级 | 效果 | 典型示例 | 常见用途 |
|---|---|---|---|---|
replace(默认动作) | 标签级 | source_labels+regex 匹配,结果写入 target_label(标签不存在则新建,存在则覆盖) | __address__→instance | 生成/改写标签、黑盒改 __address__ |
keep | target 级 | source_labels 匹配则保留该 target,否则整条丢弃 | keep __meta_kubernetes_namespace=~"kube-system" | 只采集特定 target |
drop | target 级 | source_labels 匹配则丢弃该 target | drop __meta_.* 某条件 | 排除不需要的 target |
labelmap | 标签级 | 把匹配 regex 的标签名映射成新标签名(值复制过去) | (job|app) → ${1}_kpyun | 批量重命名标签 |
labeldrop | 标签级 | 按**标签名(key)**匹配,删掉整个 key=value(值随 key 一起消失) | labeldrop (job|app) | 去掉敏感/多余标签 |
labelkeep | 标签级 | 只保留匹配 key 的标签(整条 key=value),其余删除 | labelkeep (job|instance|__name__) | 精简标签、降基数 |
hashmod | 标签级 | 对 source_labels 哈希取模,结果写入 target_label(配 modulus) | hashmod modulus: 4 | 多 Prometheus 分片采集 |
📌 replacement 字段的双向语义
- 在
replace里:target_label决定”写到哪个标签(名)“,replacement决定”写什么值”(可引用${1}等捕获组重组来源值);不写source_labels时,replacement就是写死的固定值(如 blackbox 地址) - 在
labelmap里:replacement配合正则捕获组(如${1})决定”新标签的名”,值原样复制过去——所以 labelmap 的replacement改的是名 - 一句话:
replacement既能改值(replace 场景)也能改名(labelmap 场景),区别在于 action
⚠️ 上表”target 级 / 标签级”的划分是基于 relabel_configs(抓取前) 的视角:keep/drop 在这里决定整条 target 采不采集;到了 metric_relabel_configs(抓取后),同样的 7 种 action 都能写,但 keep/drop 作用的对象变成了已采集的 series(时间序列)——丢的是匹配的 series(时间序列),不是 target 本身
📌 怎么区分这些 action(重要,一次讲清)
- target 级 vs 标签级:
keep/drop没带label,动的是”整条 target 采不采集”(作用于整个抓取目标),labelkeep/labeldrop带label,动的是”这条序列上保留/删除哪些 key”(target 照采,只是标签被筛掉),记忆口诀:没label动 target,有label动标签名 - 动 key 还是 value:
labeldrop/labelkeep只按标签名(key)匹配,删/留的是整个key=value,值跟着 key 一起走,不存在”只删 key 留 value”,想改值用replace(读 source_labels 的值、正则重组后写进target_label,已存在则覆盖其值=改值,不存在则新建标签);⚠️replace只产出一个target_label,不删标签、不能直接改名(改名用labelmap),source_labels仅作输入、自身不会被改动,keep/drop在relabel_configs阶段根本不碰 key/value,直接决定整条 target 采不采集(到了metric_relabel_configs阶段则改为决定哪些 series(时间序列) 留存) - target / instance / 时间序列 的关系:一个 target(如
10.0.0.2:9100)= 一个instance标签的值,一个 instance 被抓取后会产出成百上千条时间序列(node_load5、各 CPU 核的 node_cpu_* 等),它们共享同一个instance/job,所以keep/drop丢掉 target 是丢掉它名下所有序列,labelkeep/labeldrop只是把每条序列上的某些标签 key 筛掉,序列本身还在
实战演练
下面从最简单的”加标签”开始,逐步做标签操作实验
1️⃣ 自定义标签(static_configs labels)
在 static_configs 中为 targets 添加自定义标签:
1)修改 prometheus.ymlroot@Prom ~# vim /etc/prometheus/prometheus.yml... - job_name: "kpyun-custom-labels" static_configs: - targets: ["10.0.0.2:9100","10.0.0.11:9100","10.0.0.12:9100"] labels: auther: jiuzhao school: kpyun-edu class: C413# labels 下自定义三个标签: auther、school、class'给每个 target 打上同样的自定义标签'
2)检查配置并热加载root@Prom ~# promtool check config /etc/prometheus/prometheus.ymlSUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntax✅️ 配置语法没问题root@Prom ~# curl -k -u kpyun:kpyun123 -X POST https://10.0.0.10:9090/-/reload'热加载,不用重启 Prometheus'
3)验证自定义标签# Prometheus WebUI 查询:up{job="kpyun-custom-labels"}# 每个 target 都带上了 auther="jiuzhao"、school="kpyun-edu"、class="C413"
https://prometheus.kpyun.com:9090/query
📌 relabel_configs vs labels 的区别
labels:直接在 static_configs 中添加,简单但功能有限(只能写死值)relabel_configs:基于正则进行标签操作,可拼接、映射、删除,功能更强
2️⃣ relabel_configs 实战:replace 改写/合成标签
用 replace 读取源标签(多个值可先拼接)、经正则重组后写入目标标签(不存在则新建、存在则覆盖):
💡 replace 是 relabel 的默认动作,“拼接”只是 source_labels 多值、靠 separator 粘起来时的可选手段;它只把结果写到 target_label——能改值、能新建标签,但不能删标签、不能直接改名
1)修改 prometheus.ymlroot@Prom ~# vim /etc/prometheus/prometheus.yml... - job_name: "kpyun-relabel-replace" static_configs: - targets: ["10.0.0.2:9100","10.0.0.11:9100","10.0.0.12:9100"] labels: auther: jiuzhao relabel_configs: # 指定源标签: 将 __scheme__、__address__、__metrics_path__ 拼接 - source_labels: - __scheme__ - __address__ - __metrics_path__ # 正则分组匹配,"${1}" 和 "${2}" 引用匹配结果 regex: "(http|https)(.*)" # 拼接分隔符,不指定默认为分号 ";" # 空字符串,拼接时源标签的值之间什么都不加 separator: "" # 替换值: scheme://address+path replacement: "${1}://${2}" # 新标签名称 target_label: "kpyun_prometheus_ep" action: replace# 假设数据: __scheme__="http", __address__="10.0.0.2:9100", __metrics_path__="/metrics"# 拼接后: "http10.0.0.2:9100/metrics"# 正则分组: ${1}="http", ${2}="10.0.0.2:9100/metrics"# 最终 kpyun_prometheus_ep = "http://10.0.0.2:9100/metrics"'把三个内部标签拼成了一个访问端点'
2)检查配置并热加载root@Prom ~# promtool check config /etc/prometheus/prometheus.ymlSUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntax✅️ 配置语法没问题root@Prom ~# curl -k -u kpyun:kpyun123 -X POST https://10.0.0.10:9090/-/reload'热加载'
3)验证替换结果# Prometheus WebUI 查询:up{job="kpyun-relabel-replace"}# 每个 target 多了一个标签 kpyun_prometheus_ep,值为 "http://10.0.0.x:9100/metrics"
3️⃣ relabel_configs 实战:labelmap + labeldrop
将已有标签通过正则映射生成新标签,再删除原始标签:
📌 labelmap 的机理
拿标签的”名”(key)去匹配正则,把匹配到的标签改名,值原样复制过去
例如 regex:"__address__" + replacement:"__param_target",会造出 __param_target=原值
💡 它适合”按标签名批量重命名”
1)修改 prometheus.ymlroot@Prom ~# vim /etc/prometheus/prometheus.yml... - job_name: "kpyun-labelmap" static_configs: - targets: ["10.0.0.2:9100","10.0.0.11:9100","10.0.0.12:9100"] relabel_configs: # labelmap: 将匹配到的标签名映射为新标签名(值复制过去) - regex: "(job|app)" replacement: "${1}_kpyun_labelmap" action: labelmap # 把 job 的值复制到 job_kpyun_labelmap # 如 job="kpyun-labelmap" → job_kpyun_labelmap="kpyun-labelmap" - regex: "(job|app)" action: labeldrop # 删除匹配到的 job 和 app 标签(连同值一起消失)'先复制一份新标签,再删掉旧的'
2)检查配置并热加载root@Prom ~# promtool check config /etc/prometheus/prometheus.ymlroot@Prom ~# curl -k -u kpyun:kpyun123 -X POST https://10.0.0.10:9090/-/reload
3)验证 labelmap 结果# Prometheus WebUI 查询:up{job_kpyun_labelmap="kpyun-labelmap"}# ✅️ 原始 job 标签已删除,新标签 job_kpyun_labelmap 存在`标签值(kpyun-labelmap)不变,直接复制过去`# 🈚 up{job="kpyun-labelmap"} → 查不到(job 已被 drop)

4️⃣ metric_relabel_configs 实战:按 name 删指标
metric_relabel_configs 运行在”数据已拉回、但还没写进 TSDB 之前”,典型用途是按 __name__ 删除整个指标以省存储
💡 注意这里的 drop 和 relabel_configs 里的 drop 不是一回事:此刻 target 早已抓取完成,drop 不可能再丢整条 target 链条,它只能丢掉匹配到的 series(时间序列)——target 照抓、其它指标照存
1)修改 prometheus.ymlroot@Prom ~# vim /etc/prometheus/prometheus.yml... - job_name: "kpyun-metric-relabel" static_configs: - targets: ["10.0.0.2:9100","10.0.0.11:9100","10.0.0.12:9100"] relabel_configs: - regex: "(job|app)" replacement: "${1}_kpyun_test" action: labelmap - regex: "(job|app)" action: labeldrop metric_relabel_configs: # 删除所有 node_cpu_* 开头的指标 - source_labels: - __name__ regex: "node_cpu_.*" action: drop# __name__ 是指标名称的内置标签# regex 匹配所有 node_cpu_* 指标,执行 drop 动作'抓取后直接把整类指标扔掉,省存储'
2)检查配置并热加载root@Prom ~# promtool check config /etc/prometheus/prometheus.ymlSUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntax✅️ 配置语法没问题root@Prom ~# curl -k -u kpyun:kpyun123 -X POST https://10.0.0.10:9090/-/reload'热加载'
3)验证 metric_relabel_configs 结果# 测试语句 1: 查询 node_cpu 指标node_cpu_seconds_total{job_kpyun_test="kpyun-metric-relabel"}[10s]# 🈚 无数据(被 metric_relabel_configs drop 了)
# 测试语句 2: 查询 node_load 指标哈哈node_load5{job_kpyun_test="kpyun-metric-relabel"}[10s]# ✅️ 有数据(node_load 不在 drop 列表中)✅️ metric_relabel_configs 过滤成功

💡 怎么选(决策清单)
- 要修改 target 的标签(如改
__address__、instance)→ 用relabel_configs - 要删除/修改已采集的指标(如按
__name__过滤 collector)→ 用metric_relabel_configs - 要控制采集哪些 collector → 用黑白名单(更简单,见上节 node-exporter 黑白名单)
- 不确定?记住一句话:抓取前动 target 用前者,抓取后动样本用后者
blackbox-exporter黑盒监控
| 对比 | 白盒监控 | 黑盒监控 |
|---|---|---|
| 关注点 | 内部指标(CPU、内存、磁盘) | 外部结果(端口、HTTP状态码、连通性) |
| 时机 | 事件未发生时预测 | 事件已发生后检测 |
| 类比 | 看汽车仪表盘的油量,提前加油 | 车开不动了才知道没油了 |
| 组件 | node-exporter、各种 exporter | blackbox-exporter |
📌 为什么黑盒只能”事后检测”、白盒能”事前预测”
- 黑盒(blackbox-exporter):从外部探(HTTP 通不通、端口在不在、ping 得通不通)
- 它探测失败的那一刻,故障对用户已经发生了——网站已经打不开了,你才探测到失败
- 它是”黑盒”看不到服务内部,根本没有内部指标可用来预测,只能事后发现
- 白盒(node-exporter 等):看内部指标(CPU、内存、磁盘、错误率、队列长度…)
-
这些指标往往在”用户可见的大故障”之前就出现异常趋势(内存缓慢上涨、错误率从 0.1% 爬到 1%、TCP 重传变多)
-
所以能靠前置信号提前预警,当然故障真发生了它也能检测
-
💡 一句话:白盒 = 能事前预测(看内部趋势)+ 能事后检测;黑盒 = 只能事后检测(看不到内部,无法预测)
blackbox-exporter 支持基于 HTTP、HTTPS、DNS、TCP、ICMP、gRPC 协议对目标进行探测
📌 blackbox-exporter 的定位
一般用于监控:网站是否存活、端口是否监听、证书是否过期 它不是采集内部指标,而是从外部视角验证服务是否可达
部署blackbox-exporter

- GitHub项目地址 :https://github.com/prometheus/blackbox_exporter
# blackbox-exporter 部署在 `node3`(10.0.0.12)
1)下载软件包[root@node3 ~]# wget -P /tmp https://github.com/prometheus/blackbox_exporter/releases/download/v0.28.0/blackbox_exporter-0.28.0.linux-amd64.tar.gz'包先放 /tmp'
2)解压[root@node3 ~]# tar tf /tmp/blackbox_exporter-0.28.0.linux-amd64.tar.gzblackbox_exporter-0.28.0.linux-amd64/blackbox_exporter-0.28.0.linux-amd64/LICENSE # ❌没用blackbox_exporter-0.28.0.linux-amd64/NOTICE # ❌没用blackbox_exporter-0.28.0.linux-amd64/blackbox.ymlblackbox_exporter-0.28.0.linux-amd64/blackbox_exporter[root@node3 ~]# mkdir -p /etc/blackbox/ && tar xf /tmp/blackbox_exporter-0.28.0.linux-amd64.tar.gz -C /etc/blackbox/ --strip-components 1 blackbox_exporter-0.28.0.linux-amd64/blackbox.yml[root@node3 ~]# tar xf /tmp/blackbox_exporter-0.28.0.linux-amd64.tar.gz -C /usr/local/bin/ --strip-components 1 blackbox_exporter-0.28.0.linux-amd64/blackbox_exporter'二进制进 /usr/local/bin,配置进 /etc/blackbox'[root@node3 ~]# blackbox_exporter --version | head -1blackbox_exporter, version 0.28.0✅️ 版本正确,二进制与配置就位
3)查看默认配置[root@node3 ~]# cat /etc/blackbox/blackbox.ymlmodules: http_2xx: prober: http http: preferred_ip_protocol: "ip4" ....... tcp_connect: prober: tcp icmp: prober: icmp# 默认支持 http_2xx、tcp_connect、icmp、grpc、ssh、postgresql 等模块
4)启动 blackbox-exporter[root@node3 ~]# blackbox_exporter --config.file=/etc/blackbox/blackbox.yml# 默认监听 0.0.0.0:9115# 后台运行: nohup 或写 systemd 服务'指定配置文件路径再启动'
5)验证端口[root@node3 ~]# ss -ntl | grep 9115LISTEN 0 4096 0.0.0.0:9115 0.0.0.0:*
6)访问 WebUI# 浏览器访问 http://10.0.0.12:9115/# 可以在 Web 界面上直接测试探测HTTP探测
通过 blackbox 的 http_2xx 模块探测目标网站是否返回 200 状态码
1)在 blackbox WebUI 测试# 浏览器访问 http://10.0.0.12:9115/# 选择模块: http_2xx# Target 填写: www.baidu.comhttp://10.0.0.12:9115/probe?target=www.baidu.com&module=http_2xx
2)测试多个 HTTP 目标# www.baidu.com → ✅️ success(HTTP 200)# 10.0.0.2:9100(node1 node-exporter)→ ✅️ success# 10.0.0.11:9100(node2 node-exporter)→ ✅️ success
3)在 Prometheus 中配置 HTTP 探测root@Prom ~# vim /etc/prometheus/prometheus.yml... - job_name: "kpyun-blackbox-http" # 修改访问路径 /probe → blackbox 的探测接口 metrics_path: /probe # params.module: http_2xx → 使用 HTTP 2xx 模块(从而判断相应的返回状态码是否为200) params: module: [http_2xx] # 静态配置,需要手动指定监控目标 static_configs: # 需要监控的目标 - targets: # 支持 https 协议 - https://www.baidu.com # 支持 http 协议和自定义端口 - http://10.0.0.2:9100 - http://10.0.0.11:9100 # 对目标节点进行重新打标签配置 relabel_configs: # ① 读 __address__ 的值,写入 __param_target → URL 里变成 ?target=真实目标 - source_labels: [__address__] target_label: __param_target # ② 把真实目标也写进 instance 标签,否则第③步改完 __address__ 后 instance 会被推导成 blackbox 地址,分不清谁是谁 - source_labels: [__param_target] target_label: instance # ③ 直接把 __address__ 设成固定值(blackbox 地址),让 Prometheus 真正去问 blackbox 而非直连目标 - target_label: __address__ replacement: 10.0.0.12:9115# 三条规则都没写 action,因为默认动作就是 replace# ① 决定探谁(?target=) / ② 保留身份(instance) / ③ 把抓取对象重定向到 blackbox# 最终 Prometheus 请求 10.0.0.12:9115/probe?target=xxx&module=http_2xx
4)热加载并验证root@Prom ~# promtool check config /etc/prometheus/prometheus.ymlroot@Prom ~# curl -k -u kpyun:kpyun123 -X POST https://10.0.0.10:9090/-/reload`Prometheus WebUI → Targets: kpyun-blackbox-http 的所有 target 状态应为 UP`# 查询探测指标: probe_success{job="kpyun-blackbox-http"}# ✅️ 全部返回 1(成功)

💡 relabel_configs 的核心逻辑
黑盒探测的 relabel_configs 都是同一个套路(三步顺序不能乱):
① 把 __address__(真实目标)复制到 __param_target(URL 参数 ?target=)
② 把 __param_target 复制到 instance(序列标识/查询用,用来区分每条探测结果)
③ 把 __address__ 替换为 blackbox-exporter 的地址(真正去请求的地址)
⚠️ ② 必须在 ③ 之前:否则 instance 会被改写成 blackbox 地址,分不清谁是谁

📌 Grafana 导入 blackbox 模板
常用 blackbox 模板 ID:
- 7587:Blackbox Exporter
- 13659:Blackbox Exporter (HTTP prober)
在 Grafana → Dashboards → Import 中输入模板 ID,选择对应数据源即可


ICMP探测
通过 blackbox 的 icmp 模块探测目标主机是否可达(ping)
1)在 blackbox WebUI 测试# 选择模块: icmp# Target: 10.0.0.2 → ✅️ successhttp://10.0.0.12:9115/probe?target=10.0.0.2&module=icmp
2)在 Prometheus 中配置 ICMP 探测root@Prom ~# vim /etc/prometheus/prometheus.yml... - job_name: "kpyun-blackbox-icmp" metrics_path: /probe params: module: [icmp] static_configs: - targets: - 10.0.0.2 - 10.0.0.11 - 10.0.0.12 relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: 10.0.0.12:9115
3)热加载并验证root@Prom ~# promtool check config /etc/prometheus/prometheus.ymlroot@Prom ~# curl -k -u kpyun:kpyun123 -X POST https://10.0.0.10:9090/-/reload
# 查询: probe_success{job="kpyun-blackbox-icmp"}# ✅️ 全部返回 1(ping 通)TCP探测
通过 blackbox 的 tcp_connect 模块探测目标端口是否监听
1)在 blackbox WebUI 测试# 选择模块: tcp_connect# Target: 10.0.0.2:22 → ✅️ success(SSH 端口)# Target: 10.0.0.11:9100 → ✅️ success(node-exporter 端口)# Target: 10.0.0.10:9090 → ✅️ success(Prometheus 端口)http://10.0.0.12:9115/probe?target=10.0.0.2:22&module=tcp_connect
2)在 Prometheus 中配置 TCP 探测root@Prom ~# vim /etc/prometheus/prometheus.yml... - job_name: "kpyun-blackbox-tcp" metrics_path: /probe params: module: [tcp_connect] static_configs: - targets: - 10.0.0.2:22 - 10.0.0.11:9100 - 10.0.0.10:9090 relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: 10.0.0.12:9115
3)热加载并验证root@Prom ~# promtool check config /etc/prometheus/prometheus.ymlroot@Prom ~# curl -k -u kpyun:kpyun123 -X POST https://10.0.0.10:9090/-/reload
# 查询: probe_success{job="kpyun-blackbox-tcp"}# ✅️ 全部返回 1(端口可达)Grafana指定MySQL存储

Grafana 默认使用 SQLite 数据库存储元数据(dashboard、用户、数据源配置等)
1)查看配置文件默认数据库类型root@Prom ~# grep sqlite3 /etc/grafana/grafana.ini | grep -v '^#';type = sqlite3# 分号开头表示被注释,是默认值
2)查看本地 SQLite 数据库文件root@Prom ~# ll -lh /var/lib/grafana/ | grep 'grafana\.db'-rw-r----- 1 grafana grafana 8.6M Aug 21 08:29 grafana.dbroot@Prom ~# file /var/lib/grafana/grafana.db/var/lib/grafana/grafana.db: SQLite 3.x database, ...# 确认当前使用 SQLite📌 为什么要切换到 MySQL
SQLite 是单文件数据库,适合开发和小规模使用 生产环境中,Grafana 连接数多、数据量大时,SQLite 性能不足 切换到 MySQL 后,元数据存储在远程数据库,Grafana 服务器可以无状态扩展
准备MySQL环境
Docker VM(10.0.0.9)上有 MySQL 镜像,只需创建对应的容器( Grafana 专用的库和用户)
1)创建数据库root@Docker ~# docker container run \ -e MYSQL_ALLOW_EMPTY_PASSWORD="yes" \ -d \ -p 3306:3306 \ --name mysql-server \ -e MYSQL_DATABASE="grafana" \ -e MYSQL_USER="grafana" \ -e MYSQL_PASSWORD="oldboy123.com" \ -e TZ=Asia/Shanghai \ mysql:8.0.36 \ --character-set-server=utf8mb4 \ --collation-server=utf8mb4_unicode_ci \ --default-authentication-plugin=mysql_native_password \ --default-time-zone='+8:00'
2)确认 MySQL 容器运行状态root@Docker ~# docker ps -lmysql:8.0.36 "docker-entrypoint.s…" Up 0.0.0.0:3306->3306/tcp, 33060/tcp mysql-serverroot@Docker ~# ss -ntl | grep 3306LISTEN 0 151 *:3306 *:*✅️ MySQL 容器正常运行
3)登录 MySQL 验证 Grafana 数据库和用户root@Docker ~# docker exec -it mysql-server mysqlWelcome to the MySQL monitor.Server version: 8.0.36 MySQL Community Server - GPL
mysql> SHOW DATABASES;+--------------------+| Database |+--------------------+| grafana || information_schema || mysql || performance_schema || sys |+--------------------+
mysql> SELECT USER, HOST FROM mysql.user WHERE USER='grafana';+---------+------+| USER | HOST |+---------+------+| grafana | % |+---------+------+✅️ grafana 数据库和用户创建完成
mysql> USE grafana;Database changed
mysql> SHOW TABLES;Empty set (0.00 sec)`grafana 数据库里面一张表都没有`存储迁移到MySQL
1)修改 Grafana 配置文件root@Prom ~# vim /etc/grafana/grafana.ini...[database]# 默认被注释的是 sqlite3# type = sqlite3# path = /var/lib/grafana/grafana.db
# 修改为 MySQLtype = mysqlhost = 10.0.0.9:3306name = grafanauser = grafanapassword = oldboy123.com# host: MySQL 容器的 IP 和端口# name: 刚才创建的数据库名# user/password: 刚才创建的用户
2)重启 Grafanaroot@Prom ~# systemctl restart grafana-server.serviceroot@Prom ~# ss -ntl | grep 3000LISTEN 0 4096 *:3000 *:*# 3000 端口正常监听
3)验证 Grafana WebUI 可访问# 浏览器访问 http://10.0.0.10:3000# 使用 admin/admin 登录(首次登录会提示修改密码)✅️ Grafana 正常启动,存储后端已切换到 MySQL⚠️ 切到 MySQL 后首次登录 Grafana 仪表盘/数据源全空,是正常的
- 旧配置(仪表盘、数据源、用户)都还在 SQLite 的
grafana.db里,Grafana 不会跨数据库自动迁移,所以新 MySQL 里是空的 - 你的监控指标(metrics)存在 Prometheus / VictoriaMetrics,根本不在 Grafana 的数据库里,指标数据毫发无损,只是“看板”空了
- 原
grafana.db文件仍在/var/lib/grafana/,可备份保留
4)验证MySQL表# 登录 MySQL 查看 Grafana 自动创建所需的表root@Docker ~# docker exec -it mysql-server mysql grafanamysql> SHOW TABLES;+------------------------------------+| Tables_in_grafana |+------------------------------------+| alert || ........... || user_role || user_stats |+------------------------------------+110 rows in set (0.00 sec)✅️ Grafana 自动创建了 110 张表,MySQL 存储后端切换成功📌 验证要点
- Grafana WebUI 能正常登录 → 配置正确
- MySQL 中有 110 张表 → 自动迁移成功
- 原来的 SQLite 文件
grafana.db还在但不再使用 → 可以备份后删除
⚠️ 如果重启后 Grafana 起不来,按下面三处排查:
- MySQL 容器是否在运行(
docker ps/ss -ntl | grep 3306) grafana.ini里 MySQL 的host/name/user/password是否与创建库和用户时一致- MySQL 用户
grafana是否允许远程连接(授权 host 需含'grafana'@'%')
📌 恢复旧仪表盘:Grafana 数据库里只存元数据(仪表盘、数据源、用户、文件夹、告警规则),不存监控指标——指标一直在 Prometheus / VictoriaMetrics。切到 MySQL 后旧的 grafana.db(SQLite)被弃用,仪表盘/数据源都变空;用 WebUI 迁移最直观:
- 仪表盘:在旧 SQLite 实例上,打开仪表盘 → 右上角「导出」→「导出为代码」→ 下载 JSON 文件;再到新 MySQL 实例 Dashboard → Import,上传该 JSON 文件即可
- 数据源:在 MySQL 实例里手动重新加一次,指向已有的 Prometheus 数据源
导入后仪表盘重新指向 Prometheus 就能出图
API导出仪表盘和数据源
'旧数据在 SQLite 的 grafana.db,需先让 Grafana 临时回到 SQLite 把配置导出来'1)临时切回 SQLite,导出旧仪表盘与数据源root@Prom ~# vim /etc/grafana/grafana.ini# 把 [database] 改回 type = sqlite3(注释掉 mysql),重启让 Grafana 读回 grafana.dbroot@Prom ~# systemctl restart grafana-server.service
2)导出旧仪表盘(先拿 uid 列表,再逐个导出)'列表文件名不用 dash_ 前缀,否则会被下面的 /tmp/dash_*.json 通配符误伤'root@Prom ~# curl -s -k -u admin:admin "http://10.0.0.10:3000/api/search?type=dash-db" -o /tmp/dashboards_list.jsonroot@Prom ~# for uid in $(jq -r '.[].uid' /tmp/dashboards_list.json); do curl -s -k -u admin:admin "http://10.0.0.10:3000/api/dashboards/uid/$uid" -o /tmp/dash_$uid.json; done
3)导出数据源root@Prom ~# curl -s -k -u admin:admin http://10.0.0.10:3000/api/datasources -o /tmp/datasources.json
4)切回 MySQL,准备导入root@Prom ~# vim /etc/grafana/grafana.ini# 恢复 type = mysql,重启root@Prom ~# systemctl restart grafana-server.service
5)导入数据源(/api/datasources 只收单个对象,需逐个取出数组元素 POST)jq -c '.[]' /tmp/datasources.json | while IFS= read -r ds; do curl -s -k -u admin:admin -X POST -H "Content-Type: application/json" --data-binary "$ds" http://10.0.0.10:3000/api/datasources; echodone✅️ 数据源导入成功`提前切换语言为中文,才能正常显示!`
6)导入仪表盘(先删掉 dashboard 里的 id,避免内部 ID 冲突)for f in /tmp/dash_*.json; do jq -c '{dashboard: (.dashboard | del(.id)), overwrite: true, folderId: 0}' "$f" | curl -s -k -u admin:admin -X POST -H "Content-Type: application/json" --data-binary @- http://10.0.0.10:3000/api/dashboards/db; echodone✅️ 旧仪表盘已恢复到 MySQL 后端,重新指向 Prometheus 数据源即可出图'嫌命令行麻烦,也可用 Grafana WebUI'
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!















