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_exporterPostgreSQLPrometheusGolang数据库监控2026/11/01

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.01.5.0(go1.27.3 构建)20.3 MB官方唯一镜像源,GoReleaser 多架构构建(amd64/arm64)
被监控数据库postgres:1616.15642 MBPostgreSQL 官方镜像,与 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版本可追溯、升级显式可控,生产首选
跟随 latestpgsty/pg_exporter:latest自动拿最新,但升级时机不可控、回滚困难
固定 digestpgsty/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_PASSWORDdbq1w2e3r4postgres 超级用户密码,首次初始化时生效
POSTGRES_USER / POSTGRES_DBdb未设置分别默认 postgres / $POSTGRES_USER,本方案用默认值

6.2 pg_exporter 的 PG_EXPORTER_* 环境变量:pg_exporter 的启动参数大多有同名环境变量形态,在容器部署时可改用 environment: 注入(与 command: 参数等价,命令行参数优先)。常用变量与官方默认值:

环境变量对应命令行参数官方默认值作用
PG_EXPORTER_URL--urlpostgresql:///?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-cachefalse关闭全部采集器 TTL 缓存
PG_EXPORTER_AUTO_DISCOVERY--auto-discoverytrue自动发现实例内全部可连接数据库
PG_EXPORTER_EXCLUDE_DATABASE--exclude-databasetemplate0,template1,postgres自动发现排除清单
PG_EXPORTER_INCLUDE_DATABASE--include-database空自动发现白名单(设置后仅发现清单内数据库)
PG_EXPORTER_NAMESPACE--namespacepg指标命名空间前缀(PgBouncer 场景用 pgbouncer)
PG_EXPORTER_CONNECT_TIMEOUT--connect-timeout100连接超时(毫秒)
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 编排参数:

参数取值可调整方向与影响
namepg-exporter-1.5.0-stack项目名标识;含点号会被规范化(见 11.1),建议用小写字母/数字/连字符
db.imagepostgres:16换成已有数据库时整段删除 db 服务,改 --url 指向外部地址
db.environment.POSTGRES_PASSWORDq1w2e3r4生产环境务必更换强密码,并与连接串同步
db.healthcheckpg_isready -U postgres,5 秒间隔数据库启动慢(大库崩溃恢复)时加大 retries
exporter.command --urlpostgres://dbuser_monitor:q1w2e3r4@db:5432/postgres?sslmode=disable指向真实库时改主机与账号;远程库显式用 sslmode=require 及以上
exporter.command --config/etc/pg_exporter/demo.yml换成默认全量配置时挂载官方 pg_exporter.yml 并改此路径
exporter.ports8134:9630宿主端口按需改;9630 是 exporter 内部固定端口一般不动
exporter.depends_onservice_healthy保证启动顺序,无需调整

7.2 pg_exporter 启动参数(本方案 command 中出现的三个):

参数本方案取值默认值说明
--urlpostgres://dbuser_monitor:q1w2e3r4@db:5432/postgres?sslmode=disablepostgresql:///?sslmode=disable监控目标连接串;未写 sslmode 时会自动注入 sslmode=disable
--config/etc/pg_exporter/demo.yml按探测顺序回退支持单文件或目录(目录内 YAML 按字母序合并)
--web.listen-address:9630:9630HTTP 监听地址,含 /metrics 与健康检查端点

7.3 采集器配置(demo.yml)的调度行为——启动日志已给出实证:

采集器tags 标签规划结果
demo_orders_statdbname:dbtest仅安装到 dbtest(postgres 库 discarded)
demo_db_sizecluster每个库的 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-netdocker 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 -fcompose 的核心增益即在此

结论: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 就是自动发现正常工作的标准回显。

十二、参考链接

  1. pg_exporter 官方仓库:https://github.com/pgsty/pg_exporter (README 的 Quick Start / Docker / API 章节为本文镜像与端点信息的来源,查询日期 2026-11-01)
  2. 官方 Docker 镜像:https://hub.docker.com/r/pgsty/pg_exporter (标签与多架构说明;镜像 OCI label 实测见 2.2 节)
  3. PostgreSQL 官方镜像文档:https://hub.docker.com/_/postgres (POSTGRES_PASSWORD 与 /docker-entrypoint-initdb.d/ 初始化机制说明)
  4. 站内系列篇:认知与选型见 《pg_exporter 1.5.0 介绍与选型指南》;配置体系逐项拆解见 《pg_exporter 1.5.0 配置参数详解》;命令行与 systemd 部署见 《pg_exporter 1.5.0 常用 CLI 命令与工具详解》