pgsql-onekey-backup

PostgreSQL OneKey Backup

一个面向 Linux 和 Cron 的单文件 PostgreSQL 逻辑备份工具。它逐库调用 pg_dump,可导出集群全局对象,并在校验完成后原子发布备份。

功能

本项目只做逻辑备份,不提供物理备份、WAL 归档、PITR、流复制、增量备份、对象存储上传或备份加密。

安装

需要 Bash 4.2+、PostgreSQL 客户端、flock,以及 sha256sumshasumzipcurl、Apprise 和 timeout 只在对应功能启用时需要。

Debian 或 Ubuntu:

sudo apt-get update
sudo apt-get install postgresql-client util-linux coreutils zip

脚本可以先独立检查依赖。它不会安装软件,也不会连接数据库:

bash pgsql_backup.sh --dependency-report

安装脚本:

sudo install -d -m 755 /opt/postgresql-backup &&
sudo curl -fL https://raw.githubusercontent.com/funnyzak/pgsql-onekey-backup/main/pgsql_backup.sh \
  -o /opt/postgresql-backup/pgsql_backup.sh &&
sudo chmod 755 /opt/postgresql-backup/pgsql_backup.sh

下载地址使用 main 分支,每次安装都会获取最新版脚本。执行前可先打开下载地址检查脚本内容。

Homebrew 的 libpq 默认可能不在 PATH 中。按 brew info libpq 的提示加入其 bin 目录。

客户端最好与服务端使用相同主版本,至少不能比服务端旧。脚本会在连接预检时拒绝较旧的 pg_dump

快速开始

目标根目录必须提前创建,归运行脚本的用户所有,且组用户和其他用户不能写入:

install -d -m 700 /var/backups/postgresql

离线检查配置和本机依赖:

bash pgsql_backup.sh \
  --target-dir /var/backups/postgresql \
  --host 127.0.0.1 \
  --port 5432 \
  --user backup \
  --passfile /etc/postgresql-backup/pgpass \
  --database app \
  --check

执行单库备份:

bash pgsql_backup.sh \
  --target-dir /var/backups/postgresql \
  --host 127.0.0.1 \
  --port 5432 \
  --user backup \
  --passfile /etc/postgresql-backup/pgpass \
  --database app

多次传入 --database 可按指定顺序备份多个数据库。不传数据库或使用 --all-databases 时,脚本通过维护库查询所有 datallowconn=truedatistemplate=false 的数据库。

认证

passfile

生产环境推荐 passfile。文件必须是当前用户所有的普通文件,不能是符号链接,权限不能宽于 0600;各级父目录也不能允许组用户或其他用户写入。

127.0.0.1:5432:*:backup:replace-with-your-password
chmod 600 /etc/postgresql-backup/pgpass
bash pgsql_backup.sh \
  --target-dir /var/backups/postgresql \
  --passfile /etc/postgresql-backup/pgpass \
  --database app

passfile 的字段顺序是 hostname:port:database:username:password。字段中的 : 写成 \:,反斜杠写成 \\。尽量使用精确的主机、端口和用户,避免通配符匹配错误凭据。

service

service file 可保存连接参数。显式传入的 host、port、user 会覆盖 service 中的同名值。

[backup]
host=127.0.0.1
port=5432
user=backup
dbname=postgres
bash pgsql_backup.sh \
  --target-dir /var/backups/postgresql \
  --service backup \
  --service-file /etc/postgresql-backup/pg_service.conf \
  --passfile /etc/postgresql-backup/pgpass \
  --database app

显式 service file 按敏感文件检查。只指定 --service 时,也可以使用系统或用户默认的 service 配置。

直接密码

export PGSQL_BACKUP_PASSWORD='replace-with-your-password'
bash pgsql_backup.sh \
  --target-dir /var/backups/postgresql \
  --database app

直接密码不能与 passfile 或 service 组合。脚本只对子数据库客户端进程设置 PGPASSWORD,不会把密码写入日志、manifest、通知或 Hook 环境。命令行 --password 会进入 Shell 历史和进程参数,生产环境不推荐。

未显式配置认证时,libpq 仍可读取运行用户的默认 .pgpass、service 或使用服务端免密认证。Cron 必须使用同一系统用户。

数据库范围和全局对象

默认维护库是 postgres。不存在时显式指定:

--maintenance-database template1

--globals-mode 支持:

全局对象默认使用 pg_dumpall --globals-only --no-role-passwords--include-role-passwords 会把角色密码哈希写入 globals.sql,只应在明确评估风险后使用。

单个 pg_dump 使用一致快照;多个数据库按顺序导出,不保证跨库同一时点一致。严格一致的业务应由外部流程管理停写和恢复、安排维护窗口,或改用物理备份。不要把前置 Hook 和发布后 Hook 当成必定成对执行的停写机制。

产物

--format 决定数据库文件格式:

--compression 0..9 只控制 custom 内部压缩。plain 模式显式设置压缩级别会失败。

--output-mode 决定包装方式:

custom 外层 Zip 使用 store 模式,避免重复压缩。

/var/backups/postgresql/
├── .staging/
└── runs/
    └── pgback_20260807T120000Z_12345/
        ├── .pgsql-onekey-backup-run
        ├── backup.zip
        ├── manifest.txt
        └── SHA256SUMS

manifest 记录客户端和服务端版本、认证来源、最终数据库与文件映射、逐库时间和大小,但不记录密码、Token 或敏感文件内容。

恢复

恢复前先复制产物到权限受控的临时目录。不要直接在备份目录中修改文件。

sha256sum -c SHA256SUMS
zip -T backup.zip
unzip backup.zip -d restore-files

阅读 manifest.txtglobals.sql。异机恢复时,globals.sql 中的表空间绝对路径可能不存在,需要先修改或预建目录。

需要集群对象时先恢复 globals:

psql --dbname=postgres --file=restore-files/globals.sql

恢复 custom:

pg_restore --create --dbname=postgres restore-files/001_app.dump

恢复 plain:

psql --dbname=postgres --file=restore-files/001_app.sql

每个备份固定加入 --create,因此恢复命令连接维护库。恢复后检查扩展、所有者、权限、表空间、行数和应用连接。备份命令成功不等于恢复可用,发布前必须演练一次完整恢复。

Hook

三类 Hook 都必须是当前用户所有的绝对路径普通可执行文件,不能是符号链接,组用户和其他用户不能写入。

所有 Hook 接收 BACKUP_RUN_IDBACKUP_TARGET_DIRBACKUP_STAGE_DIRBACKUP_PUBLISHED_DIR。每库 Hook 还接收数据库名、文件、序号、总数、格式和 output mode。Hook 使用干净环境启动,不接收 libpq 凭据或通知密钥。

前置或每库 Hook 失败时不发布。发布后 Hook 失败时保留已发布产物,但脚本返回失败。

--after-hook 只在备份发布成功后执行。导出或校验中途失败时不会执行它,因此前置 Hook 不适合单独承担“停写”、后置 Hook 承担“恢复写入”。需要停写时,应由外部编排保证失败后也能恢复,或使用带自动过期的维护状态。

通知

默认发送成功和失败通知,--notify-start 还会发送开始通知。支持以下渠道:

通知默认脱敏,不显示连接、用户、数据库、目标路径和错误详情。受信任渠道可使用 --no-notify-redact。HTTP 通知只接受 HTTPS;只有 localhost127.0.0.1[::1] 可以使用 HTTP。单个通知渠道失败不会改变备份结果。

Cron

每天 03:00 使用 passfile 备份全部数据库:

0 3 * * * /usr/bin/bash '/opt/postgresql-backup/pgsql_backup.sh' --target-dir '/var/backups/postgresql' --host '127.0.0.1' --port '5432' --user 'postgres' --passfile '/etc/postgresql-backup/pgpass' --notify-redact --all-databases >> '/var/log/postgresql-backup.log' 2>&1

每条 Cron 任务携带完整参数,多个任务不会共享环境配置。Linux 上通常使用 /usr/bin/bash。Crontab 必须是一条物理行;命令中的 % 要写成 \%。密码、Token 和 Webhook 会以明文保存在 Crontab 中,生产环境优先使用权限为 600 的 passfile、service file 或通知配置文件,并使用独立的低权限账号运行任务。

保留期和并发

--expire-hours 默认 4320 小时,0 表示不清理。脚本只检查 runs/pgback_* 的一级真实目录,并同时核对身份文件和 manifest 中的格式版本及 Run ID。无法识别的目录只警告,不删除。

同一目标目录使用非阻塞 flock。已有任务运行时,新任务立即失败。

配置

每个选项都有 PGSQL_BACKUP_* 环境变量形式,CLI 优先。PGSQL_BACKUP_DATABASESPGSQL_BACKUP_DUMP_OPTIONS 每行一项;只要 CLI 出现同类列表选项,就整体替换环境变量列表。

脚本只接受 --option value,不接受 --option=value。完整参数可查看:

bash pgsql_backup.sh --help

安全边界

License

MIT