---
title: "Atsarginės kopijos, atkūrimas taško ir atkūrimo pratybos"
description: "Darykite Quire atsatines kopijas, atkurkite ją į laiko tašką ir įrodykite tai atkūrimo pratybomis."
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/lt/llms.txt
> Use this file to discover all available pages before exploring further.

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

<span id="backup-point-in-time-recovery-and-the-restore-drill"></span>

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 <!--quire:what-is-protected-and-how-->

| 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](/lt/ops/key-rotation/)), tai apima ir atsargos raktus. Abu yra
atsarginės kopijos dalis.

## Atsarginių kopijų darymas <!--quire:taking-backups-->

Bazinė atsarginė kopija viso klasterio:

```sh
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:

```cron
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.

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

## Užšifruotos kopijos už sistemos ribų <!--quire:encrypted-off-host-copies-->

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:

```sh
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`:

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

## Atkūrimas į laiko tašką <!--quire:restoring-to-a-point-in-time-->

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:
   ```sh
   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:
   ```sh
   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:
   ```yaml
   # 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`.
   ```sh
   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 <!--quire:the-scheduled-verification-drill-->

`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 <!--quire:the-restore-drill-->

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ą:

```sh
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:

```cron
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 <!--quire:files-->

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

```sh
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.

Source: https://docs.quirelms.com/lt/ops/backup-restore/index.mdx
