বিষয়বস্তুলৈ যাওক

Backup, point-in-time recovery আৰু restore drill

Docker Compose-ৰে Quire backup কৰক, সময়লৈ restore কৰক আৰু recovery অভ্যাস কৰক।

Markdown হিচাপে চাওক

ডিজাইন docs/architecture/23-ops.mdৰ section 8-ত। Docker Compose product-ৰ বাবে এই runbook। ইয়াক অনুসৰণ কৰা ব্যক্তিজনে লিখা নাছিল বুলি ধৰি লিখা হৈছে; কোনো step অস্পষ্ট হ’লে এই নথিৰ দোষ।

কি সুৰক্ষিত, আৰু কেনেকৈ

Asset কেনেকৈ ক’ত
Database প্ৰথম boot-ৰ পৰা অবিৰতভাৱে, সৰ্বাধিক প্ৰতি 60 ছেকেণ্ডত WAL archive pgwal volume
Database pg_basebackupৰে base backup, ডিফল্টভাৱে দৈনিক (backup-scheduler) pgbackup volume
Database Base backup আৰু WAL-ৰ encrypted copy, প্ৰতি পাঁচ মিনিটত (backup-offsite) আপোনাৰ নাম দিয়া পৃথক store
File files volume। Host backup tool-ৰে copy কৰক অথবা version থকা object storage ব্যৱহাৰ কৰক files volume
Secret docker/.env, বিশেষকৈ QUIRE_MASTER_KEY (আৰু এতিয়াও ব্যৱহৃত QUIRE_MASTER_KEY_RETIRED), QUIRE_BACKUP_ENCRYPTION_KEY, আৰু docker/secrets/audit-signing-key.pem এই host-ৰ বাহিৰত copy ৰাখক
Search index, cache, rendition Backup নহয়; পুনৰ নিৰ্মাণ কৰা হয়

লক্ষ্য: বিফলতাৰ 60 ছেকেণ্ডৰ ভিতৰত recovery point, আৰু 500 GB database-ৰ বাবে 60 মিনিটৰ ভিতৰত restore।

দুটা ভুল সাধাৰণ। File অবিহনে restore কৰা database-এ ভঙা page দেখুৱায়। QUIRE_MASTER_KEY অবিহনে restore কৰা database-এ ইয়াৰ SSO, webhook আৰু integration credential decrypt কৰিব নোৱাৰে; একো unresolved নথকাকৈ master key rotation সম্পূৰ্ণ নোহোৱালৈ (key-rotation.md), ইয়াত retired key-ও অন্তৰ্ভুক্ত। দুয়োটাই backup-ৰ অংশ।

Backup লওক

সম্পূৰ্ণ cluster-ৰ base backup:

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

ই আটাইতকৈ নতুন QUIRE_BACKUP_KEEPটা base backup ৰাখে (ডিফল্ট 5) আৰু আটাইতকৈ পুৰণিটোৱে আৰু নলগা WAL prune কৰে, যাতে archive সীমাহীনভাৱে নাবাঢ়ে। Host-ত cron বা systemd timer-ৰে দৈনিক schedule কৰক:

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

অথবা stack-ক schedule কৰিবলৈ দিয়ক: backup profile-এ backup-scheduler চলায়, যিয়ে প্ৰতিটো QUIRE_BACKUP_INTERVAL_HOURS ঘণ্টাত base backup লয় (ডিফল্ট 24), আৰু তলত বৰ্ণনা কৰা backup-offsite-ও চলে।

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

Host-ৰ বাহিৰত encrypted copy

দুয়োটা volume database-ৰ সৈতে একে host-ত থাকে; বিফল হোৱা machine-ত থকা backup backup নহয়। backup-offsite-এ প্ৰতিটো base backup আৰু archived WAL segment পৃথক store-লৈ storage port-ৰে encrypted copy কৰে আৰু retention নিয়মত ৰাখে:

  • Encryption. QUIRE_BACKUP_ENCRYPTION_KEY (অথবা QUIRE_BACKUP_ENCRYPTION_KEY_FILE-এ নাম দিয়া file)-সহ AES-256-GCM: openssl rand -hex 32ৰে সৃষ্টি কৰা 32 byte। প্ৰতিটো file-ৰ নিজা nonce আৰু authentication tag থাকে, সেয়ে key অবিহনে copy পঢ়িব নোৱাৰি আৰু পৰিৱৰ্তন হ’লে ধৰা পৰে। Key-টো QUIRE_MASTER_KEYৰ সৈতে, এই host আৰু backup store-ৰ পৰা আঁতৰত ৰাখক। Key নাথাকিলে restore নহয়।
  • ক’ত. QUIRE_BACKUP_STORAGE_DRIVER হৈছে s3, azure অথবা local (QUIRE_BACKUP_STORAGE_ROOTত mount কৰা remote disk)। Setting-সমূহ file storage-ৰেই QUIRE_BACKUP_ prefix-সহ: QUIRE_BACKUP_S3_ENDPOINT, QUIRE_BACKUP_S3_BUCKET, QUIRE_BACKUP_S3_ACCESS_KEY_ID আদি। File-ৰ পৰা বেলেগ bucket, ভাল হ’লে বেলেগ account ব্যৱহাৰ কৰি provider-এ অনুমতি দিলে লিখিব পৰা কিন্তু delete কৰিব নোৱাৰা credential দিয়ক।
  • Retention. আটাইতকৈ নতুন QUIRE_BACKUP_OFFSITE_KEEPটা base backup (ডিফল্ট QUIRE_BACKUP_KEEP, নহ’লে 7) আৰু আটাইতকৈ পুৰণিটোক লগা WAL; পুৰণি set আৰু segment store-ৰ পৰা delete হয়।
  • কেতিয়া. প্ৰতিটো QUIRE_BACKUP_SHIP_INTERVAL_SECONDS ছেকেণ্ডত (ডিফল্ট 300)। Shipping idempotent: আগতে store হোৱা বস্তু skip হয়; manifest শেষত লিখাৰ পিছতহে base backup store হোৱা বুলি গণ্য হয়।

হাতেৰে একে 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

নতুন host-ত restore কৰিবলৈ, আগতে এটা set ঘূৰাই আনি তাৰ পিছত তলৰ step অনুসৰণ কৰক; download কৰা directory-টো pgbackup volume-ৰ সলনি আৰু download কৰা wal-archiveটো pgwalৰ সলনি ব্যৱহাৰ কৰক:

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

সময়ৰ এটা বিন্দুলৈ restore

Data হেৰালে ব্যৱহাৰ কৰক: ভুল import, মচি পেলোৱা পাঠ্যক্ৰম, অথবা বাতিল কৰিবলগীয়া contract migration। ই live database সলনি কৰে, সেয়ে তলৰ drill-ৰে আগতে অভ্যাস কৰক।

  1. Target time বাছক, UTC-ত ক্ষতিৰ ঠিক আগৰ সময়: 2026-09-24 09:30:00+00। Audit log (/admin/audit)-এ সাধাৰণতে সেই মুহূৰ্ত দেখুৱায়।
  2. লিখা কৰা সকলো বন্ধ কৰক: docker compose -f docker/compose.yaml stop web content worker scheduler collab
  3. Restore পৰীক্ষা নোহোৱালৈ ক্ষতিগ্ৰস্ত cluster ৰাখক:
    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. Target-তকৈ পুৰণি আটাইতকৈ নতুন base backup data volume-ত unpack কৰি 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. Recover: স্বাভাৱিক file নসলনি কৰিবলৈ Compose override-ৰ পৰা recovery setting-সহ এবাৰ Postgres আৰম্ভ কৰক:
    # 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]
    Override-এ সম্পূৰ্ণ command সলনি কৰে, সেয়ে recovery-ৰ প্ৰয়োজনীয় দুটা setting পুনৰ দিয়ে: max_connections primary-তকৈ কম নহ’ব (নহ’লে recovery “insufficient parameter settings”ৰে বন্ধ হয়) আৰু mount কৰা 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. মানুহক সোমাবলৈ দিয়াৰ আগতে পৰীক্ষা কৰক: audit chain (docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts) আৰু হেৰোৱা data ঘূৰি আহিছে নে।
  7. স্বাভাৱিক অৱস্থালৈ ঘূৰক: docker compose -f docker/compose.yaml up -d। ই archiving অন কৰি Postgres পুনৰ আৰম্ভ কৰে আৰু নতুন WAL timeline আৰম্ভ হয়। লগে লগে নতুন base backup লওক।

Project name quire প্ৰতিটো volume-ৰ আগত যোগ হয়; docker volume ls-এ হুবহু নাম দেখুৱায়।

Schedule কৰা verification drill

backup-offsite-এ প্ৰতিটো QUIRE_BACKUP_DRILL_INTERVAL_HOURS ঘণ্টাত (ডিফল্ট 168, সাপ্তাহিক) আৰু বিফলতাৰ পিছৰ পৰৱৰ্তী pass-ত drill চলায়। ই host-ৰ বাহিৰৰ নতুনতম base backup আৰু তাৰ পিছৰ প্ৰতিটো WAL segment fetch কৰি decrypt কৰে (key-এ এতিয়াও খুলিব পাৰে আৰু একো সলনি হোৱা নাই প্ৰমাণ হয়), প্ৰতিটো file manifest-ৰ সৈতে তুলনা কৰে, archive Postgres data directory নে পৰীক্ষা কৰে আৰু backup-ৰ পিছৰ WAL-ত gap নাই বুলি নিশ্চিত কৰে। Report-টো reports/drill-<time>.json হিচাপে store আৰু service log-ত লিখা হয়; বিফল drill-এ file বা প্ৰথম missing segment-ৰ নাম কয়।

Restore drill

কেতিয়াও restore নকৰা backup, backup নহয়। Drill-এ target-ৰ আগতে লোৱা নতুনতম সম্পূৰ্ণ base backup আৰু WAL archive live-ৰ পৰা একো share নকৰা scratch Postgres-ত restore কৰি ফল প্ৰমাণ কৰে:

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

Target হুবহু এই format-ৰ UTC সময়। ইয়াৰ আগৰ এটা base backup আৰু তাৰ পিছৰ archived WAL লাগে: নতুন install-ত base backup লৈ পৰৱৰ্তী archive segment আহিবলৈ (write থাকিলে সৰ্বাধিক এক মিনিট) অপেক্ষা কৰি তাৰ পিছৰ target বাছক। Host-ত Docker আৰু bash-হে লাগে।

প্ৰতিটো step-এ drill fail কৰে:

  1. Recoverability: scratch cluster-এ target-লৈ replay কৰি খোলে।
  2. Completeness: live database-ৰ বিপৰীতে প্ৰতিটো table-ৰ row count (tooling/restore-drill)। Live database target-ৰ পিছত আগবাঢ়িছে; সেয়ে যিকোনো দিশত table-ৰ পাৰ্থক্য 500 row বা size-ৰ এক-দশমাংশৰ ভিতৰত যিটো ডাঙৰ সেইখিনি হ’ব পাৰে (write-এ restore পিছত ৰাখে, deletion-এ restore-ত বেছি ৰাখে); target-ৰ পিছত সৃষ্টি হোৱা partition হেৰোৱা table নহয়। অধিক ব্যস্ত install-ত QUIRE_DRILL_MAX_BEHIND আৰু QUIRE_DRILL_MAX_DRIFT_RATIOৰে allowance বঢ়াওক। Missing বা খালী table-এ fail কৰে।
  3. Integrity: restored copy-ত audit hash chain verify হয়।
  4. ব্যৱহাৰযোগ্যতা: application role-এ row-level security-ৰে পঢ়ে।
  5. সময়: আৰম্ভণিৰ পৰা সফল হোৱালৈ QUIRE_DRILL_RTO_SECONDSৰ বিপৰীতে (ডিফল্ট 3600)।

ই live database বা volume-ত কেতিয়াও লিখা নকৰে: backup আৰু WAL volume read-only mount হয় আৰু pass বা fail যিয়েই হওক শেষত scratch cluster আঁতৰোৱা হয়।

JSON report (pass বা fail) লিখিবলৈ QUIRE_DRILL_REPORTক path দিয়ক আৰু Docker host-ৰ পৰা schedule কৰক:

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

মাহে এবাৰ আৰু প্ৰতিটো upgrade-ৰ আগতে চলাওক। বিফল drill-এ upgrade বন্ধ কৰে। প্ৰতি quarter-ত এই runbook নিলিখা কোনোবাক কেৱল এই নথি ব্যৱহাৰ কৰি spare host-ত প্ৰকৃত point-in-time restore কৰিবলৈ দিয়ক।

File

Local file files volume-ত থাকে। Database-ৰ সৈতে একে সময়তে backup লৈ দুয়ো একেলগে restore কৰক:

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 .

Object storage-ত bucket versioning অন কৰি 35 দিনৰ noncurrent version ৰাখক; তেতিয়া file-ৰ point-in-time recovery bucket-ৰ নিজা কাম।

নেভিগেচন

বিচাৰিবলৈ লিখক…

↑↓ নেভিগেট কৰক↵ বাছকEsc বন্ধ কৰক