Skip to content

Commit e634614

Browse files
committed
feat(postgresql): 增加 pgBackRest 备份配置
1 parent 45e0859 commit e634614

20 files changed

Lines changed: 1269 additions & 6 deletions

File tree

.trellis/spec/infra/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@
1111
| [Coding Plan Window Warmer](./coding-plan-window-warmer.md) | 独立窗口预热脚本、直连上游、uv 依赖和 PM2 管理约定 | Active |
1212
| [LiteLLM Gateway](./litellm-gateway.md) | LiteLLM 路由、fallback、参数兼容和验证边界 | Active |
1313
| [Node/Vitest Scripts](./node-vitest-scripts.md) | 根目录 Vitest 发现的 Node 脚本测试与 shebang 行尾约定 | Active |
14+
| [PostgreSQL Toolkit](./postgresql-toolkit.md) | PostgreSQL / pgBackRest 命令边界、env 解析和备份范围约定 | Active |
1415
| [rathole template](./rathole.md) | rathole 裸二进制、PM2 管理、`.local.toml` 与公网白名单转发模板约定 | Active |
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# PostgreSQL Toolkit Spec
2+
3+
> 本规范记录 `scripts/pwsh/devops/postgresql``config/database/backup/pgBackRest` 的备份命令边界、env 解析和测试约定。
4+
5+
## Scenario: Postgres Toolkit + pgBackRest Maintenance
6+
7+
### 1. Scope / Trigger
8+
9+
- Trigger: 修改 `scripts/pwsh/devops/postgresql/**``scripts/pwsh/devops/Postgres-Toolkit.ps1`、PostgreSQL 备份文档或 `config/database/backup/pgBackRest/**`
10+
- Scope: `Postgres-Toolkit.ps1` 是统一维护入口;配置目录只放可复制模板和 README,不再新增平行 Bash 维护脚本。
11+
- Design intent: 逻辑备份和物理备份能力共用一个 CLI 分发、dry-run、构建和 Pester 测试体系,避免两套脚本漂移。
12+
13+
### 2. Signatures
14+
15+
- 逻辑快照:
16+
- `pwsh -File ./scripts/pwsh/devops/Postgres-Toolkit.ps1 backup --database app --output ./app.dump --format custom`
17+
- `pwsh -File ./scripts/pwsh/devops/Postgres-Toolkit.ps1 backup --database app --table public.orders --output ./orders.dump`
18+
- pgBackRest 物理备份:
19+
- `pwsh -File ./scripts/pwsh/devops/Postgres-Toolkit.ps1 pgbackrest --action check --config ./pgbackrest.conf.local`
20+
- `pwsh -File ./scripts/pwsh/devops/Postgres-Toolkit.ps1 pgbackrest --action stanza-create --config ./pgbackrest.conf.local`
21+
- `pwsh -File ./scripts/pwsh/devops/Postgres-Toolkit.ps1 pgbackrest --action backup --type full|diff|incr --config ./pgbackrest.conf.local`
22+
- `pwsh -File ./scripts/pwsh/devops/Postgres-Toolkit.ps1 pgbackrest --action info|expire --config ./pgbackrest.conf.local`
23+
- Build:
24+
- `pwsh -NoProfile -File ./scripts/pwsh/devops/postgresql/build/Build-PostgresToolkit.ps1`
25+
26+
### 3. Contracts
27+
28+
- `backup` wraps `pg_dump` and creates logical snapshots. It is not a generic incremental backup mechanism.
29+
- `pgbackrest` wraps `pgbackrest` and is the supported path for full/diff/incr physical backup chains.
30+
- `backup`, `restore`, and `import-csv` may call `Resolve-PgContext` and use PostgreSQL connection defaults.
31+
- `pgbackrest` must not call `Resolve-PgContext` before dispatch. It reads only explicit `--env-file` for `PGBR_*` values, so application `.env` files in the current directory cannot break physical-backup dry-runs.
32+
- Supported `pgbackrest --action` values are `check`, `stanza-create`, `backup`, `info`, and `expire`.
33+
- Supported `pgbackrest --type` values for `--action backup` are `full`, `diff`, and `incr`.
34+
35+
### 4. Validation & Error Matrix
36+
37+
| Condition | Expected Behavior |
38+
|-----------|-------------------|
39+
| `pgbackrest --action restore` | Throw a validation error listing supported actions |
40+
| `pgbackrest --action backup --type bad` | Throw a validation error listing `full`, `diff`, `incr` |
41+
| Current directory has non-PostgreSQL `.env` | `pgbackrest --dry-run` must still succeed when options are explicit |
42+
| `pgbackrest --env-file missing.local` | Throw `配置文件不存在` |
43+
| `backup --jobs 4 --format custom` | Throw because pg_dump parallel backup requires `directory` format |
44+
45+
### 5. Good/Base/Bad Cases
46+
47+
- Good: Use `pgbackrest --action backup --type incr` for incremental disaster-recovery backups.
48+
- Good: Use `backup --table public.orders` for a one-off logical table snapshot.
49+
- Base: `pgbackrest --dry-run` returns a preview command without requiring `pgbackrest` installed.
50+
- Bad: Add another maintenance script under `config/database/backup/pgBackRest` that duplicates toolkit behavior.
51+
- Bad: Treat `pg_dump` as an incremental backup tool. Business-key exports based on `updated_at` are data pipelines, not generic backups.
52+
53+
### 6. Tests Required
54+
55+
- `New-PgBackRestCommandSpec` builds command arguments for full/diff/incr backups.
56+
- Env-file defaults load `PGBR_CONFIG`, `PGBR_STANZA`, `PGBR_PG1_HOST`, `PGBR_PG1_HOST_TYPE`, and `PGBR_BACKUP_TYPE`.
57+
- Invalid `pgbackrest --action` throws.
58+
- Regression: `Invoke-PostgresToolkitCommand pgbackrest --dry-run` does not read current-directory `.env`.
59+
- Build test confirms generated `Postgres-Toolkit.ps1` includes the new command.
60+
61+
### 7. Wrong vs Correct
62+
63+
#### Wrong
64+
65+
```powershell
66+
$context = Resolve-PgContext -CliOptions $options
67+
switch ($CommandName) {
68+
'pgbackrest' {
69+
$spec = New-PgBackRestCommandSpec -CliOptions $options
70+
}
71+
}
72+
```
73+
74+
问题:`pgbackrest` 不需要 PostgreSQL connection context,提前解析会读取当前目录 `.env`,导致应用配置文件污染物理备份命令。
75+
76+
#### Correct
77+
78+
```powershell
79+
switch ($CommandName) {
80+
'backup' {
81+
$context = Resolve-PgContext -CliOptions $options
82+
$spec = New-PgBackupCommandSpec -CliOptions $options -Context $context
83+
}
84+
'pgbackrest' {
85+
$spec = New-PgBackRestCommandSpec -CliOptions $options
86+
}
87+
}
88+
```
89+
90+
理由:每个子命令只读取自己需要的配置来源,降低跨命令副作用。
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# pgBackRest 配置示例与维护脚本
2+
3+
## Goal
4+
5+
`config/database/backup/pgBackRest/` 下补充 pgBackRest 配置示例、中文文档与维护脚本,服务于 `postgresql://postgres:12345678@macmini:5432/lobechat` 对应 PostgreSQL 实例的整实例备份,并明确“某数据库某表”应采用 `pg_dump` 逻辑备份的最佳实践。
6+
7+
## What I Already Know
8+
9+
- 用户要求目标目录为 `config/database/backup/pgBackRest`
10+
- 用户要求配置文件使用 `.local` 结尾。
11+
- 用户提供的数据库连接串为 `postgresql://postgres:12345678@macmini:5432/lobechat`
12+
- 用户希望维护脚本能在任意机器执行;macmini 当前可通过 Tailscale IP/地址访问。
13+
- 需求包含 pgBackRest 配置示例、文档、整库备份、某数据库某表备份最佳实践、维护脚本。
14+
- 仓库中已有 `config/database/backup/pgBackRest/` 目录,目前为空。
15+
- 仓库已有 PostgreSQL 逻辑备份工具与文档:`scripts/pwsh/devops/Postgres-Toolkit.ps1``docs/cheatsheet/database/postgresql/backup-restore.md`
16+
- pgBackRest 是实例/集群级物理备份工具;表级备份最佳实践应使用 `pg_dump -t`
17+
- `pg_dump` 不提供真正的增量备份;如果要增量,应使用 pgBackRest 的整实例 full/diff/incr 备份链。
18+
- 仓库已有 `scripts/pwsh/devops/postgresql` 备份脚本,应在现有 toolkit 上扩展,而不是另起一套 Bash 维护入口。
19+
20+
## Assumptions (temporary)
21+
22+
- `.local` 配置用于本机真实环境,不应提交可泄露密码的真实文件;仓库可提交 `.example` 或无敏感值模板。
23+
- 维护脚本优先复用 `scripts/pwsh/devops/postgresql`,保持 `Postgres-Toolkit.ps1` 为统一入口。
24+
- 目标 PostgreSQL 主机名 `macmini` 或其 Tailscale IP 可被执行脚本的机器访问。
25+
- `lobechat` 是需要逻辑表级备份的默认数据库名;pgBackRest 整实例备份仍以 PostgreSQL data directory 为范围。
26+
- pgBackRest 整实例远程备份默认采用 Tailscale + SSH 模式;若用户明确要避免 SSH,再考虑 pgBackRest TLS server。
27+
28+
## Open Questions
29+
30+
- 备份仓库应默认存放在执行脚本的当前机器,还是固定存放到某个共享/NAS/服务器路径?
31+
32+
## Requirements (evolving)
33+
34+
-`config/database/backup/pgBackRest/` 下提供 pgBackRest 配置示例和中文 README。
35+
- 提供 `.local` 结尾的本机配置入口或模板,满足用户命名偏好。
36+
- 支持在任意能通过 Tailscale 访问 macmini 的机器上运行维护脚本。
37+
- 文档说明 pgBackRest 整实例备份、WAL 归档、保留策略、初始化与日常维护命令。
38+
- 文档说明 pgBackRest 远程备份不是仅依赖 PostgreSQL 连接串:需要 macmini 上安装 pgBackRest,并通过 SSH 或 TLS 让执行机访问数据库主机的 data directory/WAL 配置。
39+
- 文档说明“备份某数据库某表”使用 `pg_dump -t` / `pg_restore -t`,并给出 `lobechat` 示例。
40+
- 文档说明 `pg_dump` 是逻辑快照而非增量备份;需要增量时使用 pgBackRest full/diff/incr 整实例链路。
41+
- 扩展现有 `Postgres-Toolkit.ps1`,至少覆盖 pgBackRest 检查、创建 stanza、全量备份、差异/增量备份、查看状态、过期清理;表级逻辑备份继续由现有 `backup --table` 承担。
42+
- 避免将真实密码提交到仓库;需要提供本地 secret 文件或环境变量方案。
43+
44+
## Acceptance Criteria (evolving)
45+
46+
- [ ] `config/database/backup/pgBackRest/` 包含可读的中文 README,能解释 pgBackRest 与 pg_dump 的职责边界。
47+
- [ ] 示例配置包含 `macmini``lobechat` 场景所需字段,并避免提交真实密码。
48+
- [ ] 示例配置体现 Tailscale 网络访问场景,允许将 `macmini` 替换为 Tailscale IP。
49+
- [ ] `Postgres-Toolkit.ps1` 支持 pgBackRest dry-run 或等价的命令预览能力,降低误操作风险。
50+
- [ ] 表级备份示例能指定 schema/table,并默认指向 `lobechat`
51+
- [ ] README 明确说明 pg_dump 无通用增量备份,避免用户误以为单表可通过 pg_dump 做增量。
52+
- [ ] 文档包含首次初始化、执行备份、查看备份、恢复注意事项的步骤。
53+
54+
## Definition of Done
55+
56+
- 新增/更新的脚本具备中文注释,函数包含参数和返回值说明。
57+
- 配置文件不需要单元测试。
58+
- 代码改动完成后执行根目录 `pnpm qa`;若维护脚本属于 pwsh 范围则额外执行 `pnpm test:pwsh:all`
59+
- 文档明确说明敏感信息处理、恢复前验证和 pgBackRest 与 pg_dump 的适用边界。
60+
61+
## Out of Scope
62+
63+
- 不改造现有 `Postgres-Toolkit.ps1` 的核心实现,除非后续确认必须复用。
64+
- 不自动修改远程 PostgreSQL `postgresql.conf` / `pg_hba.conf`
65+
- 不提交真实生产密码或真实 `.local` secret 文件。
66+
- 不实现完整 PITR 自动恢复流程;先提供恢复说明和必要命令入口。
67+
68+
## Research References
69+
70+
- [`research/pgbackrest-backup-practices.md`](research/pgbackrest-backup-practices.md) — pgBackRest 适合整实例物理备份,表级备份应使用 `pg_dump -t`
71+
72+
## Research Notes
73+
74+
### Feasible approaches here
75+
76+
**Approach A: 扩展现有 Postgres Toolkit(推荐)**
77+
78+
- How it works: 在 `scripts/pwsh/devops/postgresql` 增加 `pgbackrest` 子命令;`backup` 继续封装 `pg_dump` 做逻辑库/表快照;`config/database/backup/pgBackRest` 只放配置模板和中文文档。
79+
- Pros: 复用已有连接串、env-file、dry-run、测试和构建体系,避免两套维护脚本分叉。
80+
- Cons: 远端 Linux/macOS 环境需要安装 PowerShell,或使用已构建的 `Postgres-Toolkit.ps1`
81+
82+
**Approach B: 任意 Tailscale 可达机器远程执行 pgBackRest**
83+
84+
- How it works: 在执行机放 repo,使用 `pg1-host=macmini` 或 Tailscale IP 远程调用数据库主机上的 pgBackRest;表级逻辑备份直接通过 PostgreSQL TCP 连接 `lobechat`
85+
- Pros: 符合用户“任意机器执行”的目标,备份仓库可与数据库主机隔离,Tailscale 已提供网络可达性。
86+
- Cons: macmini 上仍需要安装 pgBackRest 并配置 SSH 或 pgBackRest TLS server;执行机之间若各自保存 repo,需要额外注意备份分散问题。
87+
88+
**Approach C: 仅文档化 pgBackRest,表级备份完全交给现有 Postgres-Toolkit**
89+
90+
- How it works: pgBackRest 目录只放配置和 README;表级备份引导用户运行现有 PowerShell toolkit。
91+
- Pros: 复用已有工具,新增脚本少。
92+
- Cons: 不能完全满足“提供维护脚本”的直觉预期,Linux/macmini 上使用 PowerShell 可能不如 Bash 直接。
93+
94+
## Technical Notes
95+
96+
- Context7 查询库:`/websites/pgbackrest_configuration`
97+
- Context7 文档确认:`pg1-host` 用于远程 PostgreSQL 主机;`pg1-host-type` 支持 `ssh``tls`,默认 `ssh`
98+
- 已读本地文件:
99+
- `.gitignore`
100+
- `docs/cheatsheet/database/postgresql/backup-restore.md`
101+
- `scripts/pwsh/devops/postgresql/README.md`
102+
- `scripts/pwsh/devops/postgresql/docs/help.md`
103+
- `ai/self-hosted/lobehub/docs/postgres-docker-usage.md`
104+
- `ai/self-hosted/lobehub/.env.example`
105+
- 当前 git 工作区已有用户/任务改动:`.gitignore` 修改、`.trellis/tasks/05-14-pgbackrest-config-docs/` 未跟踪。
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# pgBackRest 配置与备份范围研究
2+
3+
## 结论摘要
4+
5+
- pgBackRest 的核心模型是 PostgreSQL 集群/实例级物理备份:通过 stanza 绑定一个 PostgreSQL data directory 与备份仓库,适合整库灾备、WAL 归档和 PITR。
6+
- `pg1-host``pg1-path``repo1-path``repo1-retention-full` 等是配置示例的关键字段;远程备份时需要在数据库主机与备份主机上都能执行 `pgbackrest`
7+
- pgBackRest 不适合作为“只备份某个数据库某张表”的主工具;表级备份/恢复应使用 `pg_dump -t` / `pg_restore -t`,仓库已有 `docs/cheatsheet/database/postgresql/backup-restore.md``Postgres-Toolkit.ps1` 覆盖这个方向。
8+
- 用户提供的连接串 `postgresql://postgres:12345678@macmini:5432/lobechat` 可用于逻辑表级脚本,但 pgBackRest 仍需要数据库服务器上的 `pg1-path`、WAL archive 配置和 pgBackRest stanza 初始化。
9+
- 用户希望在任意能通过 Tailscale 访问 macmini 的机器执行备份。表级逻辑备份只需要 PostgreSQL TCP 可达;pgBackRest 整实例物理备份还需要通过 `pg1-host` 连接 macmini,并配置 `pg1-host-type=ssh``pg1-host-type=tls` 让执行机调用数据库主机上的 pgBackRest。
10+
- `pg_dump` 不提供真正的增量备份语义,它每次输出的是当前逻辑快照;真正的增量链路应使用 pgBackRest 或 PostgreSQL 18+ 的 `pg_basebackup --incremental`。后者仍然是整个 cluster 级别,不能只备份单表。
11+
12+
## 官方文档依据
13+
14+
- Context7 `/websites/pgbackrest_configuration``pg1-host` 用于远程 PostgreSQL 主机;`pg1-database` 只指定 pgBackRest 连接 PostgreSQL 时使用的数据库,默认通常是 `postgres`,不是“只备份该数据库”的范围过滤。
15+
- Context7 `/websites/pgbackrest_configuration``pg1-host-type` 支持 `ssh``tls` 两种协议类型,默认是 `ssh`;这意味着通过 Tailscale 网络远程运行 pgBackRest 是可行的,但数据库主机仍需安装并允许远程调用 pgBackRest。
16+
- Context7 `/websites/pgbackrest_configuration``repo1-path` 指定备份仓库路径;`repo1-retention-full``repo1-retention-full-type``repo1-retention-diff``repo1-retention-history` 控制保留策略。
17+
- PostgreSQL 官方 `pg_dump` 文档:表级备份使用 `-t/--table=PATTERN`,更适合单库、单 schema、单表这类逻辑范围备份。
18+
- PostgreSQL 官方 `pg_basebackup` 文档:增量 base backup 属于整个 database cluster 级别,不能备份单个数据库或对象;选择性备份仍应使用 `pg_dump`
19+
20+
## 映射到本仓库
21+
22+
- 目标目录已经存在:`config/database/backup/pgBackRest/`
23+
- 仓库已有 PostgreSQL 逻辑备份资料:
24+
- `docs/cheatsheet/database/postgresql/backup-restore.md`
25+
- `scripts/pwsh/devops/Postgres-Toolkit.ps1`
26+
- `scripts/pwsh/devops/postgresql/**`
27+
- 因仓库已经有 `scripts/pwsh/devops/postgresql` 维护脚本,新增能力应优先扩展该 toolkit,而不是在 `config/database/backup/pgBackRest/` 下再创建一套 Bash 入口。
28+
- LobeChat 相关文档确认本地常用数据库为 `lobechat`,用户这次明确要求连接 `macmini:5432/lobechat`
29+
- `.gitignore` 已忽略 `.env``.env.local``*.env.local``*.local.json`,但没有覆盖 `*.local.conf`;如果产出 `.local.conf` 且包含密码,应同时更新忽略规则或让 `.local.conf` 不含敏感值。
30+
31+
## 推荐方向
32+
33+
1.`config/database/backup/pgBackRest/` 下提供可提交的示例配置与中文说明。
34+
2.`.local` 后缀存放本机真实配置入口,但不要提交真实密码;如果必须生成含密码文件,应确保 git 忽略。
35+
3. 维护脚本入口统一放在 `scripts/pwsh/devops/postgresql` / `Postgres-Toolkit.ps1`
36+
- `backup` 继续封装 `pg_dump`,负责单库、schema、表级逻辑快照。
37+
- 新增 `pgbackrest` 命令封装整实例物理备份维护:基于远程 `pg1-host=macmini`,支持 `check``stanza-create``backup full/diff/incr``info``expire`
38+
4. 默认推荐 Tailscale + SSH 模式:网络层由 Tailscale 提供可达性和访问控制,pgBackRest 远程协议用 SSH,避免额外维护 pgBackRest TLS server 证书。
39+
5. 文档必须清楚说明:pgBackRest 负责整实例/PITR/增量,pg_dump 负责逻辑快照,单表没有通用“pg_dump 增量备份”。
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"id": "pgbackrest-config-docs",
3+
"name": "pgbackrest-config-docs",
4+
"title": "brainstorm: pgBackRest 配置示例与维护脚本",
5+
"description": "",
6+
"status": "in_progress",
7+
"dev_type": null,
8+
"scope": null,
9+
"package": null,
10+
"priority": "P2",
11+
"creator": "mudssky",
12+
"assignee": "mudssky",
13+
"createdAt": "2026-05-14",
14+
"completedAt": null,
15+
"branch": null,
16+
"base_branch": "master",
17+
"worktree_path": null,
18+
"commit": null,
19+
"pr_url": null,
20+
"subtasks": [],
21+
"children": [],
22+
"parent": null,
23+
"relatedFiles": [],
24+
"notes": "",
25+
"meta": {}
26+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# 本目录的 .local 文件保存真实主机、路径或密码,不进入 Git。
2+
*.local
3+
*.local.conf
4+
*.env.local
5+
pgbackrest.conf.local
6+
pgbackrest.env.local
7+
pgpass.local
8+
9+
# 备份产物通常体积较大,按本机运行态处理。
10+
backups/
11+
table-dumps/
12+
logs/
13+
*.dump
14+
*.backup
15+
*.sql

0 commit comments

Comments
 (0)