feat(deploy): continuous WAL archiving to S3 for point-in-time recovery #219
Reference in New Issue
Block a user
Delete Branch "feature/postgres-pitr-archiving"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Continuous WAL archiving with point-in-time recovery for the production database
(pgBackRest -> Selectel S3), so the money ledger and game state can be restored to any
moment. This is the primary recovery path; the migration-window
pg_dumpbecomes thesecondary belt-and-braces.
Shape
deploy/postgres/Dockerfile); postgresjoins the built + pushed image set.
a daily full base backup (systemd timer, Ansible
mainrole) + continuous WAL(
archive_command, a 5-minute forced switch bounds the recovery point).archive_modeand the base-backup timer are gated off by default(
PGBACKREST_ARCHIVE_MODE,pitr_enabled). Merging/redeploying does not startarchiving, so an un-armed deploy cannot fill the disk with WAL. The test contour never
archives (the prod overlay carries it all).
pg_stat_archiver(failing / stalled), absent/NaN-safe on the contour.pg_dumpnow snapshots the whole database (it was-n backend,silently excluding the
paymentsschema).deploy/README.md.Assessment (recorded, owner-reviewed gate)
Measured on prod: WAL ~0.77 MB/day, DB ~9.6 MB -> archive < 1 rub/month on S3; performance
impact negligible.
Owner follow-up — prod arming (separate, before real payments)
This PR lands the artifacts only (inert). To arm PITR in prod (steps in
deploy/README.md):create a Selectel S3 bucket (lowercase, no dots/underscores) + an S3 key/secret, choose a
repository cipher passphrase (store it apart from the S3 keys), and set the Gitea
PROD_set — variables
PROD_PGBACKREST_S3_ENDPOINT/_S3_BUCKET/_S3_REGION/_ARCHIVE_MODE=on; secretsPROD_PGBACKREST_S3_KEY/_S3_KEY_SECRET/_CIPHER_PASS.Then promote -> prod-deploy,
stanza-create+ first backup, re-run Ansible with-e pitr_enabled=true, and run the restore drill on an isolated one-shot target.Verification
docker compose configvalid (base + prod overlay); archive gating resolves to off unless armed.ansible-playbook --syntax-check site.ymlpasses.