सीधे सामग्री पर जाएँ

बैकअप, समय-बिंदु पुनर्प्राप्ति और पुनर्स्थापन अभ्यास

Quire का बैकअप लें, उसे समय-बिंदु पर पुनर्स्थापित करें और अभ्यास से इसकी पुष्टि करें।

Markdown के रूप में देखें

डिज़ाइन docs/architecture/23-ops.md के अनुभाग 8 में है। यह Docker Compose उत्पाद की रनबुक है। इसे ऐसे व्यक्ति के अनुसरण के लिए लिखा गया है जिसने इसे नहीं लिखा; यदि कोई चरण अस्पष्ट है, तो यह इस दस्तावेज़ की कमी है।

क्या सुरक्षित है और कैसे

संपत्ति तरीका स्थान
डेटाबेस पहले बूट से लगातार WAL संग्रहण, अधिकतम हर 60 सेकंड में pgwal वॉल्यूम
डेटाबेस pg_basebackup से बेस बैकअप, डिफ़ॉल्ट रूप से हर दिन (backup-scheduler) pgbackup वॉल्यूम
डेटाबेस बेस बैकअप और WAL की एन्क्रिप्टेड प्रतियाँ, हर पाँच मिनट (backup-offsite) आपके द्वारा चुना अलग संग्रह
फ़ाइलें files वॉल्यूम। इसे होस्ट के बैकअप टूल से कॉपी करें या संस्करणित ऑब्जेक्ट स्टोरेज इस्तेमाल करें files वॉल्यूम
सीक्रेट docker/.env, खासकर QUIRE_MASTER_KEY (और उपयोग में हो तो QUIRE_MASTER_KEY_RETIRED), QUIRE_BACKUP_ENCRYPTION_KEY, और docker/secrets/audit-signing-key.pem इस होस्ट से बाहर प्रति रखें
खोज इंडेक्स, कैश, रेंडर बैकअप नहीं होते; फिर बनाए जाते हैं

लक्ष्य: विफलता से 60 सेकंड के भीतर का पुनर्प्राप्ति बिंदु, और 500 GB डेटाबेस के लिए 60 मिनट के भीतर पुनर्स्थापन।

दो गलतियाँ आम हैं। फ़ाइलों के बिना पुनर्स्थापित डेटाबेस टूटे हुए पृष्ठ दिखाता है। QUIRE_MASTER_KEY के बिना पुनर्स्थापित डेटाबेस अपने SSO, webhook और integration क्रेडेंशियल डिक्रिप्ट नहीं कर सकता; जब तक मास्टर कुंजी रोटेशन पूरा न हो और कुछ भी अनसुलझा न रहे (key-rotation.md), इसमें सेवानिवृत्त कुंजियाँ भी शामिल हैं। दोनों का बैकअप लें।

बैकअप लेना

पूरे क्लस्टर का बेस बैकअप:

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

यह सबसे नए QUIRE_BACKUP_KEEP बेस बैकअप (डिफ़ॉल्ट 5) रखता है और सबसे पुराने बैकअप के लिए अब गैरज़रूरी WAL हटाता है, ताकि संग्रह असीमित रूप से न बढ़े। होस्ट पर cron या systemd timer से इसे प्रतिदिन चलाएँ:

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

या स्टैक से समय-सारणी बनवाएँ: backup प्रोफ़ाइल का backup-scheduler हर QUIRE_BACKUP_INTERVAL_HOURS घंटे (डिफ़ॉल्ट 24) पर बेस बैकअप लेता है, और आगे बताया गया backup-offsite चलाता है।

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

होस्ट से बाहर एन्क्रिप्टेड प्रतियाँ

दोनों वॉल्यूम डेटाबेस के साथ उसी होस्ट पर हैं, और विफल मशीन पर रखा बैकअप बैकअप नहीं है। backup-offsite हर बेस बैकअप और हर संग्रहीत WAL खंड को storage port से अलग संग्रह में एन्क्रिप्ट करके कॉपी करता है और वहाँ प्रतिधारण नीति के अनुसार रखता है:

  • एन्क्रिप्शन। QUIRE_BACKUP_ENCRYPTION_KEY (या QUIRE_BACKUP_ENCRYPTION_KEY_FILE से बताई फ़ाइल) के साथ AES-256-GCM: openssl rand -hex 32 से बनाए गए 32 bytes। हर फ़ाइल का अपना nonce और authentication tag होता है, इसलिए कुंजी के बिना प्रति पढ़ी नहीं जा सकती और उसमें बदलाव पकड़ा जाता है। कुंजी को QUIRE_MASTER_KEY के साथ, इस होस्ट और बैकअप संग्रह दोनों से दूर रखें। कुंजी के बिना पुनर्स्थापन नहीं हो सकता।
  • स्थान। QUIRE_BACKUP_STORAGE_DRIVER का मान s3, azure या local है (QUIRE_BACKUP_STORAGE_ROOT पर माउंट की गई दूरस्थ डिस्क)। सेटिंगें फ़ाइल स्टोरेज वाली हैं, जिनके आगे QUIRE_BACKUP_ उपसर्ग है: QUIRE_BACKUP_S3_ENDPOINT, QUIRE_BACKUP_S3_BUCKET, QUIRE_BACKUP_S3_ACCESS_KEY_ID आदि। फ़ाइलों से अलग bucket और बेहतर हो तो अलग खाता इस्तेमाल करें; यदि प्रदाता अनुमति दे तो ऐसे क्रेडेंशियल रखें जिनसे लिख सकें लेकिन मिटा न सकें।
  • प्रतिधारण। सबसे नए QUIRE_BACKUP_OFFSITE_KEEP बेस बैकअप (डिफ़ॉल्ट QUIRE_BACKUP_KEEP, अन्यथा 7) और सबसे पुराने के लिए ज़रूरी WAL; पुराने सेट और खंड संग्रह से मिटते हैं।
  • समय। हर QUIRE_BACKUP_SHIP_INTERVAL_SECONDS सेकंड (डिफ़ॉल्ट 300)। भेजने की प्रक्रिया idempotent है: जो पहले से संग्रह में है उसे छोड़ देती है और बेस बैकअप को तभी संग्रहित मानती है जब अंत में उसका manifest लिखा गया हो।

हाथ से चलाने पर भी यही कमांड है:

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

नए होस्ट पर पुनर्स्थापन के लिए पहले सेट वापस लाएँ, फिर नीचे के चरणों में pgbackup वॉल्यूम की जगह लाई गई डायरेक्टरी और wal-archive की जगह लाई गई pgwal डायरेक्टरी इस्तेमाल करें:

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

समय-बिंदु पर पुनर्स्थापन

डेटा खोने पर इसका उपयोग करें: गलत import, हटाया पाठ्यक्रम, या ऐसी contract migration जिसे वापस लेना है। यह चालू डेटाबेस बदलता है, इसलिए पहले नीचे के अभ्यास में इसे आज़माएँ।

  1. लक्ष्य समय चुनें, क्षति से ठीक पहले का 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. पुनर्स्थापन सत्यापित होने तक क्षतिग्रस्त क्लस्टर रखें:
    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. लक्ष्य समय से पहले का सबसे नया बेस बैकअप डेटा वॉल्यूम में खोलें और लक्षित रिकवरी माँगें:
    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. पुनर्प्राप्त करें: सामान्य फ़ाइल को छुए बिना Compose override के जरिए रिकवरी सेटिंगों सहित 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 बदलता है, इसलिए रिकवरी की निर्भर दो सेटिंगें भी दोहराएँ: max_connections प्राथमिक सर्वर से कम न हो (वरना रिकवरी “insufficient parameter settings” संदेश के साथ रुकती है) और माउंट की गई 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), और यह कि खोया डेटा लौट आया है।
  7. सामान्य स्थिति में लौटें: docker compose -f docker/compose.yaml up -d. इससे Postgres archiving चालू करके फिर शुरू होता है और WAL की नई timeline आरंभ होती है। तुरंत नया बेस बैकअप लें।

प्रोजेक्ट नाम quire हर वॉल्यूम के आगे जुड़ता है; सटीक नाम docker volume ls दिखाता है।

नियोजित सत्यापन अभ्यास

backup-offsite हर QUIRE_BACKUP_DRILL_INTERVAL_HOURS घंटे (डिफ़ॉल्ट 168, यानी साप्ताहिक) अभ्यास चलाता है, और विफलता के बाद अगले चक्र में फिर चलाता है। यह नवीनतम होस्ट-बाहरी बेस बैकअप और उसके बाद के सभी WAL खंड लाता है, हर एक को डिक्रिप्ट करता है (इससे पुष्टि होती है कि कुंजी अब भी खोलती है और बदलाव नहीं हुआ), प्रत्येक फ़ाइल को उसके manifest से मिलाता है, जाँचता है कि संग्रह Postgres डेटा डायरेक्टरी है, और पुष्टि करता है कि बैकअप के बाद WAL में कोई अंतराल नहीं। रिपोर्ट संग्रह में reports/drill-<time>.json और सेवा लॉग में लिखी जाती है; विफल अभ्यास फ़ाइल या पहला अनुपस्थित खंड बताता है।

पुनर्स्थापन अभ्यास

जिस बैकअप को कभी पुनर्स्थापित नहीं किया गया, वह बैकअप नहीं है। अभ्यास नवीनतम पूर्ण बेस बैकअप (जो लक्ष्य से पहले लिया गया हो) और WAL संग्रह को ऐसे अस्थायी Postgres में पुनर्स्थापित करता है जिसका चालू सर्वर से कुछ साझा नहीं, और नतीजे की पुष्टि करता है:

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

लक्ष्य ठीक इसी रूप में UTC होना चाहिए। इसके लिए उससे पुराना बेस बैकअप और उसके आगे का संग्रहीत WAL चाहिए: नए इंस्टॉल पर बेस बैकअप लें और लक्ष्य चुनने से पहले अगला संग्रहीत खंड आने की प्रतीक्षा करें (लिखाई चल रही हो तो अधिकतम एक मिनट)। इस अभ्यास को होस्ट पर Docker और bash चाहिए, और कुछ नहीं।

हर चरण में विफलता से अभ्यास विफल होता है:

  1. पुनर्प्राप्ति क्षमता: अस्थायी क्लस्टर लक्ष्य समय तक WAL लागू करके खुलता है।
  2. पूर्णता: चालू डेटाबेस से हर तालिका की पंक्ति-संख्या की तुलना (tooling/restore-drill)। चालू डेटाबेस लक्ष्य से आगे बढ़ चुका है, इसलिए किसी तालिका में दोनों दिशाओं में 500 पंक्तियों और उसके आकार के दसवें हिस्से में से अधिकतम अंतर स्वीकार्य है (लिखाइयों से पुनर्स्थापन पीछे रह सकता है, मिटाने से उसमें अधिक पंक्तियाँ रह सकती हैं); लक्ष्य के बाद बना partition खोई तालिका नहीं। अधिक व्यस्त इंस्टॉल में QUIRE_DRILL_MAX_BEHIND और QUIRE_DRILL_MAX_DRIFT_RATIO से सीमा बढ़ाएँ। अनुपस्थित या खाली तालिका विफल होती है।
  3. अखंडता: पुनर्स्थापित प्रति में audit hash chain सत्यापित होती है।
  4. उपयोगिता: application role row-level security के जरिए पढ़ती है।
  5. समय: आरंभ से सफलता तक, QUIRE_DRILL_RTO_SECONDS (डिफ़ॉल्ट 3600) के भीतर।

यह चालू डेटाबेस या उसके वॉल्यूम में कभी नहीं लिखता: बैकअप और WAL वॉल्यूम केवल पढ़ने के लिए माउंट होते हैं और अस्थायी क्लस्टर अंत में हटा दिया जाता है, सफलता या विफलता दोनों में।

QUIRE_DRILL_REPORT को पथ पर सेट करके JSON रिपोर्ट लिखवाएँ; यह सफलता या विफलता, दोनों स्थितियों में लिखी जाएगी। इसे Docker होस्ट से समय-सारणी पर चलाएँ:

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

इसे हर महीने और हर अपग्रेड से पहले चलाएँ। विफल अभ्यास अपग्रेड रोकता है। हर तिमाही किसी ऐसे व्यक्ति से अतिरिक्त होस्ट पर वास्तविक समय-बिंदु पुनर्स्थापन करवाएँ जिसने यह रनबुक नहीं लिखी हो, और केवल यही दस्तावेज़ दें।

फ़ाइलें

स्थानीय फ़ाइलें files वॉल्यूम में रहती हैं। डेटाबेस के साथ, उसी समय इनका बैकअप लें और दोनों को एक साथ पुनर्स्थापित करें:

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 .

ऑब्जेक्ट स्टोरेज में bucket versioning चालू करें और 35 दिन तक अप्रचलित संस्करण रखें; तब फ़ाइलों की समय-बिंदु पुनर्प्राप्ति bucket संभालता है।

नेविगेशन

खोजने के लिए लिखें…

↑↓ नेविगेट करें↵ चुनेंEsc बंद करें