Konstrukcija ir docs/architecture/23-ops.md 8. sadaļa. Šī ir darbību lapa
Docker Compose produktam. Tā ir uzrakstīta tā, lai tai sekotu cilvēks, kas to
neuzrakstīja; ja solis ir neskaidrs, tas ir šī dokumenta defekts.
Kas tiek aizsargāts un kā
Resurss
Kā
Kur
Datubāze
WAL arhivēts nepārtraukti, vismaz ik pēc 60 sekundēm, no pirmās ielādes
pgwal sējums
Datubāze
Bāzes dublējumi ar pg_basebackup, pēc noklusējuma katru dienu (backup-scheduler)
pgbackup sējums
Datubāze
Bāzes dublējumu un WAL šifrētas kopijas ik pēc piecām minūtēm (backup-offsite)
Atsevišķa glabātuve, kuru nosauci
Faili
files sējums. Kopē to ar sava servera dublēšanas rīku vai izmanto versijām objektu glabātuvi
files sējums
Noslēpumi
docker/.env, vispirms QUIRE_MASTER_KEY (un jebkurš joprojām lietojamais QUIRE_MASTER_KEY_RETIRED), QUIRE_BACKUP_ENCRYPTION_KEY un docker/secrets/audit-signing-key.pem
Glabā kopiju ārpus šī servera
Meklēšanas indeksi, keši, renderējumi
Netiek dublēti; tiek pārbūvēti
Mērķi: atgūšanas punkts 60 sekunžu robežās pēc kļūmes un atjaunošana 60 minūšu
laikā 500 GB datubāzei.
Divas kļūdas ir izplatītas. Datubāze, kas atjaunota bez tās failiem, rāda
bojātas lapas. Datubāze, kas atjaunota bez QUIRE_MASTER_KEY, nevar
atsifrēt tajā glabātos SSO, tīmekļa āķu un integrāciju akreditācijas datus; līdz
galvenās atslēgas maiņa nav pabeigta bez nekā neatrisināta
(key-rotation.md), tas ietver arī atsauktās atslēgas. Abas
ir dublējuma sastāvdaļa.
Dublējumu uzņemšana
Bāzes dublējums visai kopklasei:
docker compose -f docker/compose.yaml --profile backup run --rm backup
Tas patur jaunākos QUIRE_BACKUP_KEEP bāzes dublējumus (noklusējums 5) un
izgriež WAL, ko vecākajam vairs nevajag, tāpēc arhīvs neaug bez robežas.
Plānojiet to katru dienu ar cron vai systemd taimeri uz servera:
15 2 * * * cd /srv/quire && docker compose -f docker/compose.yaml --profile backup run --rm backup >> /var/log/quire-backup.log 2>&1
Vai ļaujiet kopklasei to plānot: profils backup palaiž backup-scheduler,
kas ik pēc QUIRE_BACKUP_INTERVAL_HOURS (noklusējums 24) ņem bāzes dublējumu,
un backup-offsite, kas aprakstīts tālāk.
docker compose -f docker/compose.yaml --profile backup up -d
Šifrētas kopijas ārpus servera
Abi sējumi atrodas uz tā paša servera kur datubāze, un dublējums uz mašīnas,
kas izgāzās, nav dublējums. backup-offsite nokopē katru bāzes dublējumu un
katru arhivēto WAL segmentu uz atsevišķu glabātuvi caur glabātuves portu,
šifrētus, un tur tos glabā paturēšanas noteikumu dēļ:
Šifrēšana. AES-256-GCM ar QUIRE_BACKUP_ENCRYPTION_KEY (vai failu, ko
nosaka QUIRE_BACKUP_ENCRYPTION_KEY_FILE): 32 baiti, no
openssl rand -hex 32. Katram failam ir sava nonce un autentifikācijas
žetons, tāpēc bez atslēgas kopija nav lasāma un jebkura tās maiņa tiek
atklāta. Glabā atslēgu kopā ar QUIRE_MASTER_KEY, prom no šī servera un prom
no dublējumu glabātuves. Bez atslēgas atjaunošanas nav.
Kur.QUIRE_BACKUP_STORAGE_DRIVER ir s3, azure vai local
(montēts attālināts disks vietnē QUIRE_BACKUP_STORAGE_ROOT). Iestatījumi
ir tie paši, kas failu glabātuvei, ar QUIRE_BACKUP_ prefiksu:
QUIRE_BACKUP_S3_ENDPOINT, QUIRE_BACKUP_S3_BUCKET,
QUIRE_BACKUP_S3_ACCESS_KEY_ID un tā tālāk. Izmantojiet citu spaini un,
vēlams, citu kontu nekā failiem, ar akreditācijas datiem, kas drīkst rakstīt,
bet ne dzēst, ja pakalpojums to ļauj.
Paturēšana. Jaunākie QUIRE_BACKUP_OFFSITE_KEEP bāzes dublējumi
(noklusējums QUIRE_BACKUP_KEEP, citādi 7) un WAL, ko vajag vecākajam no
tiem; vecāki kopu un segmenti tiek no glabātuves izdzēsti.
Kad. Katrs QUIRE_BACKUP_SHIP_INTERVAL_SECONDS (noklusējums 300).
Nosūtīšana ir idempota: kas jau ir saglabāts, tiek izlaists, un bāzes
dublējums tiek uzskatīts par saglabātu tikai tad, kad tā manifests ir
pierakstīts, pēdējais.
To pašu komandu var palaist ar roku:
docker compose -f docker/compose.yaml run --rm backup-offsite bun apps/worker/src/backups/main.ts shipdocker compose -f docker/compose.yaml run --rm backup-offsite bun apps/worker/src/backups/main.ts verify
Lai atjaunotu jaunā serverī, vispirms atvediet kopu atpakaļ, pēc tam sekojiet
tālāk esošajiem soļiem, vietā liekot pgbackup sējumu un vietā liekot
atvilktos wal-archive sējumam pgwal:
bun apps/worker/src/backups/main.ts fetch base-20260924T021500Z /srv/restore
Atjaunošana līdz noteiktam laika punktam
To izmanto pēc datu zaudēšanas: sliktas importes, izdzēsta kursa,
sašaurinājuma migrācijas, kuru vajag atsaukt. Tā aizstāj dzīvo datubāzi, tāpēc
vispirms to izmēģiniet ar zemāk esošo mācību.
Izvēlieties mērķa laiku, UTC, tieši pirms bojājuma:
2026-09-24 09:30:00+00. Audita žurnāls (/admin/audit) parasti rāda šo
brīdi.
Apturiet visu, kas raksta:
docker compose -f docker/compose.yaml stop web content worker scheduler collab
Paturiet bojāto kopklasi, līdz atjaunošana ir pārbaudīta:
docker compose -f docker/compose.yaml stop postgresdocker run --rm -v quire_postgres18-data:/from -v quire_postgres-damaged:/to alpine cp -a /from/. /to/
Atspiediet jaunāko bāzes dublējumu, kas ir vecāks par mērķi, datu
sējumā un pieprasiet mērķētu atgūšanu:
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'
Atgūstiet: palaidiet Postgres vienreiz ar atgūšanas iestatījumiem, no
Compose pārklājuma, lai parastais fails paliktu neskarts:
Pārklājums aizstāj visu komandu, tāpēc tajā atkārtojas abi iestatījumi, no
kuriem ir atkarīga atgūšana: max_connections ne zemāks par galvenā
servera (citādi atgūšana pārtrūkst ar “insufficient parameter settings”) un
montētais pg_hba.conf.
docker compose -f docker/compose.yaml -f docker/compose.recover.yaml up -d postgresdocker compose -f docker/compose.yaml logs -f postgres # wait for "database system is ready"
Pārbaudiet to, pirms ļaujat kādam ienākt: audita ķēdi
(docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts)
un to, ka zaudētie dati ir atpakaļ.
Atgriezieties normālā stāvoklī:
docker compose -f docker/compose.yaml up -d. Tas atkal startē Postgres ar
ieslēgtu arhivēšanu, un sākas jauna WAL laika līnija. Uzreiz paņemiet svaigu
bāzes dublējumu.
Projekta nosaukums quire ir prefikss katram sējumam; docker volume ls rāda
precīzos nosaukumus.
Plānotā pārbaudes mācība
backup-offsite arī katru QUIRE_BACKUP_DRILL_INTERVAL_HOURS (noklusējums 168,
reizi nedēļā) palaiž mācību un atkal nākamajā reizē pēc neveiksmes. Tā atvelk
jaunāko bāzes dublējumu ārpus servera un katru pēc tam sekojošo WAL segmentu,
katru atšifrē (kas pierāda, ka atslēga joprojām tos atver un nekas nav
mainīts), salīdzina katru failu ar tā manifestu, pārbauda, ka arhīvs ir
Postgres datu direktorijs, un pārbauda, ka WAL no dublējuma uz priekšu nav ar
caurumiem. Atskaite tiek rakstīta glabātuvē kā
reports/drill-<time>.json un pakalpojuma žurnālā; neizdevusies mācība nosauc
failu vai pirmo trūkstošo segmentu.
Atjaunošanas mācība
Dublējums, kas nekad nav atjaunots, nav dublējums. Mācība atjauno jaunāko
pilno bāzes dublējumu, kas uzņemts pirms mērķa, plus WAL arhīvu, pagaidu
Postgres, kas ar dzīvo nedalās neko, un pierāda rezultātu:
docker/scripts/restore-drill.sh # to ninety minutes agodocker/scripts/restore-drill.sh --target "2026-09-24 09:30:00+00"
Mērķis ir UTC tieši šajā formā. Tam vajag bāzes dublējumu, kas ir vecāks par to,
un arhivētu WAL aiz tā: jaunā uzstādīšanā paņemiet bāzes dublējumu un pagaidiet
nākamo arhivēto segmentu (ar ierakstījumiem ne vairāk par minūti), pirms
izvēlaties mērķi pēc dublējuma. Mācībai uz servera vajag Docker un bash, neko
citu.
Katrs solis izsauc mācības neveiksmi:
Atgūstamība: pagaidu kopklase atsāk līdz mērķim un atveras.
Pilnība: katra tabulu rindu skaits pret dzīvo datubāzi
(tooling/restore-drill). Dzīvā datubāze kopš mērķa ir virzījusies
uz priekšu, tāpēc tabula var atšķirties par lielāko no 500 rindām un
desmitdaļas no tās izmēra, abos virzienos (ierakstījumi to padara
atpaliekošu, dzēšanu — atjaunošanā var būt vairāk); pēc mērķa izveidota
daļa nav zaudēta tabula. Platāku atļauju aizņemtākā uzstādīšanā iestatiet
ar QUIRE_DRILL_MAX_BEHIND un QUIRE_DRILL_MAX_DRIFT_RATIO. Trūkstoša vai
iztukšota tabula ir neveiksme.
Lietojamība: lietojumprogrammas loma lasa caur rindu līmeņa drošību.
Laiks: no sākuma līdz zaļajam, pret QUIRE_DRILL_RTO_SECONDS
(noklusējums 3600).
Tā nekad neraksta dzīvajā datubāzē vai tās sējumos: dublējumu un WAL sējumus
montē tikai lasāmajā režīmā, un pagaidu kopklase tiek noņemta beigās, vai nu
veiksmes, vai neveiksmes gadījumā.
Iestatiet QUIRE_DRILL_REPORT uz ceļu, lai tiktu uzrakstīta JSON atskaite, vai
nu veiksmes, vai neveiksmes gadījumā, un palaidiet to pēc grafika no Docker
servera:
Palaidiet to ik pēc mēneša un pirms katra jauninājuma. Neizdevusies mācība
bloķē jaunināšanu. Reizi ceturksnī ļauj kādam, kas šo darbību lapu neuzrakstīja,
veikt īstu atjaunošanu punkta laikā uz rezerves servera, izmantojot tikai šo
dokumentu.
Faili
Vietējie faili dzīvo files sējumā. Dublējiet tos kopā ar datubāzi, vienā
laikā, un atjaunojiet abus kopā:
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 .
Ar objektu glabātuvi ieslēdziet spaiņu versijēšanu un glabājiet 35 dienas
neaktīvās versijas; failu atjaunošana punkta laikā tad ir paša spaiņa.