这是本节的多页打印视图。 .
文档
1 - 快速开始
几分钟内让 pgcli 运行起来。
安装
使用单条命令安装 pgcli:
此脚本将:
- 为你的平台下载最新的 pgcli 二进制文件
- 安装到
/usr/local/bin(如果没有 sudo 则安装到~/.local/bin) - 将 pgcli 添加到你的 PATH
初始化配置
这会在 ~/.pgcli/pg.yaml 创建带有合理默认值的配置,包括:
- 名为
default的默认实例 - 数据目录
/data/pg/default - 从 35432 开始自动分配的端口
启动实例
输出会显示连接 URL、管理员密码和备份状态。
连接到数据库
基本操作
多实例管理
多配置文件(隔离环境)
为同一主机上的隔离测试环境或每个项目一个配置,
使用不同的 --namespace 和不重叠的端口范围生成独立的配置文件。
| 参数 | 默认值 | 含义 |
|---|---|---|
--namespace |
default |
容器名称前缀:pgcli-pg-<namespace>-<instance> |
--pg-start-port |
35432 |
第一个 PG 主机端口;实例按顺序分配 |
--pg-ssh-port |
42201 |
第一个 SSH 主机端口;按顺序分配 |
规划建议:
- 始终使用显式的
--namespace以避免容器名称冲突。 - 同一主机上的端口范围不能重叠。
- 命名空间在创建时固化到容器名称中。 后期更改需要
pg destroy后重新初始化。
交互式 psql 会话
在交互式 psql 中你可以使用:
- 带历史记录和 tab 补全的 SQL 查询
- psql 元命令(
\dt、\du、\l等) \q退出
容器 Shell
Shell 以 root 身份在容器内运行,可以完全访问:
- PostgreSQL 数据目录(
/var/lib/postgresql/data) - 配置文件
- 日志文件(
/var/log/postgresql/) - 所有系统工具和实用程序
下一步
2 - 命名空间隔离
命名空间允许你在单台主机上创建完全隔离的环境,非常适合将生产、开发和测试环境分开,避免容器名称冲突或端口冲突。
什么是命名空间?
命名空间是应用于配置文件中所有容器名称的前缀。这种隔离机制确保:
- 容器名称不冲突:每个命名空间有自己的容器前缀
- 端口范围分离:每个配置文件从自己的范围分配端口
- 备份容器隔离:每个命名空间有自己的 pgBackRest 容器
- 配置文件独立:每个环境使用单独的配置文件
使用场景:生产和开发环境
一个常见场景是在同一台服务器上运行生产和开发环境:
这会创建两个完全隔离的环境:
| 环境 | 配置文件 | 容器前缀 | PG 端口范围 | SSH 端口范围 |
|---|---|---|---|---|
| 生产 | ~/.pgcli-prod/pg.yaml |
pgcli-pg-prod-* |
35432+ | 42201+ |
| 开发 | ~/.pgcli-dev/pg.yaml |
pgcli-pg-dev-* |
38000+ | 43000+ |
管理多个环境
使用 -c 标志指定要使用的配置文件:
工作原理
容器命名
命名空间为 prod,实例为 app-db:
- 实例容器:
pgcli-pg-prod-app-db - 备份容器:
pgcli-backup-prod - 网络:
pgcli-net-prod(如果使用独立网络)
没有命名空间(或 --namespace ""):
- 实例容器:
pgcli-pg-default-app-db - 备份容器:
pgcli-backup-default
端口分配
配置文件中的每个实例获得顺序端口:
- 第一个实例:
pg_start_port(例如 35432) - 第二个实例:
pg_start_port + 1(例如 35433) - 依此类推…
SSH 端口同理。
配置持久化
命名空间和端口范围保存在配置文件中:
最佳实践
1. 始终使用显式命名空间
在一台主机上运行多个配置时,永远不要依赖默认命名空间:
2. 使用不重叠的端口范围
确保配置之间的端口范围不重叠:
为每个环境中的多个实例预留足够的端口空间。
3. 命名空间在创建时固化
命名空间在创建时嵌入容器名称。之后更改会破坏关联:
4. 使用 Shell 别名简化操作
创建别名避免重复输入 -c:
高级用法:带副本的多环境
你甚至可以设置隔离的复制环境:
每个环境维护自己的复制槽、备份 stanza 和数据目录。
故障排除
容器名称冲突
原因:两个配置使用了相同的命名空间。
解决:使用不同的命名空间,或先销毁冲突的实例。
端口已被占用
原因:配置之间的端口范围重叠。
解决:使用不重叠的端口范围,并预留足够间距。
更改命名空间后找不到实例
原因:创建实例后更改了配置文件中的命名空间。
解决:销毁并重建实例,或恢复命名空间更改。
总结
命名空间为单台主机上的多环境提供完全隔离:
- 独立配置:每个环境有自己的
pg.yaml - 不同命名空间:防止容器名称冲突
- 不重叠端口:避免端口冲突
- 独立操作:每个环境使用
-c单独管理
非常适合在同一台服务器上运行生产、开发、测试和预发布环境,互不干扰。
3 - exec 和 psql
两种对实例运行 SQL 的方式:pg exec 用于一次性 SQL 或容器命令,pg psql 用于交互式会话。
pg exec
SQL 模式(默认)
没有 -- 的参数作为 SQL 通过 psql 执行,使用实例配置的用户和数据库。
容器命令模式(– 之后)
-- 之后的参数直接在容器内运行(以 root 身份)。
远程数据库(–dsn)
通过连接字符串对任何可达数据库执行 SQL,使用临时容器。--dsn 仅支持 SQL 模式;容器命令需要本地实例。
pg psql
交互式会话
在 shell 内你获得完整的 psql 功能:带历史记录和 tab 补全的 SQL、元命令(\dt、\du、\l),以及 \q 退出。
非交互式(脚本)
切换到 postgres 超级用户
某些管理任务(例如创建某些扩展、修改系统级设置)需要 postgres 超级用户权限。使用 -- 传递 psql 参数并切换用户:
推荐方法:日常操作使用实例默认用户(admin),仅在需要超级用户权限时切换到 postgres。这比修改配置文件或重启容器更安全更方便。
示例场景:
远程数据库(–dsn)
规则
--dsn和--instance互斥:连接字符串确定主机、端口和数据库,因此-i被拒绝以避免静默误用。- 使用
--dsn时,数据库是 URL 的路径部分:postgres://user:pass@host:5432/mydb连接到mydb。要使用另一个数据库,更改路径。 - 使用本地实例时,
--传递原始 psql 参数(包括-d/-U),覆盖实例默认值。
4 - PostgreSQL 扩展
pgcli 支持从 Pigsty DEB 仓库安装和管理 PostgreSQL 扩展。
工作原理
扩展被烘焙到派生容器镜像中:
pg extension install构建新镜像(基于当前镜像 + Pigsty 仓库 + 扩展包)- 停止并移除旧容器
- 从新镜像重新创建容器(主机数据卷被保留)
- 更新配置文件中的
image_tag
这种方法的优势:
- 扩展在容器重建后仍然存在(烘焙到镜像层)
pg start不需要在每次启动时运行apt-get install- 扩展文件是持久的并与容器生命周期解耦
命令
安装扩展
重启确认: 需要 shared_preload_libraries 的扩展(例如 pg_stat_statements、pg_cron)需要 PostgreSQL 重启。默认情况下,会提示你确认:
如果你拒绝重启,可以稍后应用更改:
列出已安装扩展
示例输出:
- managed:由 pgcli 跟踪(记录在配置中,包含在镜像中)
- unmanaged:手动安装的扩展(不在配置中跟踪)
移除扩展
工作流:
DROP EXTENSION IF EXISTS pgmq- 更新配置和
shared_preload_libraries - 无镜像重建 —
-ext镜像在实例间共享,包永远不会被卸载
重启确认: 如果移除需要 shared_preload_libraries 的扩展(例如 pg_stat_statements、pg_cron),会在重启前提示你确认:
如果你拒绝重启,可以稍后应用更改:
查看可用扩展
列出所有 440 个已知扩展:
- 45 个内置(contrib,已在基础镜像中——无需镜像构建)
- 395 个 Pigsty 目录(来自 Pigsty DEB 仓库,需要镜像构建)
内置扩展目录
需要 shared_preload_libraries(安装时重启)
| 扩展 | 描述 |
|---|---|
pg_stat_statements |
SQL 性能分析 |
pg_cron |
定时任务执行 |
pg_hint_plan |
查询提示 |
pg_stat_monitor |
高级性能监控 |
pg_qualstats |
查询谓词统计 |
pg_stat_kcache |
内核级性能统计 |
pg_wait_sampling |
等待事件采样 |
pg_track_settings |
配置更改跟踪 |
timescaledb |
时序数据库扩展 |
不需要 shared_preload_libraries(无需重启)
| 扩展 | 描述 |
|---|---|
uuid-ossp |
UUID 生成函数 |
pgmq |
轻量级消息队列 |
hstore |
键值对存储 |
pgcrypto |
加密函数 |
tablefunc |
交叉表函数 |
btree_gist |
B-tree GiST 索引支持 |
btree_gin |
B-tree GIN 索引支持 |
pg_trgm |
三元组相似性匹配 |
unaccent |
去重音函数 |
fuzzystrmatch |
模糊字符串匹配 |
intarray |
整数数组操作 |
isn |
ISBN/ISSN/EAN 标准数字类型 |
pg_repack |
在线表重组 |
pg_squeeze |
表空间回收 |
pg_partman |
分区管理 |
pgvector |
向量相似性搜索 |
postgis |
地理空间数据支持 |
目录外的扩展
只有目录中的扩展(builtin + Pigsty)可以通过 pg extension install 安装。未知扩展名称会在构建开始前被拒绝:
完整目录:https://pigsty.cc/ext/list/
配置
安装扩展后,配置会被更新:
image_tag 指向包含所有已安装扩展的派生镜像。
共享预加载库
需要 shared_preload_libraries 的扩展会在 postgresql.conf 中自动配置:
这是 postmaster 级别参数;更改后必须重启 PostgreSQL。
故障排除
扩展安装失败
原因:扩展名称不在内置 contrib 列表或 Pigsty 目录中。
解决方法:
- 验证扩展名称:
pg extension available - 检查 Pigsty 目录:https://pigsty.cc/ext/list/
- 注意确切的 SQL 扩展名称(例如
vector而不是pgvector)
CREATE EXTENSION 失败
扩展已安装但未在配置中跟踪。你可以安全地忽略这个,或手动将其添加到配置:
共享预加载库冲突
如果 shared_preload_libraries 在 postgresql.conf 中被手动编辑,pgcli 的标记块会覆盖它。
解决方法:删除手动配置并让 pgcli 管理它。
注释
- 扩展数量:45 个内置(contrib)+ 395 个 Pigsty 目录 = 440 个已知扩展
- 镜像大小:每个扩展增加 10-50MB 到镜像,但 Pigsty 包已优化
- 构建时间:首次扩展安装需要 1-3 分钟(下载 + 构建);后续安装更快(缓存命中)
- 副本行为:副本可以安装扩展,但
CREATE EXTENSION会被拒绝(只读)。在主实例上安装;副本通过物理复制同步 - 扩展升级:
ALTER EXTENSION ... UPDATE TO ...尚不支持;通过pg exec手动运行
5 - 备份
快照
快照类型:
full— 完整备份(默认,自包含)diff— 自上次完整备份以来的更改incr— 自上次备份以来的更改
共享备份容器
所有实例共享单个 pgbackrest 容器;每个实例在存储库中都有自己的 stanza。
备份基础设施(网络、镜像、目录、配置、容器)在 pg start 时自动准备;手动运行 pg backup setup 重新初始化,例如更改基础目录之后。
6 - 副本(只读备用)
创建现有实例的只读物理副本。副本通过 PostgreSQL 物理复制从其主实例持续流式传输 WAL,并提供只读查询服务——适用于读写分离、报告或作为热备。
发生了什么
- 预检 — 主实例必须正在运行(在任何配置写入之前验证;停止的主实例会失败但没有副作用)
- 注册 — 添加新实例条目,使用主实例的数据库名称和密码(参见注释),禁用 PITR,
replica_of设置为主实例 - 复制设置 — 在主实例上:
pg_hba.conf为回环地址和 RFC1918 范围添加host replication条目(幂等)- 创建物理复制槽
pgcli_r_<name>,保留 WAL 以确保副本不会落后于 WAL 回收
- 基础备份 —
pg_basebackup -R将主实例的数据目录复制到副本的数据目录,写入primary_conninfo(带密码)和standby.signal,使副本以备用模式启动 - 启动 — 副本容器启动并持续流式传输 WAL
验证
销毁
销毁副本是两步操作:
步骤 1 必须在步骤 2 之前运行:PostgreSQL 拒绝删除仍在流式传输的槽(replication slot is active),因此必须先销毁副本以关闭其流式连接。
注意: 如果主实例是本地 pgcli 管理的实例(同一主机),可以跳过步骤 2 —
destroy会自动清理槽。当从副本主机无法访问主实例时需要步骤 2。
跨网络副本
上述同主机流程假设主实例和副本共享一个服务器(一个 podman 守护进程,一个网络)。对于在另一台主机上的副本,pgcli 在每一侧运行一个命令——无需 SSH,唯一的跨机器信息就是你作为参数传递的内容:
获取主实例 DSN
如果主实例是 pgcli 管理的实例,使用 pg status 获取其连接信息:
然后将 127.0.0.1 替换为从副本主机看到的主实例主机 IP(例如 10.241.20.50)——用户、密码和数据库按原样使用。注意主实例主机必须接受从副本主机到该端口的 TCP 连接(防火墙/安全组)。
每一侧的作用:
- 主实例侧(
--replica-host <ip|hostname>):仅准备主实例——本地不创建任何内容。它将host replication all <addr>条目追加到pg_hba.conf并创建物理槽pgcli_r_<name>,然后打印要在副本主机上运行的确切--primary-dsn命令。IP 地址获得/32(IPv6 为/128)掩码;主机名按原样写入。已在托管 RFC1918 范围(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)内的 IP 会被跳过去重。幂等——重新运行不会添加重复行。 - 副本侧(
--primary-dsn):首先验证主实例上存在槽(验证连接性和顺序——在主实例侧之前运行会失败并带有可操作的错误消息且没有副作用),然后注册实例,通过网络从 DSN 运行pg_basebackup(主机网络),并启动备用实例。
副本侧仅在副本主机上运行:副本实例的用户、数据库和密码来自 DSN(物理复制复制 pg_authid,因此本地密码必须等于主实例的密码)。主实例名称使用 --primary-name 给出并记录为 replica_of;它不必存在于副本主机的配置中,-i 不用于远程主实例——如果给出,它保持其严格含义并且必须引用真实的本地实例。
销毁是对称的,每个主机一个命令——按此顺序:
步骤 1 必须在步骤 2 之前运行:PostgreSQL 拒绝删除仍在流式传输的槽(replication slot is active),因此必须先销毁副本以关闭其流式连接。
自动槽清理: 当跨主机副本设置了 PrimaryDSN 时,destroy 会自动尝试通过 DSN 删除远程主实例上的复制槽。如果主实例可达,则无需手动步骤 2。replica drop 是幂等的——当槽已不存在时重新运行会作为无操作成功。
非 pgcli 主实例
主实例不必由 pgcli 管理——只要主实例侧已手动准备(槽检查仅验证槽是否存在,不验证谁创建了它),副本侧可以对任何 PostgreSQL 服务器工作:
- 在
pg_hba.conf中允许从副本主机复制,然后重新加载(SELECT pg_reload_conf()): - 使用确切名称
pgcli_r_<replica-name>创建物理槽(副本侧检查此名称):需要wal_level = replica(或logical)和具有REPLICATION权限的用户——DSN 用户。
然后副本侧命令不变:
销毁时,主实例侧没有 pgcli——在 pg destroy -i ro1 之后,手动删除槽:
如果基础备份失败(例如网络中断),销毁副本并重新运行副本侧命令——主实例侧的槽和 hba 条目保持有效。
注释
- 只读 — 副本拒绝所有写入(
cannot execute INSERT in a read-only transaction)。要使其可写你需要提升它(pg_ctl promote),这尚未作为 pgcli 命令暴露 - 相同数据,相同密码 — 物理复制是主实例的逐字节复制,包括
pg_authid。因此副本的管理员密码和数据库名称与主实例相同;只有容器名称、端口和数据目录不同。使用--dsn风格的连接时使用副本的端口 - 副本上禁用 PITR — 备用实例不归档任何内容,也不在 pgBackRest 备份容器中注册;备份在主实例上运行
- 主实例必须正在运行 — 初始创建(
pg_basebackup)和持续流式传输都需要;如果主实例重启,副本会自动重新连接(槽显示为active) - 延迟显示 —
replica list延迟(now() - pg_last_xact_replay_timestamp())在主实例空闲时会增长;它会在下一个复制的事务时降回零。这是预期的空闲行为,不是漂移 - 幂等启动 — 重复的
pg start -i ro1在数据目录已初始化时跳过基础备份
7 - 故障转移:副本提升
当当前主实例失败时,将副本提升为新的主实例。pgcli 提供 3 步手动故障转移工作流——每个步骤在其各自的主机上运行,不自动检测同主机与跨主机拓扑。
概述
故障转移后(提升 ro1 → 新主实例):
3 步故障转移
每个步骤都是独立的命令。按顺序在各自的主机上运行它们。
步骤 1:pg replica promote <name>
在被提升为主实例的副本主机上运行。
发生了什么:
- 验证实例是副本(
ReplicaOf已设置)且容器正在运行 - 调用
pg_promote()(PostgreSQL 12+ 原生提升——无需容器重启) - 等待恢复结束(通常亚秒级)
- 通过
ALTER SYSTEM RESET从postgresql.auto.conf清理primary_conninfo - 更新配置:清除
ReplicaOf和PrimaryDSN,启用PITR - 自动初始化 PITR:
- pgBackRest stanza 创建
archive_mode/archive_command配置- PostgreSQL 重启以应用 postmaster 级别参数
- 打印下一步指令
幂等: 如果副本已被提升(例如通过手动 pg_ctl promote),命令会跳到配置更新。
步骤 2:pg replica drop <name> -i <old-primary>
在旧主实例主机上运行以清理复制槽。此步骤仅在特定场景中需要。
这会在旧主实例上删除物理复制槽 pgcli_r_ro1。没有清理,槽会无限期保留 WAL,直到主实例磁盘空间耗尽。
何时运行:
| 场景 | 操作 | 原因 |
|---|---|---|
| 旧主实例永久丢失 | 跳过 | 槽随服务器一起消失 |
| 计划将旧主实例降级为副本 | 跳过 | repoint 销毁数据目录(包括 pg_replslot/),所有槽被隐式移除 |
| 旧主实例已恢复,继续作为独立主实例运行 | 必须运行 | 槽无限期保留 WAL;没有清理磁盘最终会填满 |
| 旧主实例已恢复但将被关闭 | 可选 | 如果实例不再运行,跳过无害 |
保持旧主实例不变? 如果你想保留旧主实例及其原始数据(例如用于取证分析或作为只读归档),你可以简单地不理会它——不要在其上运行
drop或repoint。旧主实例继续作为具有陈旧数据的独立实例运行。只是要注意被提升副本的复制槽仍然存在并会累积 WAL;你可能想要仅删除那个特定的槽(pg replica drop ro1 -i pg01)同时保持其他一切不变。
步骤 3:pg replica repoint <name> --primary-dsn <dsn> --primary-name <name>
在每个剩余副本主机上运行以将其重新指向新主实例。
发生了什么:
- 通过 DSN 查询新主实例的扩展(
pg_extension目录) - 如果存在非内置扩展(例如 pg_cron、timescaledb),构建本地
-ext镜像并匹配包 - 停止旧副本容器并销毁其数据目录
- 通过 DSN 在新主实例上创建复制槽
- 更新配置:
ReplicaOf、PrimaryDSN、ImageTag、Extensions,禁用PITR - 通过
pg_basebackup -R从新主实例重新初始化 - 以备用模式启动副本容器
为什么销毁 + 重建而不是 ALTER SYSTEM SET?
提升后,新主实例进入新时间线。旧时间线上的其他副本不能简单地更改 primary_conninfo——PostgreSQL 会拒绝连接:
唯一安全的方法是从新主实例进行完整的 pg_basebackup。
获取主实例 DSN
从被提升副本主机上的 pg status 获取新主实例的连接字符串:
将 127.0.0.1 替换为从副本主机可达的新主实例主机 IP(例如 10.241.21.97)。
降级旧主实例
当旧主实例恢复时,你可以使用相同的 repoint 命令将其作为新主实例的副本重新加入:
即使 pg01 曾是主实例(未设置 ReplicaOf)这也有效。该命令:
- 停止 pg01 并销毁其数据(包括旧的 PITR stanza)
- 在新主实例上为 pg01 创建复制槽
- 设置
ReplicaOf = "ro1",PITR.Enabled = false - 通过
pg_basebackup从新主实例重新初始化
重新指向后,pg01 作为只读副本从新主实例流式传输 WAL——没有 WAL 归档,没有备份。
扩展同步
当副本被重新指向新主实例时,pgcli 会自动同步扩展:
- 查询 — 通过 DSN 连接到新主实例并查询
pg_extension获取已安装的扩展 - 过滤 — 识别非内置扩展(需要外部包的扩展,例如 pg_cron、pgmq、timescaledb)
- 构建 — 如果存在非内置扩展,构建本地
-ext镜像:- 如果本地
-ext镜像已存在,在其上安装缺失的包(重用 Pigsty 仓库——快速) - 如果没有
-ext镜像,从基础镜像构建并设置 Pigsty 仓库 apt-get install是幂等的——安装已存在的包是无操作
- 如果本地
- 应用 — 副本启动时,
ApplyExtensions将shared_preload_libraries写入postgresql.conf - 跳过 CREATE EXTENSION — 副本是只读的;扩展通过
pg_basebackup+ WAL 流式传输从主实例复制
这确保副本容器具有 postgresql.auto.conf 中引用的所需共享库(例如 pg_cron)。
同主机 vs 跨主机
pgcli 不自动检测拓扑。你选择在每个命令运行的位置:
| 场景 | 步骤 1 | 步骤 2 | 步骤 3 |
|---|---|---|---|
| 全部在同一主机 | pg replica promote ro1 |
pg replica drop ro1 -i pg01 |
pg replica repoint ro2 --primary-dsn "postgres://...@127.0.0.1:..." --primary-name ro1 |
| 主实例 + 副本分散在多个主机 | 在副本主机 | 在旧主实例主机 | 在每个副本主机上使用新主实例的网络 IP |
| 混合 | 在各自的主机 | 在旧主实例主机 | 在每个副本主机 |
--primary-dsn 必须使用从 repoint 运行所在主机可达的 IP/主机名。
完整示例
跨主机示例
级联复制
副本本身可以作为下游副本的主实例,形成级联链。这减少主实例的负载并启用分层拓扑。
工作原理
-
创建副本的副本:使用副本作为
-i目标 -
WAL 传播:
- ra2 从 ra3 流式传输 WAL
- ra2_ro1 从 ra2 流式传输 WAL
- 数据流:ra3 → ra2 → ra2_ro1
-
复制槽:每个链接维护自己的槽
- ra3 有槽
pgcli_r_ra2 - ra2 有槽
pgcli_r_ra2_ro1
- ra3 有槽
优势
- 减少主实例负载:只有直接副本连接到主实例
- 地理分布:主实例 → 区域副本 → 本地副本
- 网络效率:本地副本可以共享区域上游
限制
- 增加延迟:每一跳增加复制延迟
- 级联故障:如果 ra2 失败,ra2_ro1 失去其上游
- 提升复杂性:提升 ra2_ro1 需要将其重新指向新主实例
验证级联
级联故障转移
如果 ra2(中间节点)失败:
如果 ra3(主实例)失败且 ra2 被提升:
注释
- pg_promote() — PostgreSQL 12+ 原生函数,无需容器重启。实例就地退出恢复并立即变为可读写
- 时间线分歧 — 提升后,新主实例在新时间线上。其他副本不能用
ALTER SYSTEM SET primary_conninfo重新指向——它们必须通过pg_basebackup重建 - 被提升副本上的 PITR — 提升后,运行
pg start创建 pgBackRest stanza 并启用 WAL 归档。被提升的副本没有先前的备份历史 - 复制槽 — 旧主实例为被提升副本的槽在提升后变得陈旧。
pg replica drop清理它。如果旧主实例被降级为副本,repoint销毁旧数据且陈旧的槽不再被引用 - 扩展 — 副本容器通过
postgresql.auto.conf从主实例继承shared_preload_libraries。repoint 命令确保本地镜像在重建副本之前具有所需的扩展包 - 跳过 CREATE EXTENSION — 副本是只读的;
pg_basebackup从主实例复制扩展元数据,因此不需要CREATE EXTENSION(且会失败 “cannot execute CREATE EXTENSION in a read-only transaction”)
8 - 管理
Shell 补全
为命令、标志和实例名称启用 tab 补全。
Bash
Zsh
Fish
PowerShell
PostgreSQL 配置
通过 pg exec 使用 ALTER SYSTEM 修改 PostgreSQL 运行时参数,然后重新加载:
注意: 某些参数(例如 shared_buffers、max_connections)需要重启而不是重新加载。使用 pg stop && pg start 应用这些更改。
配置文件管理
检查或验证配置文件(默认为 ~/.pgcli/pg.yaml,使用 -c 覆盖)。
Init 生成默认配置;--add 在同一文件中创建命名实例,-o 写入自定义路径:
在一个主机上运行多个配置的隔离参数(参见快速开始进行规划):
| 参数 | 默认值 | 含义 |
|---|---|---|
--namespace |
default |
容器名称前缀:pgcli-pg-<namespace>-<instance>,备份容器 pgcli-backup-<namespace>。传递 --namespace "" 保持旧式名称不带前缀 |
--pg-start-port |
35432 |
分配范围中的第一个 PG 主机端口 |
--pg-ssh-port |
42201 |
分配范围中的第一个 SSH 主机端口 |
所有三个都保存到配置文件中(namespace、pg_start_port、pg_ssh_port);跨配置使用不重叠的端口范围,这样分配永远不会冲突。
9 - 克隆
创建新实例,其数据从现有实例复制,直接流式传输——磁盘上无临时文件。
发生了什么
- 预检 — 在创建任何内容之前验证源:
- 本地实例:容器必须正在运行
--dsn:认证的SELECT 1必须成功(捕获错误密码、不可达主机)
- 创建 — 新实例条目添加到配置,带有随机密码、自己的容器名称、数据目录和自动分配的端口
- 启动 — 新实例启动(与
pg start相同的工作流) - 流式传输 — 源数据管道传输到目标,每秒显示一次实时传输进度
注释
- 源实例必须正在运行(或
--dsn目标可达);错误的源会立即失败且无副作用 - 新实例名称在配置中不能已存在
--dsn和--instance互斥:使用--dsn时连接字符串确定主机、端口和数据库- 新实例获得新的随机密码——在克隆输出或
pg status -i <name>中查找 - 仅逻辑复制(模式 + 数据);对于大型数据库,物理方法可能更快
10 - 数据导入/导出
导出和导入数据库到转储文件。支持自定义格式(推荐)和纯 SQL,带有自动 gzip 压缩。还支持在实例间管道传输。
格式比较:
| 特性 | 自定义(.dump) |
SQL(.sql) |
|---|---|---|
| 导入速度 | 更快(二进制格式) | 更慢(文本格式) |
| 文件大小 | 更小(压缩) | 更大(纯文本) |
| 人类可读 | 否 | 是 |
| 选择性恢复 | 是(特定表) | 否 |
| 最适合 | 迁移、备份、大型数据库 | 版本控制、CI 种子数据、手动编辑 |
格式检测: 使用魔数(基于内容)配合扩展名回退。
- 以
PGDMP开头的文件 → 自定义格式 .sql或.sql.gz→ 纯 SQL 格式.gz扩展名或 gzip 魔数(0x1f 0x8b) → 自动解压- 如果内容检测失败则使用扩展名作为回退
远程数据库(–dsn): 使用连接字符串连接到任何 PostgreSQL 实例。
- 无需本地 PostgreSQL 安装
- 适用于本地到远程、远程到本地和远程到远程迁移
- 支持与本地实例相同的所有标志(
-o、-d、--clean、-v、--compress)
关于现有数据的说明: 导入到包含现有表的数据库会失败,除非你使用 --clean 标志,它会在恢复前删除对象。导入到已包含数据的数据库时使用 --clean。
用例:
- 在实例间迁移数据:
pg export -i proj01 | pg import -i proj02 - 跨主机迁移:
pg export -i proj01 | pg import --dsn postgres://user:pass@remote:5432/db - 与团队共享数据库:
pg export -i proj01 -o dump.dump.gz(压缩,更小文件) - 重大更改前备份:
pg export -i proj01 -o pre-migration.sql.gz - CI/CD 管道:导出测试数据,导入到新的测试数据库
11 - 恢复
时间点恢复(PITR)
恢复到首次备份后的任意时间点。
时间格式:
2026-08-26 15:30:00+08:00— 带时区偏移2026-08-26 15:30:00+08— 仅时区小时2026-08-26 15:30:00Z— UTC2026-08-26 15:30:00— 假定为 UTC
恢复工作流: 停止 → 恢复 → 启动 → WAL 重放到目标时间
注意: --promote 之后,在进行进一步的 PITR 之前需要创建新的完整快照。
12 - 销毁
destroy 会停止并移除容器,然后从配置文件中删除该实例。默认情况下,主机的数据目录会被保留。使用 --clean-data 可以同时移除数据、WAL 归档和 pgBackRest 仓库的 stanza。
基本用法
执行过程
运行 pg destroy 时:
- 停止容器 — PostgreSQL 优雅关闭
- 移除容器 — 删除 Podman 容器
- 移除配置 — 从
~/.pgcli/pg.yaml中删除该实例条目 - 保留数据(默认)— 主机数据目录
--base-dir/<instance>保留
使用 --clean-data 时:
- 以上所有步骤,加上:
- 移除主机数据 — 删除数据目录
- 移除 WAL 归档 — 删除主机上的所有 WAL 文件
- 移除备份 stanza — 删除该实例的 pgBackRest 仓库 stanza
重建实例
销毁后,可以重新创建实例以获得全新开始:
重要: 不使用 --clean-data 时,旧的数据目录会被保留。当你重新创建实例时,PostgreSQL 会使用现有数据,而 init.sh(创建用户和设置管理员密码)不会再次运行。这可能导致以下问题:
- 数据是用不同的用户或密码创建的
- 你更改了配置中的默认用户
- 你想要完全全新开始
需要彻底清理时使用 --clean-data。
确认提示
默认情况下,pg destroy 会在执行前询问确认:
使用 --force 跳过提示:
使用场景
1. 配置更改后的干净重启
如果你更改了配置中的默认用户、密码或 PostgreSQL 版本,销毁并重建:
2. 移除测试实例
测试完成后,移除不再需要的实例:
3. 修复损坏的状态
如果实例处于异常状态(例如启动失败、数据损坏),销毁并重建:
4. 释放资源
销毁不再活跃使用的实例以释放:
- Podman 容器(CPU 和内存)
- 主机磁盘空间(使用
--clean-data) - 配置文件中的条目
与副本的关系
销毁副本时,主实例上的复制槽不会自动移除。你需要单独清理:
这种两步流程确保如果你计划稍后重新创建副本,不会意外丢失复制槽。
安全注意事项
- 数据丢失:
--clean-data会永久删除该实例的所有数据、WAL 和备份。谨慎使用。 - 无法撤销:销毁后,除非有外部备份,否则实例无法恢复。
- 配置丢失:实例条目会从配置文件中移除。如果以后需要该配置,请先备份。
标志
| 标志 | 默认值 | 描述 |
|---|---|---|
--force |
false |
跳过确认提示 |
--clean-data |
false |
同时移除主机数据、WAL 归档和备份 stanza |
-i, --instance |
default |
要销毁的实例名称 |
相关命令
pg create— 创建新实例pg start— 启动实例pg stop— 停止实例(容器保留)pg replica drop— 从主实例移除复制槽