PostgreSQL 18:用 extension_control_path 把扩展安装目录搬出系统目录

2026-07-18 40 预计阅读时间: 1 分钟
来源: postgr.es AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

PostgreSQL 18 为扩展部署增加了 extension_control_path。过去,扩展通常必须放进 PostgreSQL 的系统目录,才能被 CREATE EXTENSION 找到;现在可以把扩展放在自定义目录中,再通过配置告诉 PostgreSQL 去哪里搜索。

这项变化对容器镜像、无 root 权限部署、同一台机器维护多套 PostgreSQL 版本,以及需要隔离第三方扩展的环境都很实用。扩展不再必须和 PostgreSQL 主安装目录绑定,安装和升级的边界也更清晰。

这个参数解决了什么问题

扩展并不只有一个文件。典型扩展可能包含:

  • .control 控制文件
  • 一个或多个版本化的 SQL 安装脚本
  • C、Rust 或其他语言编译出的共享库
  • 额外的配置、文档或迁移文件

传统做法通常是把这些文件复制到 PostgreSQL 的 share/extensionlib 等系统目录。这样做有几个实际问题:

  • 修改系统目录通常需要 root 权限。
  • 扩展升级会直接影响整套 PostgreSQL 安装。
  • 多个 PostgreSQL 版本之间容易发生路径和 ABI 混用。
  • 容器中需要为了一个扩展重新构建基础 PostgreSQL 镜像。

extension_control_path 提供了一个额外的扩展控制文件搜索路径。可以把自定义扩展目录加入 PostgreSQL 配置,然后在数据库中照常执行 CREATE EXTENSION

它改变的是 PostgreSQL 查找扩展的方式,并不会自动解决扩展二进制文件的兼容性问题。扩展共享库仍然必须针对正在运行的 PostgreSQL 主版本和目标平台构建。

一个可改造的目录布局

下面是一个可以用于测试或内部部署的目录布局。这里假设扩展安装包已经准备好,并且把控制文件和相关 SQL 文件放在 /srv/pg18/extensions 下:

/srv/pg18/extensions/
└── demo_ext.control
└── demo_ext--1.0.sql

如果扩展还包含共享库,可以把它放在扩展约定的位置,并在控制文件的 module_pathname 中使用正确路径。实际目录结构应以扩展自身的安装说明为准。

在 Unix 系统上,可以这样准备目录并检查文件:

set -eu

EXT_DIR=/srv/pg18/extensions
sudo install -d -o postgres -g postgres -m 0755 "$EXT_DIR"

# 将已经构建好的扩展文件复制到自定义目录。
# 请把 ./build/demo_ext.* 替换成实际构建产物。
sudo install -o postgres -g postgres -m 0644 ./build/demo_ext.control "$EXT_DIR/"
sudo install -o postgres -g postgres -m 0644 ./build/demo_ext--1.0.sql "$EXT_DIR/"

sudo -u postgres ls -l "$EXT_DIR"

不要直接把尚未针对当前 PostgreSQL 18 构建的 .so 文件复制过去。控制文件能够被找到,并不代表共享库一定能够加载。

配置并创建扩展

可以在 postgresql.conf 中加入自定义目录:

# Unix 环境示例;多个目录使用 PostgreSQL 支持的路径列表格式
extension_control_path = '/srv/pg18/extensions'

修改配置后重新加载配置:

sudo -u postgres psql -d postgres -c "SELECT pg_reload_conf();"
sudo -u postgres psql -d appdb -c "SHOW extension_control_path;"

确认参数生效后,创建扩展:

CREATE EXTENSION demo_ext VERSION '1.0';

SELECT extname, extversion
FROM pg_extension
WHERE extname = 'demo_ext';

如果只想在一个会话中验证路径,也可以先临时设置参数,再创建扩展:

SET extension_control_path = '/srv/pg18/extensions';
CREATE EXTENSION demo_ext;

临时设置适合验证扩展包是否完整,不适合生产部署。生产环境应把配置纳入配置管理,并明确记录扩展目录的所有者、权限和发布版本。

部署时需要特别检查的边界

只配置路径,不等于完成扩展安装

extension_control_path 解决的是发现扩展控制文件的问题。扩展的 SQL 脚本、共享库、动态链接依赖,以及扩展需要的操作系统权限仍然需要单独准备。部署流水线应该把这些文件作为一个有版本的扩展包处理,而不是只复制一个 .control 文件。

PostgreSQL 主版本和 ABI 必须匹配

例如,为 PostgreSQL 17 编译的共享库不应默认拿到 PostgreSQL 18 上使用。即使 PostgreSQL 能找到对应的控制文件,执行扩展函数时仍可能因为符号、ABI 或编译选项不兼容而失败。

可以在发布时记录构建环境并执行最小验证:

pg_config --version
pg_config --pkglibdir
pg_config --sharedir

psql -X -v ON_ERROR_STOP=1 -d appdb <<'SQL'
SELECT current_setting('server_version');
CREATE EXTENSION IF NOT EXISTS demo_ext;
SELECT extname, extversion FROM pg_extension WHERE extname = 'demo_ext';
SQL

权限和安全边界不能忽略

自定义扩展目录中的文件会参与数据库扩展加载流程。目录不应允许普通应用用户随意写入,否则攻击者可能替换控制文件、SQL 脚本或共享库。建议至少做到:

  • 目录由专门的部署用户或 postgres 管理。
  • 应用运行用户没有写权限。
  • 扩展包发布前校验来源、版本和校验和。
  • 将扩展目录纳入备份、审计和回滚流程。
  • 在升级前确认所有数据库实例使用的是同一套扩展文件。

什么时候值得采用

如果团队需要在没有 root 权限的环境中安装扩展,或者希望让扩展生命周期独立于 PostgreSQL 系统目录,extension_control_path 是一个直接的选择。它也适合把内部扩展放到 /srv、挂载卷或镜像外部目录中。

不过,集中管理系统目录仍然有它的价值:操作系统包管理器能够统一处理依赖,标准目录也更容易被现有监控和运维脚本识别。是否采用自定义路径,应结合扩展数量、升级频率、权限模型和回滚要求决定。

上线前可以按这份清单检查:

  • [ ] 控制文件、SQL 脚本和共享库来自同一个扩展版本。
  • [ ] 扩展是针对当前 PostgreSQL 主版本和平台构建的。
  • [ ] SHOW extension_control_path; 返回预期目录。
  • [ ] 测试库中可以完成 CREATE EXTENSION 和升级验证。
  • [ ] 自定义目录不会被应用用户写入。
  • [ ] 扩展文件有明确的发布、备份和回滚方案。

PostgreSQL 18 的这项能力并不是让扩展部署变得无需管理,而是把“扩展必须放进系统目录”这个硬约束移除了。对于需要隔离权限和版本的部署环境,这个边界变化足以简化不少工程流程。


相关推荐