pg_exporter 1.5.0 Docker Compose 部署指南
在 Ubuntu 24.04 上用 Docker Compose 部署 pg_exporter 1.5.0 + PostgreSQL 16 双服务栈:编排文件与初始化脚本全文、/metrics 与健康检查 API 逐项验证、数据持久化、POST /reload 热重载实测、等价 docker run 对照与 7 条排障实录。
pg_exporter 1.5.0 Docker Compose 部署指南
目标:在一台 Ubuntu 24.04 服务器上,用 Docker Compose 把 pg_exporter 1.5.0 与 PostgreSQL 16 编排为一键可复现的双服务栈:编写 compose 编排文件、初始化监控账号与演示业务数据、逐项验证
/metrics指标端点与健康检查 API,并完成数据持久化、配置热重载与等价docker run对照。全部步骤已在 Ubuntu 24.04 + Docker Engine 29.9.2 + Docker Compose v5.6.1 环境实测通过,文中命令输出均为真实回显。
一、环境信息
本文所有命令与回显均在以下环境实测(版本复核日期 2026-11-01):
- 操作系统:Ubuntu 24.04 LTS(x86_64)
- Docker Engine:29.9.2
- Docker Compose:v5.6.1(
docker compose插件形态) - pg_exporter:1.5.0(官方镜像
pgsty/pg_exporter:1.5.0;GitHub 最新稳定版经 shields.io release 徽章复核仍为 v1.5.0,查询日期 2026-11-01,与本文版本一致) - PostgreSQL:16.15(官方镜像
postgres:16,充当被监控数据库) - 监控端口:宿主机 8134 → pg_exporter 的 9630(pg_exporter 固定默认监听端口为 9630)
- 部署目录:
/opt/pg-exporter/(compose 项目目录) - 演示业务:
dbtest库中的demo_orders表(500 行订单数据,用于演示自定义采集器) - 演示账号:监控账号
dbuser_monitor/q1w2e3r4(PostgreSQL 内置pg_monitor角色);数据库超级用户postgres/q1w2e3r4
pg_exporter 是 Go 编写、YAML 声明式驱动的 PostgreSQL/PgBouncer Prometheus 指标采集器,项目认知与同类选型对比见 《pg_exporter 1.5.0 介绍与选型指南》。它自身无状态:不落盘任何业务数据、重启即恢复,因此本方案中唯一需要持久化的是被监控对象 PostgreSQL 的数据目录。为让读者拿到一份开箱即跑的完整环境,本文用官方 postgres:16 镜像充当被监控数据库并初始化演示数据;生产环境中把 compose 里的 db 服务换成你已有的数据库连接参数即可。
二、镜像选型说明
pg_exporter 官方只发布一个镜像仓库,但镜像标签与运行形态仍有选型空间,本章给出选择依据与版本核对方法。
2.1 镜像清单与选择依据
| 服务角色 | 镜像 | 实测版本 | 体积 | 选择依据 |
|---|---|---|---|---|
| 指标采集器 | pgsty/pg_exporter:1.5.0 | 1.5.0(go1.27.3 构建) | 20.3 MB | 官方唯一镜像源,GoReleaser 多架构构建(amd64/arm64) |
| 被监控数据库 | postgres:16 | 16.15 | 642 MB | PostgreSQL 官方镜像,与 pg_exporter 默认配置的验证版本线(PG 10–18)匹配 |
表解读:pg_exporter 镜像非常轻(20.3 MB,静态链接单二进制 + 无 shell 的极简底座),与数据库镜像体积相差 30 倍,监控组件自身对宿主资源几乎无占用。pgsty/pg_exporter 是唯一官方镜像源——项目 2026 年已从个人仓库 Vonng/pg_exporter 迁入 Pigsty 官方组织 pgsty,Docker Hub 上不存在 vonng/pg_exporter 之类的旧镜像源,无需在多个来源间纠结。
💡 技术拓展:镜像标签有三种常见固定策略——
策略 写法 取舍 固定版本号 pgsty/pg_exporter:1.5.0版本可追溯、升级显式可控,生产首选 跟随 latest pgsty/pg_exporter:latest自动拿最新,但升级时机不可控、回滚困难 固定 digest pgsty/pg_exporter@sha256:…绝对不变,安全审计最严,但维护成本最高 本文采用固定版本号策略:监控组件的可观测变更应当显式可控,与数据库版本(
postgres:16)的固定大版本策略一致。
2.2 镜像版本核对
拿到镜像后用 docker inspect 核对内置的 OCI 标准元数据,确认版本与来源:
docker inspect pgsty/pg_exporter:1.5.0 --format '{{json .Config.Labels}}' | python3 -m json.tool
实测回显:
{
"org.opencontainers.image.authors": "Ruohang Feng <rh@vonng.com>",
"org.opencontainers.image.created": "2026-10-23T01:33:50Z",
"org.opencontainers.image.description": "PostgreSQL/Pgbouncer metrics exporter for Prometheus",
"org.opencontainers.image.licenses": "Apache-2.0",
"org.opencontainers.image.revision": "18912540fe5edce0ed0ee81fac0d989738ecaa87",
"org.opencontainers.image.source": "https://github.com/pgsty/pg_exporter",
"org.opencontainers.image.title": "pg_exporter",
"org.opencontainers.image.url": "https://github.com/pgsty/pg_exporter",
"org.opencontainers.image.version": "1.5.0"
}
关键项解读:version=1.5.0 即发布版本;revision 是对应的 Git 提交号,可到仓库核对源码;licenses=Apache-2.0;created 时间 2026-10-23 与 GitHub Releases 的 v1.5.0 构建日期一致——镜像与发布版本严格对应,不存在"镜像比 Release 新/旧"的漂移问题。
三、前置条件
部署前逐项确认以下四点,每点给出验证命令。
1. Docker Engine 与 Compose 插件已安装且版本达标:
docker version --format 'Docker {{.Server.Version}}'
实测回显:
Docker 29.9.2
docker compose version
实测回显:
Docker Compose version v5.6.1
⚠️ 注意:本文使用
docker compose(V2 插件,子命令形式)。若系统里只有旧版独立二进制docker-compose(V1),命令形态需相应替换,且对name:顶层字段等新特性支持不完整。
2. 监控端口未被占用。本方案把 pg_exporter 的 9630 映射到宿主机 8134,先确认该端口空闲:
ss -ltn | grep 8134 || echo "端口 8134 空闲"
实测回显:
端口 8134 空闲
若输出中已有监听记录,换成其他空闲端口并同步修改后文 compose 文件的 ports 段。
3. 部署目录已创建:
mkdir -p /opt/pg-exporter
(目录创建无输出,ls -ld /opt/pg-exporter 确认即可。)
4. 镜像拉取网络可达。docker pull 走 Docker Hub 官方源;国内网络环境拉取慢或超时时,为 Docker 守护进程配置镜像加速器或代理后重试(配置方法属 Docker 基础运维,此处不展开;实测环境中两个镜像均可正常拉取,docker compose pull 回显见 4.5 节)。
四、部署步骤
本章从零完成整套部署:先认识目录结构,再依次落盘三个文件(编排文件、数据库初始化脚本、采集器配置),最后启动并逐项验证。三个文件的全部内容如下文所示,逐字可抄。
4.1 目录结构
部署完成后 /opt/pg-exporter/ 的完整结构:
/opt/pg-exporter/
├── docker-compose.yml # compose 编排文件(4.2 节)
├── init-monitor.sql # 数据库首启初始化脚本(4.3 节)
└── demo.yml # pg_exporter 采集器配置(4.4 节)
三个文件中,init-monitor.sql 由数据库容器首次初始化时自动执行(挂载到 /docker-entrypoint-initdb.d/),demo.yml 以只读方式挂载给 pg_exporter。
4.2 编排文件 docker-compose.yml
创建 /opt/pg-exporter/docker-compose.yml,内容如下(全文):
name: pg-exporter-1.5.0-stack
services:
db:
image: postgres:16
container_name: pg-exporter-1.5.0-db
hostname: db
environment:
POSTGRES_PASSWORD: q1w2e3r4
volumes:
- ./init-monitor.sql:/docker-entrypoint-initdb.d/99-init-monitor.sql:ro
- pgdata:/var/lib/postgresql/data
networks:
- pg-exporter-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 10
exporter:
image: pgsty/pg_exporter:1.5.0
container_name: pg-exporter-1.5.0-app
hostname: exporter
depends_on:
db:
condition: service_healthy
command:
- --url=postgres://dbuser_monitor:q1w2e3r4@db:5432/postgres?sslmode=disable
- --config=/etc/pg_exporter/demo.yml
- --web.listen-address=:9630
volumes:
- ./demo.yml:/etc/pg_exporter/demo.yml:ro
ports:
- "8134:9630"
networks:
- pg-exporter-net
volumes:
pgdata:
networks:
pg-exporter-net:
driver: bridge
关键设计逐项说明:
name: pg-exporter-1.5.0-stack:显式声明 compose 项目名,避免默认用目录名,多套栈共存时互不干扰(注意:compose 会把项目名中的点号规范化去除,实测本项目名实际生效为pg-exporter-150-stack,详见 11.1 节排障实录)。healthcheck+depends_on: condition: service_healthy:数据库必须先通过pg_isready健康检查,exporter 才启动——否则 exporter 会在数据库还没就绪时抢跑,连接失败。这是双服务栈顺序控制的核心,db服务名同时充当容器网络内的 DNS 主机名(hostname: db),连接串里的@db:5432即依赖此机制。command三参数:以命令行参数方式传给 pg_exporter——--url指定被监控目标(监控账号dbuser_monitor连主库 postgres),--config指定采集器配置文件,--web.listen-address=:9630显式声明监听端口(也是默认值,写出来是为了自文档化)。三个参数的完整语义见 《pg_exporter 1.5.0 常用 CLI 命令与工具详解》。- 连接串里的
?sslmode=disable:pg_exporter 对未显式声明 sslmode 的 URL 会自动注入sslmode=disable(同机部署优化),容器网络内显式写出该参数让行为一目了然;跨网络远程监控时应改为sslmode=require级别。 ports: "8134:9630":宿主机 8134 映射到 9630。9630 是 pg_exporter 的固定默认端口,与 postgres_exporter 惯用的 9187 不同。networks显式声明 bridge:两服务同网络才能互通;多套 compose 栈共存、担心自动分配网段冲突时,可在网络段下加ipam.config显式指定空闲子网。volumes: pgdata:具名卷持久化数据库数据目录,详见第五章。
4.3 数据库初始化脚本 init-monitor.sql
创建 /opt/pg-exporter/init-monitor.sql,内容如下(全文):
-- 初始化监控账号与演示数据
CREATE USER dbuser_monitor WITH PASSWORD 'q1w2e3r4';
GRANT pg_monitor TO dbuser_monitor;
GRANT USAGE ON SCHEMA pg_catalog TO dbuser_monitor;
CREATE DATABASE dbtest;
\c dbtest
CREATE TABLE IF NOT EXISTS demo_orders (
id serial PRIMARY KEY,
item text,
amount numeric,
created_at timestamptz DEFAULT now()
);
INSERT INTO demo_orders (item, amount)
SELECT 'sku-' || i, (random() * 100)::numeric(10, 2) FROM generate_series(1, 500) i;
GRANT SELECT ON demo_orders TO dbuser_monitor;
逐段说明:
- 监控账号三件套:
CREATE USER建号(密码q1w2e3r4,与 compose 连接串一致)→GRANT pg_monitor授予 PostgreSQL 内置监控角色(聚合pg_read_all_stats等只读观测权限,官方推荐的监控授权方式)→GRANT USAGE ON SCHEMA pg_catalog保证能访问系统目录。监控账号是只读观测角色,不授予任何写权限。 - 演示库与演示表:
dbtest库 +demo_orders订单表(500 行随机金额数据)。它的存在是为了演示 pg_exporter 的自定义采集器(demo.yml 中的demo_orders_stat只对dbtest库生效)与自动发现(exporter 启动后发现dbtest并单独纳管)。生产环境不需要这段,删掉CREATE DATABASE及之后的内容即可。 \c dbtest:psql 元命令,切换连接到 dbtest 库,后续建表与授权都在该库执行。- 该脚本挂载在
/docker-entrypoint-initdb.d/,只在数据目录为空(首次初始化)时执行;数据卷已有数据时自动跳过(重启后日志中可见Skipping initialization,见 4.5 节)。
4.4 采集器配置 demo.yml
创建 /opt/pg-exporter/demo.yml,内容如下(全文):
#==============================================================
# pg_exporter 自定义采集器演示配置
#==============================================================
demo_orders_stat:
name: demo_orders
desc: demo business table statistics (dbtest only)
query: |
SELECT count(*) AS rows,
coalesce(sum(amount), 0) AS amount_total,
extract(EPOCH FROM max(created_at)) AS last_order_epoch
FROM demo_orders;
ttl: 5
timeout: 1
tags: [dbname:dbtest]
metrics:
- rows:
usage: GAUGE
description: total rows in demo_orders table
- amount_total:
usage: GAUGE
description: total amount of all orders
- last_order_epoch:
usage: GAUGE
description: epoch seconds of the latest order
demo_db_size:
name: demo_db
desc: database size for all connectable databases
query: |
SELECT datname,
pg_database_size(datname) AS size_bytes
FROM pg_database
WHERE datallowconn AND NOT datistemplate;
ttl: 30
timeout: 1
tags: [cluster]
metrics:
- datname:
usage: LABEL
description: database name
- size_bytes:
usage: GAUGE
description: database size in bytes
结构速览(每个顶层键 = 一条自定义采集器):
demo_orders_stat:统计demo_orders业务表行数、总金额与最新订单时间。tags: [dbname:dbtest]表示只安装到名为dbtest的数据库上(动态规划调度);ttl: 5表示抓取结果缓存 5 秒。demo_db_size:列出所有可连接数据库的体积。tags: [cluster]表示集群级查询(每个 server 对象都会执行);datname列声明为LABEL(变成 Prometheus 标签),size_bytes为GAUGE。- 指标名规则:暴露出来的指标 =
<name>_<列名>,如demo_orders_rows、demo_db_size_bytes。
这份配置刻意保持最小可读。pg_exporter 官方默认配置定义了 460 个指标、96 条采集分支,每个字段的完整语义(usage 取值、tags 调度维度、fatal/skip 控制等)在 《pg_exporter 1.5.0 配置参数详解》 中逐项拆解。
4.5 启动与验证
第 1 步:拉取镜像(可选步骤,up 也会自动拉取,显式 pull 可让首次部署的输出更清晰):
cd /opt/pg-exporter && docker compose pull
实测回显:
Image postgres:16 Pulling
Image pgsty/pg_exporter:1.5.0 Pulling
Image postgres:16 Pulled
Image pgsty/pg_exporter:1.5.0 Pulled
第 2 步:启动整套栈:
docker compose up -d
实测回显:
Network pg-exporter-150-stack_pg-exporter-net Created
Container pg-exporter-1.5.0-db Created
Container pg-exporter-1.5.0-app Created
Container pg-exporter-1.5.0-db Starting
Container pg-exporter-1.5.0-db Started
Container pg-exporter-1.5.0-db Waiting
Container pg-exporter-1.5.0-db Healthy
Container pg-exporter-1.5.0-app Starting
Container pg-exporter-1.5.0-app Started
回显顺序印证了编排设计:先建网络与两个服务,db 启动后进入 Waiting → Healthy(健康检查通过),exporter 才 Starting——depends_on: service_healthy 生效。
第 3 步:确认运行状态:
docker compose ps
实测回显:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
pg-exporter-1.5.0-app pgsty/pg_exporter:1.5.0 "/bin/pg_exporter --…" exporter 12 seconds ago Up 6 seconds 0.0.0.0:8134->9630/tcp, [::]:8134->9630/tcp
pg-exporter-1.5.0-db postgres:16 "docker-entrypoint.s…" db 12 seconds ago Up 12 seconds (healthy) 5432/tcp
两个服务均为 Up,db 带 (healthy) 健康标记,端口映射 0.0.0.0:8134->9630/tcp 就位。
第 4 步:查看启动日志,确认自动发现:
docker compose logs exporter --no-color --no-log-prefix
实测回显(输出节选,实测首部):
time=2026-11-01T03:32:06.822Z level=INFO msg="retrieve target url postgres://dbuser_monitor:xxxxx@db:5432/postgres?sslmode=disable from command line"
time=2026-11-01T03:32:06.822Z level=INFO msg="retrieve config path /etc/pg_exporter/demo.yml from command line"
time=2026-11-01T03:32:06.822Z level=INFO msg="auto discovery is enabled, excludeDatabase=map[postgres:true template0:true template1:true], includeDatabase=map[]"
time=2026-11-01T03:32:06.826Z level=INFO msg="server [postgres] version changed: from [0] to [160015]"
time=2026-11-01T03:32:06.828Z level=INFO msg="spawn new server for database dbtest : postgres://dbuser_monitor:xxxxx@db:5432/dbtest?sslmode=disable"
time=2026-11-01T03:32:06.828Z level=INFO msg="database dbtest is installed due to auto-discovery"
time=2026-11-01T03:32:06.828Z level=INFO msg="pg_exporter for postgres://dbuser_monitor:xxxxx@db:5432/postgres?sslmode=disable start, listen on :9630/metrics"
time=2026-11-01T03:32:06.828Z level=INFO msg="TLS is disabled." http2=false address=[::]:9630
time=2026-11-01T03:32:13.383Z level=INFO msg="server [postgres] planned with 2 queries, 1 installed, 1 discarded, installed: demo_db_size , discarded: demo_orders_stat"
time=2026-11-01T03:32:13.388Z level=INFO msg="server [dbtest] version changed: from [0] to [160015]"
time=2026-11-01T03:32:13.389Z level=INFO msg="server [dbtest] planned with 2 queries, 1 installed, 1 discarded, installed: demo_orders_stat , discarded: demo_db_size"
逐行解读:
- 密码在日志中自动脱敏为
xxxxx,日志可安全留存。 auto discovery is enabled, excludeDatabase=…:自动发现开启,默认排除template0/template1/postgres三个库不重复建 server(主连接串已覆盖 postgres)。database dbtest is installed due to auto-discovery:自动发现了初始化脚本创建的dbtest库,为它单独生成了采集对象。- 最后两行
planned with 2 queries, 1 installed, 1 discarded是动态规划的直接证据:postgres库上安装了demo_db_size、丢弃demo_orders_stat(因为它带dbname:dbtest标签);dbtest库正好相反。每个 namespace 至多选中一条分支,规划结果与 demo.yml 的标签设计完全吻合。
第 5 步:验证指标端点:
curl -s http://127.0.0.1:8134/metrics | grep -E '^(pg_up|pg_version|pg_in_recovery|demo_orders_rows|demo_db_size_bytes)'
实测回显:
pg_up 1
pg_in_recovery 0
pg_version 160015
demo_db_size_bytes{datname="dbtest"} 7.855127e+06
demo_db_size_bytes{datname="postgres"} 7.699479e+06
demo_orders_rows 500
六个关键指标全部到位:pg_up 1 表示监控链路健康;pg_version 160015 是 PostgreSQL 版本号(16.15 的数字编码);demo_db_size_bytes 按 datname 标签拆分出两个库的体积;demo_orders_rows 500 正是初始化脚本插入的演示行数——自定义采集器从 SQL 到 Prometheus 指标的全链路打通。查看完整指标全集可执行 curl -s http://127.0.0.1:8134/metrics | wc -l(本环境实测 211 行,含 Go 运行时与 pg_exporter 自监控指标)。
第 6 步:验证健康检查 API:
for ep in health up liveness readiness primary replica read; do
printf '%-10s' "/$ep"; curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:8134/$ep
done
实测回显:
/health HTTP 200
/up HTTP 200
/liveness HTTP 200
/readiness HTTP 200
/primary HTTP 200
/replica HTTP 404
/read HTTP 200
解读:存活类端点(/health、/up、/liveness、/readiness)全部 200;流量路由类端点按语义区分——当前被监控实例是主库,所以 /primary 返回 200、/replica 返回 404(404 表示"当前不是副本",属正常语义而非故障,详见 11.4 节)。这些端点可直接挂到 HAProxy/nginx 的健康探测上实现主从流量自动切换。
至此部署完成。整套栈从 up -d 到指标可用约 15 秒。
五、数据持久化说明
本方案只有一个需要持久化的对象:PostgreSQL 数据目录,通过具名卷 pgdata 落盘。
确认卷已创建:
docker volume ls --format '{{.Name}}' | grep pg-exporter
实测回显:
pg-exporter-150-stack_pgdata
具名卷自动以 <项目名>_<卷名> 命名(项目名 pg-exporter-150-stack + 卷名 pgdata)。
持久化验证:数据卷中的数据在容器删除重建后依然保留。实测:执行 docker compose down(不带 -v,仅删容器与网络)再 docker compose up -d,数据完好:
docker compose down && docker compose up -d && sleep 15 && curl -s http://127.0.0.1:8134/metrics | grep '^demo_orders_rows'
实测回显:
Container pg-exporter-1.5.0-app Stopped
Container pg-exporter-1.5.0-app Removed
Container pg-exporter-1.5.0-db Stopped
Container pg-exporter-1.5.0-db Removed
Network pg-exporter-150-stack_pg-exporter-net Removed
Network pg-exporter-150-stack_pg-exporter-net Created
Container pg-exporter-1.5.0-db Created
Container pg-exporter-1.5.0-app Created
Container pg-exporter-1.5.0-db Starting
Container pg-exporter-1.5.0-db Started
Container pg-exporter-1.5.0-db Waiting
Container pg-exporter-1.5.0-db Healthy
Container pg-exporter-1.5.0-app Starting
Container pg-exporter-1.5.0-app Started
demo_orders_rows 500
demo_orders_rows 500 与重启前一致——500 行演示数据完好,同时数据库日志会显示 PostgreSQL Database directory appears to contain a database; Skipping initialization(数据目录非空,初始化脚本不再执行)。此时 demo.yml 中带 dbname:dbtest 标签的采集器也随自动发现重新挂载。
⚠️ 注意:
docker compose down -v会连同数据卷一起删除,数据库内容不可恢复。日常停栈用down,-v只在明确要清空重来时使用。若需要把数据落到宿主机指定目录而非具名卷,把pgdata:/var/lib/postgresql/data换成 bind mount 写法(如./pgdata:/var/lib/postgresql/data)即可,两种方式对 pg_exporter 完全透明。pg_exporter 自身(exporter 服务)完全无状态:指标缓存与规划都在内存中,容器随时可删可重建,无需任何卷。
六、环境变量表
本方案涉及两层环境变量:compose 传给容器的环境变量,与 pg_exporter 自身识别的 PG_EXPORTER_* 变量。
6.1 compose 容器环境变量(本方案实际使用):
| 变量 | 所属服务 | 本方案取值 | 作用 |
|---|---|---|---|
POSTGRES_PASSWORD | db | q1w2e3r4 | postgres 超级用户密码,首次初始化时生效 |
POSTGRES_USER / POSTGRES_DB | db | 未设置 | 分别默认 postgres / $POSTGRES_USER,本方案用默认值 |
6.2 pg_exporter 的 PG_EXPORTER_* 环境变量:pg_exporter 的启动参数大多有同名环境变量形态,在容器部署时可改用 environment: 注入(与 command: 参数等价,命令行参数优先)。常用变量与官方默认值:
| 环境变量 | 对应命令行参数 | 官方默认值 | 作用 |
|---|---|---|---|
PG_EXPORTER_URL | --url | postgresql:///?sslmode=disable | 被监控目标连接串(本方案用 --url 参数传入) |
PG_EXPORTER_CONFIG | --config | 依次探测 ./pg_exporter.yml、/etc/pg_exporter.yml、/etc/pg_exporter/ | 采集器配置文件路径 |
PG_EXPORTER_LABEL | --label | 空 | 给全部指标附加静态标签 |
PG_EXPORTER_TAG | --tag | 空 | 给 server 对象附加调度标签 |
PG_EXPORTER_DISABLE_CACHE | --disable-cache | false | 关闭全部采集器 TTL 缓存 |
PG_EXPORTER_AUTO_DISCOVERY | --auto-discovery | true | 自动发现实例内全部可连接数据库 |
PG_EXPORTER_EXCLUDE_DATABASE | --exclude-database | template0,template1,postgres | 自动发现排除清单 |
PG_EXPORTER_INCLUDE_DATABASE | --include-database | 空 | 自动发现白名单(设置后仅发现清单内数据库) |
PG_EXPORTER_NAMESPACE | --namespace | pg | 指标命名空间前缀(PgBouncer 场景用 pgbouncer) |
PG_EXPORTER_CONNECT_TIMEOUT | --connect-timeout | 100 | 连接超时(毫秒) |
PG_EXPORTER_TELEMETRY_PATH | --web.telemetry-path | /metrics | 指标端点路径 |
表解读:容器编排中最常用的是前两行——把 PG_EXPORTER_URL 与 PG_EXPORTER_CONFIG 写进 environment: 段与写在 command: 里效果一致,选一种即可;EXCLUDE/INCLUDE_DATABASE 是多库实例上控制纳管范围的首选手段。参数的完整清单与逐项实测见 《pg_exporter 1.5.0 常用 CLI 命令与工具详解》。
七、配置参数说明
第四章已给出三个文件全文,本章把 compose 编排中的关键参数与 pg_exporter 启动参数集中成表,便于对照修改。
7.1 compose 编排参数:
| 参数 | 取值 | 可调整方向与影响 |
|---|---|---|
name | pg-exporter-1.5.0-stack | 项目名标识;含点号会被规范化(见 11.1),建议用小写字母/数字/连字符 |
db.image | postgres:16 | 换成已有数据库时整段删除 db 服务,改 --url 指向外部地址 |
db.environment.POSTGRES_PASSWORD | q1w2e3r4 | 生产环境务必更换强密码,并与连接串同步 |
db.healthcheck | pg_isready -U postgres,5 秒间隔 | 数据库启动慢(大库崩溃恢复)时加大 retries |
exporter.command --url | postgres://dbuser_monitor:q1w2e3r4@db:5432/postgres?sslmode=disable | 指向真实库时改主机与账号;远程库显式用 sslmode=require 及以上 |
exporter.command --config | /etc/pg_exporter/demo.yml | 换成默认全量配置时挂载官方 pg_exporter.yml 并改此路径 |
exporter.ports | 8134:9630 | 宿主端口按需改;9630 是 exporter 内部固定端口一般不动 |
exporter.depends_on | service_healthy | 保证启动顺序,无需调整 |
7.2 pg_exporter 启动参数(本方案 command 中出现的三个):
| 参数 | 本方案取值 | 默认值 | 说明 |
|---|---|---|---|
--url | postgres://dbuser_monitor:q1w2e3r4@db:5432/postgres?sslmode=disable | postgresql:///?sslmode=disable | 监控目标连接串;未写 sslmode 时会自动注入 sslmode=disable |
--config | /etc/pg_exporter/demo.yml | 按探测顺序回退 | 支持单文件或目录(目录内 YAML 按字母序合并) |
--web.listen-address | :9630 | :9630 | HTTP 监听地址,含 /metrics 与健康检查端点 |
7.3 采集器配置(demo.yml)的调度行为——启动日志已给出实证:
| 采集器 | tags 标签 | 规划结果 |
|---|---|---|
demo_orders_stat | dbname:dbtest | 仅安装到 dbtest(postgres 库 discarded) |
demo_db_size | cluster | 每个库的 server 都安装(两条日志均 installed) |
这张表与 4.5 节第 4 步日志中的 1 installed, 1 discarded 逐一对应:pg_exporter 在启动与每次 reload 时按标签重新规划,改 tags 不需要动任何代码。
八、配置文件挂载
demo.yml 以只读 bind mount 挂载进 exporter(./demo.yml:/etc/pg_exporter/demo.yml:ro),本章覆盖挂载机制、容器内查看方法与配置变更后的生效方式。
8.1 挂载机制与容器内查看。bind mount 是宿主文件与容器内路径的同一视图:宿主侧 /opt/pg-exporter/demo.yml 与容器内 /etc/pg_exporter/demo.yml 是同一个文件,宿主上修改立即对容器可见。需要注意 pg_exporter 官方镜像是极简底座、不带 shell,docker exec 进容器看文件会失败:
docker exec pg-exporter-1.5.0-app sh -c 'cat /etc/pg_exporter/demo.yml'
实测回显:
OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH
排障结论:镜像内只有 /bin/pg_exporter 一个可执行文件,无 sh/bash/cat。查看容器内生效配置的正确方式是直接看宿主侧源文件(同一文件),或用 docker compose cp 从容器拷出:
docker compose cp exporter:/etc/pg_exporter/demo.yml /tmp/demo-in-container.yml && head -3 /tmp/demo-in-container.yml
实测回显:
#==============================================================
# pg_exporter 自定义采集器演示配置
#==============================================================
(/tmp/demo-in-container.yml 内容与宿主侧一致后即可删除。)
8.2 修改配置后的生效方式。pg_exporter 不会自动监听配置文件变化,改完配置必须手动触发重载。正确方式是调用内置的 POST /reload 端点(零中断、原地重规划)。完整实测:先给 demo.yml 追加一个新采集器 demo_uptime(数据库已运行时长):
cat >> demo.yml <<'EOF'
demo_uptime:
name: demo_uptime
desc: database uptime
query: |
SELECT extract(EPOCH FROM now() - pg_postmaster_start_time()) AS uptime_seconds;
ttl: 10
timeout: 1
tags: [cluster]
metrics:
- uptime_seconds:
usage: GAUGE
description: seconds since postmaster start
EOF
直接查指标,确认此时新采集器尚未生效:
curl -s http://127.0.0.1:8134/metrics | grep demo_uptime || echo "(无输出:尚未重载)"
实测回显:
(无输出:尚未重载)
触发重载:
curl -s -X POST -w " [HTTP %{http_code}]\n" http://127.0.0.1:8134/reload
实测回显:
server reloaded [HTTP 200]
验证新指标已出现:
curl -s http://127.0.0.1:8134/metrics | grep -E '^demo_uptime_uptime_seconds|^pg_exporter_query_cache_ttl.*demo_uptime'
实测回显:
demo_uptime_uptime_seconds 85.147195
pg_exporter_query_cache_ttl{datname="postgres",query="demo_uptime"} 10
同时 exporter 日志出现重载记录:
time=2026-11-01T03:33:23.333Z level=INFO msg="server reloaded, 3 queries applied"
(2 queries applied → 3 queries applied,新采集器已进入规划。)
⚠️ 注意:修改
demo.yml后若既不POST /reload也不重启容器,改动不会生效——这是最常踩的坑。两种生效方式二选一:热重载curl -X POST http://127.0.0.1:8134/reload(推荐,不断连接);或docker compose restart exporter。另外,若用 vim 等编辑器以"重命名替换"方式保存挂载文件,bind mount 的单文件视图可能断链,改完建议docker compose restart exporter并确认日志无异常,稳妥场景可直接docker compose up -d --force-recreate exporter。
8.3 挂载多份配置。--config 也接受目录:目录下所有 YAML 按文件名字母序合并成一份逻辑配置。把默认全量配置与自定义配置分文件管理时(如 default.yml + custom.yml),挂载目录并让 --config=/etc/pg_exporter/ 指向目录即可,同名 namespace 的合并规则见 《pg_exporter 1.5.0 配置参数详解》。
九、等价 docker run
不用 compose 时,以下两条 docker run 与本方案完全等价(先建网络;init-monitor.sql 与 demo.yml 沿用 /opt/pg-exporter/ 下的文件):
docker network create pg-exporter-net
# 1. 被监控数据库(healthcheck 保证 exporter 启动前就绪)
docker run -d --name pg-exporter-db \
--network pg-exporter-net \
--hostname db \
-e POSTGRES_PASSWORD=q1w2e3r4 \
-v /opt/pg-exporter/init-monitor.sql:/docker-entrypoint-initdb.d/99-init-monitor.sql:ro \
-v pgdata:/var/lib/postgresql/data \
postgres:16
# 2. pg_exporter(等数据库就绪后再执行,可先用 pg_isready 探测)
docker run -d --name pg-exporter-app \
--network pg-exporter-net \
--hostname exporter \
-p 8134:9630 \
-v /opt/pg-exporter/demo.yml:/etc/pg_exporter/demo.yml:ro \
pgsty/pg_exporter:1.5.0 \
--url=postgres://dbuser_monitor:q1w2e3r4@db:5432/postgres?sslmode=disable \
--config=/etc/pg_exporter/demo.yml \
--web.listen-address=:9630
(在独立环境中按上述命令实测部署,curl http://127.0.0.1:8134/metrics 同样返回 pg_up 1 与 demo_orders_rows 500,与 compose 方案行为一致。)
与 compose 的对应关系及差异:
| compose 能力 | docker run 等价物 | 说明 |
|---|---|---|
networks: pg-exporter-net | docker network create + --network | 手动建网,容器名即 DNS 名 |
depends_on: service_healthy | 无自动等价物 | 需人工保证顺序(等 db 健康后再 run exporter,或给 db 加 --health-cmd) |
volumes: pgdata | -v pgdata:/var/lib/postgresql/data | 具名卷同名复用 |
| 项目名与一键 up/down | 逐个容器 docker rm -f | compose 的核心增益即在此 |
结论:run 方式仅建议用于单次调试;长期运行用 compose(声明式、可版本化、启停一键)。
十、常用运维命令
以下命令均在 /opt/pg-exporter/ 目录下执行(compose 自动读取当前目录的 docker-compose.yml)。
状态与日志:
docker compose ps # 两服务状态与健康标记
docker compose logs exporter --tail 50 # 采集器最近 50 行日志(含动态规划/重载记录)
docker compose logs db --tail 50 # 数据库日志(慢查询/连接错误在这看)
(ps 实测回显见 4.5 节第 3 步,日志实测回显见 4.5 节第 4 步。)
启停与重启:
docker compose restart exporter # 只重启采集器(配置/连接串变更后的兜底手段)
docker compose stop # 停止两服务(保留容器与数据卷)
docker compose start # 恢复已 stop 的栈
docker compose down # 删容器与网络(保留数据卷)
docker compose down -v # 连数据卷一起删(数据清空,慎用)
docker compose up -d # 启动/增量更新(配置变更后自动重建受影响容器)
采集器运维(HTTP 端点,容器部署时宿主侧加端口 8134):
curl -s -X POST http://127.0.0.1:8134/reload # 重载配置(改 demo.yml 后必做)
curl -s http://127.0.0.1:8134/metrics | head # 查看指标
curl -s http://127.0.0.1:8134/explain # 查看当前采集规划的解释
curl -s http://127.0.0.1:8134/stat # 查看采集统计(各查询次数/缓存命中/耗时)
版本升级流程(以升级到未来版本 <new-ver> 为例,镜像标签与 command 均不变时只需改两处):
sed -i 's/pgsty\/pg_exporter:1.5.0/pgsty\/pg_exporter:<new-ver>/' docker-compose.yml
docker compose up -d
compose 检测到镜像变更会自动重建 exporter 容器;pgdata 卷不受影响。升级前建议备份 pgdata 卷(docker run --rm -v pg-exporter-150-stack_pgdata:/data -v $PWD:/backup postgres:16 tar czf /backup/pgdata-backup.tgz /data)。
对接 Prometheus 抓取。在 Prometheus 服务器的抓取配置中加入本机目标(静态配置示例):
scrape_configs:
- job_name: pg_exporter
static_configs:
- targets: ["<宿主机IP>:8134"]
抓取间隔建议不小于各采集器 ttl 的最小值(本方案为 5 秒),避免穿透缓存重复执行 SQL。生产中更常见的做法是 pg_exporter 与数据库同机部署(不经 compose 编排数据库),详见 A1 篇部署拓扑对比一节。
十一、常见问题
以下 7 个问题均来自本次部署实测中真实出现或验证过的场景,按"现象 → 定位 → 解决"沉淀。
11.1 compose 项目名中的点号被静默去除
现象:compose 文件里写了 name: pg-exporter-1.5.0-stack,但 docker compose ps/卷名/网络名里出现的是 pg-exporter-150-stack(点号消失)。
定位:compose 项目名只允许小写字母、数字、连字符与下划线,点号不在合法字符集内,compose 解析时静默规范化(docker compose config 可看到解析后的实际值)。
实测确认:
docker compose config | head -1
实测回显:
name: pg-exporter-150-stack
解决:这是无害的规范化,不影响功能;但依赖项目名做脚本化操作(备份卷名 pg-exporter-150-stack_pgdata 等)时必须用规范化后的名字。想避免歧义可直接写 name: pg-exporter-150-stack。
11.2 docker exec 进 exporter 容器报 "sh: executable file not found"
现象与实测回显:
OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH
定位:官方镜像是极简底座(静态二进制 + 无 shell),不是故障。
解决:不要进容器;查看配置看宿主侧挂载源文件,从容器取文件用 docker compose cp(见 8.1 节实测)。
11.3 修改了 demo.yml 但指标不变
现象:改了采集器配置,/metrics 里还是旧指标。
定位:pg_exporter 不自动监听配置文件变化,重载必须显式触发。
解决:curl -X POST http://127.0.0.1:8134/reload(实测回显 server reloaded [HTTP 200],日志出现 server reloaded, N queries applied);或 docker compose restart exporter。完整实测过程见 8.2 节。
11.4 /replica 返回 404 是不是故障
现象:健康探测中 /replica 返回 404。
定位:这是正常语义。pg_exporter 的路由类端点约定:/primary 系(/leader、/master、/read-write)在"非恢复中"返回 200、恢复中返回 404;/replica 系(/standby、/read-only)在"恢复中(副本)"返回 200、非副本返回 404;实例不可达时才返回 503。
实测(本方案被监控实例为主库):
curl -s -o /dev/null -w "primary: %{http_code}\n" http://127.0.0.1:8134/primary
curl -s -o /dev/null -w "replica: %{http_code}\n" http://127.0.0.1:8134/replica
实测回显:
primary: 200
replica: 404
结论:主库上 /replica=404 正确。做主从流量切换时,读写流量探测用 /primary 系、只读流量探测用 /replica 系即可。
11.5 exporter 日志报认证失败(password authentication failed)
现象:日志出现 pq: password authentication failed for user "dbuser_monitor",pg_up 0。
定位:连接串密码与数据库实际密码不一致。最常见的成因:先启动过一次栈(数据卷已按旧 init 脚本初始化),后改 init-monitor.sql 或 POSTGRES_PASSWORD 再重启——初始化脚本只在数据目录为空时执行,改脚本不会重放。
解决:确认要保留数据时,手工进数据库改密码对齐连接串;或开发环境接受清空重来:
docker compose down -v && docker compose up -d
(-v 删卷后重新初始化,init-monitor.sql 的新内容才会执行。)
11.6 宿主端口 8134 被占用导致 exporter 启动失败
现象:docker compose up -d 后 exporter 反复重启,docker compose logs exporter 尾部有 bind: address already in use 字样。
定位:宿主 8134 已被其他进程监听(ss -ltnp | grep 8134 可确认占用者)。
解决:改 compose 的 ports 为其他空闲端口(如 "18134:9630"),docker compose up -d 重建;Prometheus 抓取目标同步更新。exporter 容器内端口 9630 不需要动。
11.7 新建的数据库没有被监控
现象:数据库实例上新建了库,/metrics 里却没有按该库拆分的指标。
定位:先看 exporter 日志有无该库的 spawn new server for database <库名> 记录;没有则确认两件事——该库是否落在自动发现排除清单(默认排除 template0,template1,postgres)、监控账号对该库是否有 CONNECT 权限。
解决:排除清单问题用 --exclude-database/--include-database(或对应 PG_EXPORTER_* 环境变量)调整;权限问题在目标库执行 GRANT CONNECT ON DATABASE <库名> TO dbuser_monitor;。改动后 POST /reload 或重启 exporter。本方案 4.5 节日志中 database dbtest is installed due to auto-discovery 就是自动发现正常工作的标准回显。
十二、参考链接
- pg_exporter 官方仓库:https://github.com/pgsty/pg_exporter (README 的 Quick Start / Docker / API 章节为本文镜像与端点信息的来源,查询日期 2026-11-01)
- 官方 Docker 镜像:https://hub.docker.com/r/pgsty/pg_exporter (标签与多架构说明;镜像 OCI label 实测见 2.2 节)
- PostgreSQL 官方镜像文档:https://hub.docker.com/_/postgres (
POSTGRES_PASSWORD与/docker-entrypoint-initdb.d/初始化机制说明) - 站内系列篇:认知与选型见 《pg_exporter 1.5.0 介绍与选型指南》;配置体系逐项拆解见 《pg_exporter 1.5.0 配置参数详解》;命令行与 systemd 部署见 《pg_exporter 1.5.0 常用 CLI 命令与工具详解》