Pereiti prie turinio

Atsarginės kopijos, atkūrimas taško ir atkūrimo pratybos

Darykite Quire atsatines kopijas, atkurkite ją į laiko tašką ir įrodykite tai atkūrimo pratybomis.

Rodyti kaip Markdown

Projekto aprašas yra docs/architecture/23-ops.md 8 skyrius. Šis yra Docker Compose produkto veiksmų vadovas. Jis parašytas tam, kad galėtų sekti kas jo nerašė; jei koks nors žingsnis neaiškus, tai yra šio dokumento brokas.

Kas apsaugota ir kaip

Turtas Kaip Kur
Duomenų bazė WAL archyvuojamas nuolat, dažniausiai kas 60 sekundžių, nuo pirmojo paleidimo pgwal tomas
Duomenų bazė Bazinės atsarginės kopijos su pg_basebackup, pagal nutylėjimą kasdien (backup-scheduler) pgbackup tomas
Duomenų bazė Užšifruotos bazinių atsarginių kopijų ir WAL kopijos, kas penkias minutes (backup-offsite) Atskira saugykla, kurią įvardijate
Failai files tomas. Nukopijuokite jį savo sistemos atsarginių kopijų įrankiu arba naudokite versijas turinčią objektų saugyklą files tomas
Paslaptys docker/.env, visų pirma QUIRE_MASTER_KEY (ir bet koks QUIRE_MASTER_KEY_RETIRED vis dar naudojamas), QUIRE_BACKUP_ENCRYPTION_KEY bei docker/secrets/audit-signing-key.pem Laikykite kopiją už šios ribų
Paieškos indeksai, podėliai, pavidalai Neatsarginės kopijos nedaromos; atkuriami iš naujo

Tikslai: atsigavimo taškas per 60 sekundžių nuo gedimo ir atkūrimas per 60 minučių 500 GB duomenų bazei.

Dvi klaidos yra dažnos. Duomenų bazė, atkurta be savo failų, rodo sugadintus puslapius. Duomenų bazė, atkurta be QUIRE_MASTER_KEY, negali iššifruoti joje esančių SSO, „webhook“ ir integracijos prisijungimo duomenų; kol pagrindinio rakto rotavimas nebaigiamas nieko neišsprendus (key-rotation.md), tai apima ir atsargos raktus. Abu yra atsarginės kopijos dalis.

Atsarginių kopijų darymas

Bazinė atsarginė kopija viso klasterio:

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

Ji išlaiko naujausias QUIRE_BACKUP_KEEP bazines atsatines kopijas (pagal nutylėjimą 5) ir išvalo WAL, kurio seniausiai kopijai nebereikia, todėl archyvas negali augti be ribos. Suplanuokite tai kasdien su cron arba systemd laikmačiu sistemoje:

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

Arba leiskite masyvui tai suplanuoti: profilis backup paleidžia backup-scheduler, kuris daro bazinę atsatinę kopiją kas QUIRE_BACKUP_INTERVAL_HOURS (pagal nutylėjimą 24), ir backup-offsite, aprašytą toliau.

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

Užšifruotos kopijos už sistemos ribų

Abu tomai yra toje pačioje sistemoje kaip ir duomenų bazė, o atsarginė kopija toje mašinoje, kuri sugedo, nėra atsarginė kopija. backup-offsite nukopijuoja kiekvieną bazinę atsatinę kopiją ir kiekvieną archyvuotą WAL segmentą į atskirą saugyklą per saugyklos prievadą, užšifruotą, ir laiko jas ten su saugojimo trukme:

  • Šifravimas. AES-256-GCM su QUIRE_BACKUP_ENCRYPTION_KEY (arba failu, kurį nurodo QUIRE_BACKUP_ENCRYPTION_KEY_FILE): 32 baitai, gaunami su openssl rand -hex 32. Kiekvienas failas turi savo nonces ir autentifikacijos žymą, todėl kopija be rakto neperskaitoma ir bet koks jos pakeitimas aptinkamas. Rakto laikykite kartu su QUIRE_MASTER_KEY, toli nuo šios sistemos ir toli nuo atsarginių kopijų saugyklos. Be rakto atkūrimo nėra.
  • Kur. QUIRE_BACKUP_STORAGE_DRIVER yra s3, azure arba local (prijungtas nuotolinis diskas ties QUIRE_BACKUP_STORAGE_ROOT). Nustatymai yra failų saugyklos nustatymai su priešdėliu QUIRE_BACKUP_: QUIRE_BACKUP_S3_ENDPOINT, QUIRE_BACKUP_S3_BUCKET, QUIRE_BACKUP_S3_ACCESS_KEY_ID ir t. t. Naudokite kitą kibirą ir, pageidautina, kitą paskyrą nei failams, su prisijungimo duomenimis, kurie gali rašyti, bet nešalinti, jei teikėjas tai leidžia.
  • Saugojimo trukmė. Naujausios QUIRE_BACKUP_OFFSITE_KEEP bazinės atsarginės kopijos (pagal nutylėjimą QUIRE_BACKUP_KEEP, kitaip 7) ir WAL, kurio reikia seniausiai iš jų; senesni rinkiniai ir segmentai iš saugyklos ištrinami.
  • Kada. Kas QUIRE_BACKUP_SHIP_INTERVAL_SECONDS (pagal nutylėjimą 300). Siuntimas yra idempotentiškas: kas jau išsaugota, praleidžiama, o bazinė atsarginė kopija laikoma išsaugota tik tada, kai paskutinis įrašomas jos manifestas.

Ta pati komanda paleidžiama ranka:

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

Kad atkurtumėte naujoje sistemoje, pirmiausia parsisiųskite rinkinį, tada vykdykite toliau nurodytus žingsnius, naudodami parsisiųstą katalogą vietoj pgbackup tomo ir parsisiųstą wal-archive vietoj pgwal:

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

Atkūrimas į laiko tašką

Naudokite tai praradus duomenis: blogas importas, ištrintas kursas, sutraukimo migracija, kurią reikia atšaukti. Ji pakeičia gyvą duomenų bazę, todėl pirmiausia išbandykite ją toliau nurodytomis pratybomis.

  1. Pasirinkite tikslinį laiką, UTC, tik prieš žalą: 2026-09-24 09:30:00+00. Audito žurnalas (/admin/audit) paprastai parodo tą momentą.
  2. Sustabdykite viską, kas rašo: docker compose -f docker/compose.yaml stop web content worker scheduler collab
  3. Palikite sugadintą klasterį, kol atkūrimas nepatikrintas:
    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. Išpakuokite naujausią bazinę atsatinę kopiją, senesnę už tikslinį laiką, į duomenų tomą ir paprašykite tikslingo atkūrimo:
    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. Atkurkite: paleiskite Postgres vieną kartą su atkūrimo nustatymais, iš Compose perrašymo failo, kad įprastinis failas liktų nepaliestas:
    # 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]
    Perrašymo failas pakeičia visą komandą, todėl jis pakartoja tuos du nustatymus, nuo kurių priklauso atkūrimas: max_connections ne mažesnis už pirminio (kitaip atkūrimas nutrūksta su “insufficient parameter settings”) ir prijungtą 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. Patikrinkite prieš įleisdami ką nors: audito grandinę (docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts) ir tai, kad prarasti duomenys sugrįžo.
  7. Grįžkite į įprastą būseną: docker compose -f docker/compose.yaml up -d. Tai paleidžia Postgres su įjungtu archyvavimu ir prasideda nauja WAL laiko juosta. Iš karto padarykite naują bazinę atsatinę kopiją.

Projekto pavadinimas quire priešdėliu žymi kiekvieną tomą; tikslius pavadinimus parodo docker volume ls.

Suplanuota patikros pratyba

backup-offsite taip pat paleidžia pratybą kas QUIRE_BACKUP_DRILL_INTERVAL_HOURS (pagal nutylėjimą 168, kas savaitę) ir dar kartą kitu prasėjimu po to, kai viena nepavyksta. Ji parsisiunčia naujausią už sistemos ribų bazinę atsatinę kopiją ir kiekvieną WAL segmentą po jos, iššifruoja kiekvieną (kas įrodo, kad raktas jas vis dar atveria ir nieko nebuvo pakeista), palygina kiekvieną failą su jo manifestu, patikrina, ar archyvas yra Postgres duomenų katalogas, ir patikrina, ar WAL nuo atsarginės kopijos neturi skylių. Ataskaita įrašoma į saugyklą kaip reports/drill-<time>.json ir į paslaugos žurnalą; nepavykus pratybai įvardijamas failas arba pirmas trūkstamas segmentas.

Atkūrimo pratybos

Atsarginė kopija, kuri niekados nebuvo atkurta, nėra atsarginė kopija. Pratyba atkuria naujausią pilną bazinę atsatinę kopiją, padarytą prieš tikslinį laiką, plius WAL archyvą, į laikiną Postgres, niekuo nesidalijančią su gyvąja, ir įrodo rezultatą:

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

Tikslinis laikas yra UTC būtent tokia forma. Jam reikia bazinės atsarginės kopijos, senesnės už jį, ir archyvuoto WAL už jį: naujai įdiegtoje sistemoje padarykite bazinę atsatinę kopiją ir palaukite kito archyvuoto segmento (daugiausia minutė, jei kas nors rašoma), prieš rinkdamiesi laiką po atsatinės kopijos. Pratybai reikia Docker ir bash sistemoje, nieko daugiau.

Kiekvienas žingsnis pratybą paverčia nesėkminga:

  1. Atkuriamumas: laikinas klasteris atkūrimu pasiekia tikslinį laiką ir atsidaro.
  2. Pilnumas: kiekvienos lentelės eilučių skaičius prieš gyvą duomenų bazę (tooling/restore-drill). Gyva duomenų bazė nuo to laiko pajudėjo, todėl lentelė gali skirtis tiek, kiek didesnis iš 500 eilučių ir dešimties procentų jos dydžio, bet kuria kryptimi (rašymai ją atsilieka, trynimai daro, kad atkurta turi daugiau); po tikslinio laiko sukurta skiltis nėra prarasta lentelė. Plėskite leidimą užimtesnėje sistemoje su QUIRE_DRILL_MAX_BEHIND ir QUIRE_DRILL_MAX_DRIFT_RATIO. Trūkstama arba ištuštinta lentelė priverčia pratybą nepavykti.
  3. Vientisumas: audito maišų grandinė patikrinama atkurtoje kopijoje.
  4. Privalumas: programų vaidmuo skaito per eilučių lygio apsaugą.
  5. Laikas: nuo pradžios iki žalios, prieš QUIRE_DRILL_RTO_SECONDS (pagal nutylėjimą 3600).

Ji niekada nerašo į gyvą duomenų bazę arba jos tomus: atsatinės kopijos ir WAL tomai prijungiami tik skaitymui, o laikinas klasteris pašalinamas pabaigoje, pavykus arba nepavykus.

Nustatykite QUIRE_DRILL_REPORT į kelią, kad būtų įrašytas JSON ataskaitas, pavykus arba nepavykus, ir paleiskite ją pagal tvarkaraštį iš Docker sistemos:

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

Paleiskite ją kas mėnesį ir prieš kiekvieną atnaujinimą. Nepavykusios pratybos blokuoja atnaujinimą. Kartą per ketvirtį leiskite kas, kas nerašė šio veiksmų vadovo, atlikti tikrą atkūrimą taške atsarginėje sistemoje, naudojantis tik šiuo dokumentu.

Failai

Vietiniai failai gyvena files tome. Atsarginę kopiją darykite kartu su duomenų baze, tuo pačiu metu, ir abu atkurkite kartu:

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 .

Naudojant objektų saugyklą, įjunkite kibiro versijavimą ir laikykite 35 dienas neaktualių versijų; tada failų atkūrimas taške yra paties kibiro.

Navigacija

Įveskite norėdami ieškoti…

↑↓ naršyti↵ pasirinktiEsc uždaryti