थेट मजकुराकडे जा

बॅकअप, पॉइंट-इन-टाइम पुनर्प्राप्ती आणि रिस्टोअर ड्रिल

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 आणि एकत्रीकरण प्रमाणपत्रे डिक्रिप्ट करू शकत नाही; मास्टर कुंजी फेरबदल काहीही अनिर्धारित न राहता पूर्ण होईपर्यंत (key-rotation.md), त्यात रिटायर केलेल्या कुंज्याही समाविष्ट आहेत. दोन्ही बॅकअपचा भाग आहेत.

बॅकअप घेणे

संपूर्ण क्लस्टरचे मूळ बॅकअप:

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

ते सर्वात नवीन QUIRE_BACKUP_KEEP मूळ बॅकअप (डीफॉल्ट 5) ठेवते आणि जुन्याला आवश्यक न राहिलेले WAL प्रुण करते, त्यामुळे आर्काइव्ह अमर्याद वाढू शकत नाही. होस्टवर cron किंवा systemd टाइमरने ते दैनंदिन शेड्यूल करा:

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 सेगमेंट स्टोरेज पोर्टद्वारे स्वतंत्र स्टोअरमध्ये, एन्क्रिप्ट करून कॉपी करते आणि रिटेन्शनखाली तिथे ठेवते:

  • एन्क्रिप्शन. QUIRE_BACKUP_ENCRYPTION_KEY (किंवा QUIRE_BACKUP_ENCRYPTION_KEY_FILE ने नेमलेली फाइल) सह AES-256-GCM: 32 बाइट्स, openssl rand -hex 32 पासून. प्रत्येक फाइलचे स्वतःचे नोन्स आणि प्रमाणीकरण टॅग असते, त्यामुळे कुंजीशिवाय प्रत वाचता येत नाही आणि त्यातील कोणताही बदल लक्षात येतो. कुंजी 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, इत्यादी. फाइलींपेक्षा वेगळे बकेट आणि शक्य असल्यास वेगळे खाते वापरा, प्रदाता परवानगी दिल्यास लिहू शकणारी पण हटवू न शकणारी प्रमाणपत्रे घेऊन.
  • रिटेन्शन. सर्वात नवीन QUIRE_BACKUP_OFFSITE_KEEP मूळ बॅकअप (डीफॉल्ट QUIRE_BACKUP_KEEP, नसेल तर 7) आणि त्यातील जुन्याला लागणारे WAL; जुनी संच व सेगमेंट स्टोअरमधून हटवली जातात.
  • कधी. दर QUIRE_BACKUP_SHIP_INTERVAL_SECONDS (डीफॉल्ट 300). पाठवणे बहु-विनंती सुरक्षित आहे: आधीच साठवलेले वगळले जाते आणि मूळ बॅकअप त्याचा मॅनिफेस्ट शेवटी लिहिल्यावरच एकदाच साठवलेले मानले जाते.

त्याच कमांड हाताने चालवता येते:

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

वेळेपर्यंत पुनर्स्थापना

डेटा गमावल्यानंतर हे वापरा: चुकीचे आयात, हटवलेला अभ्यासक्रम, पूर्ववत करायची आवश्यक असलेली संकुचित मायग्रेशन. ते जिवंत डेटाबेस बदलते, त्यामुळे आधी खालील ड्रिलने त्याचा सराव करा.

  1. लक्ष्य वेळ निवडा, UTC मध्ये, नुकसानापूर्वीच्या क्षणात: 2026-09-24 09:30:00+00. ऑडिट लॉग (/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. वसूली करा: वसूली सेटिंग्जसह Postgres एकदाच सुरू करा, नेहमीची फाइल न बदलता तशी एक Compose ओव्हरराइड वापरून:
    # 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]
    ओव्हरराइड संपूर्ण कमांड बदलतो, त्यामुळे तो वसूलीला लागणारे दोन्ही सेटिंग्ज पुन्हा लिहितो: 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. कोणालाही आत येऊ देण्यापूर्वी ते तपासा: ऑडिट साखळी (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 पुन्हा सुरू करते आणि नवीन WAL टाइमलाइन सुरू होते. लगेच नवीन मूळ बॅकअप घ्या.

प्रोजेक्ट नाव quire प्रत्येक वॉल्यूमच्या पूर्वलग्न म्हणून येते; docker volume ls अचूक नावे दाखवते.

शेड्यूल केलेली पडताळणी ड्रिल

backup-offsite दर QUIRE_BACKUP_DRILL_INTERVAL_HOURS ला (डीफॉल्ट 168, साप्ताहिक) ड्रिलही चालवते, आणि एक अपयशस्वी झाल्यावर पुढच्या वेळीही. ते सर्वात नवीन ऑफ-होस्ट मूळ बॅकअप आणि त्यानंतरचे प्रत्येक WAL सेगमेंट आणते, प्रत्येक डिक्रिप्ट करते (ज्यामुळे कुंजी अजूनही ते उघडते आणि काहीही बदललेले नाही हे सिद्ध होते), प्रत्येक फाइल तिच्या मॅनिफेस्टशी तुलना करते, आर्काइव्ह ही 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. वसूलीयोग्यता: कचरा क्लस्टर लक्ष्यापर्यंत पुन्हा चालवतो आणि उघडतो.
  2. पूर्णता: प्रत्येक तक्त्याची रूंदी जिवंत डेटाबेसशी (tooling/restore-drill). लक्ष्यानंतर जिवंत डेटाबेस पुढे गेला असल्याने तक्ता 500 रूंद्या आणि आकाराच्या एका दहाव्या भागापैकी मोठ्या प्रमाणाने, दोन्ही दिशांनी वेगळा असू शकतो (लेखने मागे टाकतात, हटवण्यामुळे रिस्टोअरमध्ये जास्त राहते); लक्ष्यानंतर तयार केलेली विभाजन गमावलेला तक्ता नाही. व्यस्त स्थापनेवर QUIRE_DRILL_MAX_BEHIND आणि QUIRE_DRILL_MAX_DRIFT_RATIO ने मर्यादा रुंद करा. गायब किंवा रिकामा तक्ता अपयशस्वी होतो.
  3. अखंडता: ऑडिट हॅश साखळी पुनर्स्थापित प्रतीवर पडताळली जाते.
  4. वापरण्यायोग्यता: अनुप्रयोग भूमिका रो-लेव्हल सुरक्षेतून वाचते.
  5. वेळ: सुरुवातीपासून हिरव्या स्थितीपर्यंत, QUIRE_DRILL_RTO_SECONDS (डीफॉल्ट 3600) शी तुलना.

ते जिवंत डेटाबेसावर किंवा त्याच्या वॉल्यूमवर कधीही लिहित नाही: बॅकअप आणि WAL वॉल्यूम फक्त वाचनासाठी माउंट केलेली असतात आणि कचरा क्लस्टर शेवटी, गमावले की जिंकले, काढले जाते.

JSON अहवाल लिहिवून मिळवण्यासाठी QUIRE_DRILL_REPORT ला पाथवर सेट करा, गमावले की जिंकले, आणि 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 .

ऑब्जेक्ट स्टोरेजसह बकेट आवृत्तीकरण चालू करा आणि 35 दिवसांच्या नॉनकरंट आवृत्त्या ठेवा; फाइलींसाठी पॉइंट-इन-टाइम वसूली तेव्हा बकेटची स्वतःची होते.

नेव्हिगेशन

शोधण्यासाठी लिहा…

↑↓ नेव्हिगेट करा↵ निवडाEsc बंद करा