Laktawi ngadto sa sulod

Backup, point-in-time recovery ug restore drill

I-backup ang Quire, i-restore kini sa usa ka takna, ug pamatud-i pinaagi sa restore drill.

Tan-awa isip Markdown

Gihulagway ang disenyo sa seksiyon 8 sa docs/architecture/23-ops.md. Mao kini ang runbook para sa produkto sa Docker Compose. Gisulat kini aron masunod sa tawo nga wala mosulat niini; depekto sa dokumento kon dili klaro ang usa ka lakang.

Unsay gipanalipdan ug giunsa

Asset Paagi Asa
Database Padayon nga i-archive ang WAL, labing menos matag 60 segundos, sukad sa unang pagsugod pgwal volume
Database Base backup gamit ang pg_basebackup, kasagaran kada adlaw (backup-scheduler) pgbackup volume
Database Naka-encrypt nga kopya sa base backup ug WAL matag lima ka minuto (backup-offsite) Bulag nga store nga imong ginganlan
Files Ang files volume. Kopyaha kini gamit ang backup tool sa host, o gamita ang object storage nga adunay versioning files volume
Mga sekreto docker/.env, ilabi na ang QUIRE_MASTER_KEY (ug bisan unsang QUIRE_MASTER_KEY_RETIRED nga gigamit pa), QUIRE_BACKUP_ENCRYPTION_KEY, ug docker/secrets/audit-signing-key.pem Tipigi ang kopya sa gawas niini nga host
Search index, cache, rendition Dili i-backup; tukora pag-usab

Target: recovery point nga sulod sa 60 segundos sa kapakyasan, ug restore sulod sa 60 minutos para sa database nga 500 GB.

Dunay duha ka kasagarang sayop. Makapakita og guba nga panid ang database nga gi-restore nga walay file. Dili ma-decrypt sa database nga gi-restore nga walay QUIRE_MASTER_KEY ang SSO, webhook ug integration credential niini; hangtod mahuman ang pagtuyok sa master key nga walay wala masulbad (key-rotation.md), apil niini ang mga retired key. Kinahanglan i-backup kining tanan.

Paghimo og backup

Base backup sa tibuok cluster:

docker compose -f docker/compose.yaml --profile backup run --rm backup

Tipigan niini ang pinakabag-ong QUIRE_BACKUP_KEEP ka base backup (default 5) ug papason ang WAL nga dili na gikinahanglan sa labing karaan niini, busa dili motubo hangtod walay kinutoban ang archive. Eskedyulahi kada adlaw gamit ang cron o systemd timer sa host:

15 2 * * * cd /srv/quire && docker compose -f docker/compose.yaml --profile backup run --rm backup >> /var/log/quire-backup.log 2>&1

O ipaiiskedyul kini sa stack pinaagi sa backup profile: magpadagan kini sa backup-scheduler, nga maghimo og base backup matag QUIRE_BACKUP_INTERVAL_HOURS (default 24), ug sa backup-offsite nga gihulagway sa sunod.

docker compose -f docker/compose.yaml --profile backup up -d

Naka-encrypt nga kopya sa gawas sa host

Ania sa samang host sa database ang duha ka volume, ug dili backup ang kopya anaa sa mismong makinang napakyas. Kopyahon sa backup-offsite ang matag base backup ug matag gi-archive nga WAL segment ngadto sa bulag nga store pinaagi sa storage port, i-encrypt kini, ug tipigan didto sumala sa retention:

  • Encryption. AES-256-GCM gamit ang QUIRE_BACKUP_ENCRYPTION_KEY (o ang file nga ginganlan sa QUIRE_BACKUP_ENCRYPTION_KEY_FILE): 32 bytes, gikan sa openssl rand -hex 32. Adunay kaugalingong nonce ug authentication tag ang matag file, busa dili mabasa ang kopya kon walay yawe ug mamatikdan ang kausaban niini. Tipigi ang yawe uban sa QUIRE_MASTER_KEY, palayo sa host ug backup store. Dili mahimo ang restore kon walay yawe.
  • Asa tipigan. Ang QUIRE_BACKUP_STORAGE_DRIVER mahimong s3, azure o local (gitaod nga remote disk sa QUIRE_BACKUP_STORAGE_ROOT). Parehas kini sa mga setting sa file storage apan gisugdan sa QUIRE_BACKUP_: QUIRE_BACKUP_S3_ENDPOINT, QUIRE_BACKUP_S3_BUCKET, QUIRE_BACKUP_S3_ACCESS_KEY_ID ug uban pa. Gamita ang bucket nga lahi sa para sa file ug, kon mahimo, lahi nga account; gamita ang credential nga makasulat apan dili makapapas kon itugot sa provider.
  • Retention. Tipigan ang pinakabag-ong QUIRE_BACKUP_OFFSITE_KEEP ka base backup (default nga QUIRE_BACKUP_KEEP, kon wala 7) ug WAL nga gikinahanglan sa labing karaan niini; papason sa store ang mas karaang set ug segment.
  • Kanus-a. Kada QUIRE_BACKUP_SHIP_INTERVAL_SECONDS (default 300). Idempotent ang pagpadala: laktawan ang anaa na sa store, ug maisip nga natipig lang ang base backup kon mahuman na ang manifest niini ug kini ang kataposang isulat.

Mano-mano usab nga modagan ang samang command:

docker compose -f docker/compose.yaml run --rm backup-offsite bun apps/worker/src/backups/main.ts ship
docker compose -f docker/compose.yaml run --rm backup-offsite bun apps/worker/src/backups/main.ts verify

Aron i-restore sa bag-ong host, kuhaa una ang set, unya sundon ang mga lakang sa ubos ug gamiton ang directory nga nakuha puli sa pgbackup volume ug ang wal-archive nga nakuha puli sa pgwal:

bun apps/worker/src/backups/main.ts fetch base-20260924T021500Z /srv/restore

Pag-restore sa takna

Gamita kini human mawala ang datos: sayop nga import, natangtang nga kurso, o contract migration nga kinahanglan bawi-on. Pulihan niini ang live nga database, busa suwayi una kini pinaagi sa drill sa ubos.

  1. Pilia ang takna nga adtoan, sa UTC, sa dili pa ang kadaot: 2026-09-24 09:30:00+00. Kasagaran ipakita sa audit log (/admin/audit) ang takna.
  2. Hunonga ang tanang nagsulat: docker compose -f docker/compose.yaml stop web content worker scheduler collab
  3. Tipigi ang nadaot nga cluster hangtod mapamatud-an ang restore:
    docker compose -f docker/compose.yaml stop postgres
    docker run --rm -v quire_postgres18-data:/from -v quire_postgres-damaged:/to alpine cp -a /from/. /to/
  4. Ablihi ang pinakabag-ong base backup nga nauna sa target ngadto sa data volume, ug hangyoa ang targeted recovery:
    docker run --rm -v quire_pgbackup:/backups:ro -v quire_postgres18-data:/var/lib/postgresql postgres:18-alpine sh -euc '
      base="$(ls -1d /backups/base-* | sort | tail -n 1)"   # or the one before the target
      rm -rf /var/lib/postgresql/18/docker && mkdir -p /var/lib/postgresql/18/docker
      tar -xzf "$base/base.tar.gz" -C /var/lib/postgresql/18/docker
      touch /var/lib/postgresql/18/docker/recovery.signal
      chown -R postgres:postgres /var/lib/postgresql/18/docker && chmod 700 /var/lib/postgresql/18/docker'
  5. Bawi-a ang datos: sugdi makausa ang Postgres gamit ang recovery setting, pinaagi sa Compose override aron dili mausab ang naandan nga file:
    # docker/compose.recover.yaml
    services:
      postgres:
        command: [postgres, -c, "restore_command=cp /var/lib/postgresql/wal-archive/%f %p",
                  -c, "recovery_target_time=2026-09-24 09:30:00+00",
                  -c, recovery_target_action=promote, -c, archive_mode=off,
                  -c, max_connections=200, -c, hba_file=/etc/postgresql/pg_hba.conf]
    Pulihan sa override ang tibuok command, busa gisubli niini ang duha ka setting nga gisaligan sa recovery: max_connections nga dili moubos sa primary (kay mohunong ang recovery nga adunay “insufficient parameter settings” kon ubos niini) ug ang naka-mount nga pg_hba.conf.
    docker compose -f docker/compose.yaml -f docker/compose.recover.yaml up -d postgres
    docker compose -f docker/compose.yaml logs -f postgres   # wait for "database system is ready"
  6. Susiha kini sa dili pa pasudlon ang bisan kinsa: ang audit chain (docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts), ug pamatud-i nga mibalik ang nawalang datos.
  7. Balik sa naandan: docker compose -f docker/compose.yaml up -d. I-restart niini ang Postgres nga naka-on ang archiving, ug magsugod ang bag-ong WAL timeline. Paghimo dayon og bag-ong base backup.

Idugang ang quire sa sinugdanan sa ngalan sa matag volume; ipakita sa docker volume ls ang eksaktong ngalan.

Nakaiskedyul nga verification drill

Magpadagan usab ang backup-offsite og drill matag QUIRE_BACKUP_DRILL_INTERVAL_HOURS (default 168, kada semana), ug usab sa sunod nga higayon human mapakyas ang usa. Kuhaon niini ang pinakabag-ong base backup gikan sa gawas sa host ug matag WAL segment pagkahuman niini, i-decrypt ang matag usa (pamatud-an niini nga maablihan gihapon sa yawe ug walay nabag-o), itandi ang matag file sa manifest niini, susihon nga Postgres data directory ang archive, ug pamatud-an nga walay putol ang WAL gikan sa backup padayon. Isulat ang report sa store isip reports/drill-<time>.json ug sa log sa serbisyo; nganlan sa napakyas nga drill ang file o unang nawalang segment.

Restore drill

Dili backup ang backup nga wala pa ma-restore. I-restore sa drill ang pinakabag-ong kompleto nga base backup nga gihimo sa wala pa ang target, uban sa WAL archive, ngadto sa scratch Postgres nga walay gipaambit sa live database, ug pamatud-an ang resulta:

docker/scripts/restore-drill.sh                                  # to ninety minutes ago
docker/scripts/restore-drill.sh --target "2026-09-24 09:30:00+00"

Kinahanglan eksakto kana nga porma ang UTC target. Kinahanglan adunay base backup nga nauna niini ug gi-archive nga WAL nga miabot lapas niini: sa bag-ong install, paghimo og base backup ug hulata ang sunod nga segment sa archive (kutob usa ka minuto kon adunay pagsulat) sa dili pa mopili og target pagkahuman sa backup. Docker ug bash ra sa host ang gikinahanglan sa drill; wala nay lain.

Mapakyas ang drill sa matag lakang:

  1. Mahimong ma-recover: mabalik sa scratch cluster ang datos hangtod sa target ug maablihan kini.
  2. Pagkahingpit: itandi ang gidaghanon sa row sa matag table sa live database (tooling/restore-drill). Nakauswag na ang live database sukad sa target, busa mahimong magkalahi ang table hangtod sa mas dako sa 500 ka row o ikapulo sa gidak-on niini, sa bisan hain nga direksiyon (maulahi kini tungod sa mga write; mahimong mas daghan ang na-restore tungod sa mga deletion); dili mawala ang partition nga gibuhat human sa target. Dugangi ang gitugot nga kalainan sa mas busy nga instalasyon gamit ang QUIRE_DRILL_MAX_BEHIND ug QUIRE_DRILL_MAX_DRIFT_RATIO. Mapakyas kini kon nawala o nahaw-angan ang usa ka table.
  3. Kahusto: maverify ang audit hash chain sa gi-restore nga kopya.
  4. Magamit: makabasa ang application role ubos sa row-level security.
  5. Oras: sugod hangtod malampuson, itandi sa QUIRE_DRILL_RTO_SECONDS (default 3600).

Dili gayod kini mosulat sa live database o sa mga volume niini: read only ang pagkakabit sa backup ug WAL volume, ug tangtangon ang scratch cluster sa kataposan, molampos man o mapakyas.

Itakda ang QUIRE_DRILL_REPORT sa usa ka path aron isulat didto ang JSON report, molampos man o mapakyas, ug padagana kini sa iskedyul gikan sa Docker host:

30 3 1 * * cd /srv/quire && QUIRE_DRILL_REPORT=/var/log/quire-drill.json docker/scripts/restore-drill.sh >> /var/log/quire-drill.log 2>&1

Padagana kini kada bulan ug sa dili pa ang matag upgrade. Makababag sa upgrade ang napakyas nga drill. Kada quarter, papadagana ang tinuod nga point-in-time restore sa laing tawo nga wala mosulat niining runbook, sa host nga ekstra, ug kini nga dokumento ra ang gamiton niya.

Mga file

Anaa sa files volume ang lokal nga file. I-backup kini kauban sa database ug i-restore silang duha sa samang higayon:

docker run --rm -v quire_files:/files:ro -v "$PWD":/out alpine tar -czf /out/files-$(date -u +%Y%m%d).tar.gz -C /files .

Kon object storage ang gamiton, i-on ang bucket versioning ug tipigi sulod sa 35 ka adlaw ang mga daang bersiyon; mahimong paagi sa point-in-time recovery sa file ang bucket mismo.

Paglawig

Pag-type aron mangita…

↑↓ lihok↵ piliaEsc sirad-i