U disignu hè in a sezzione 8 di docs/architecture/23-ops.md. Questu hè u manuale
per u pruduttu Docker Compose. Hè scrittu per esse seguitatu da qualchissia chì
ùn l’hà micca scrittu; s’è un passu ùn hè chjaru, hè un difettu di stu ducumentu.
Ciò chì hè prutettu, è cumu
Risorsa
Cumu
Induve
A basa di dati
WAL archiviatu di cuntinuu, almenu ogni 60 seconde, da u primu avviu
Volume pgwal
A basa di dati
Copie di salvezza di basa cù pg_basebackup, predefinitu ogni ghjornu (backup-scheduler)
Volume pgbackup
A basa di dati
Copie cifrate di e copie di salvezza di basa è di u WAL, ogni cinque minuti (backup-offsite)
Un magazinu separatu chì sceglite
Schedarii
U volume files. Copiatelu cù u strumentu di copia di salvezza di u vostru host, o aduprate un almacenamentu d’ogetti cù versioni
Volume files
Sicreti
docker/.env, soprattuttu QUIRE_MASTER_KEY (è qualsiasi QUIRE_MASTER_KEY_RETIRED sempre adupratu), QUIRE_BACKUP_ENCRYPTION_KEY, è docker/secrets/audit-signing-key.pem
Cunservate una copia fora di questu host
Indici di ricerca, cache, rendizioni
Ùn sò micca salvati; ricustruiti
Obiettivi: un puntu di ripresa à 60 seconde à u più da u guastu, è una risturazione
in 60 minuti per una basa di dati di 500 GB.
Dui sbagli sò cumuni. Una basa di dati risturata senza i so schedarii mostra
pagine rotte. Una basa di dati risturata senza QUIRE_MASTER_KEY ùn pò
decifrà e credenziali SSO, webhook è d’integrazione ch’ella cuntene; finch’è a rotazione di a chjave maestra ùn hè finita senza valori irrisolvibili (key-rotation.md),
ciò include e chjave ritirate. Tramindui facenu parte di a copia di salvezza.
Fà copie di salvezza
Una copia di salvezza di basa di tuttu u cluster:
docker compose -f docker/compose.yaml --profile backup run --rm backup
Cunserva e copie di salvezza di basa più recenti indicate da QUIRE_BACKUP_KEEP (predefinitu 5) è sguassa
u WAL chì a più vechja ùn hà più bisognu, cusì l’archiviu ùn pò cresce senza limite.
Pianificate lu ogni ghjornu cù cron o un timer systemd nant’à l’host:
15 2 * * * cd /srv/quire && docker compose -f docker/compose.yaml --profile backup run --rm backup >> /var/log/quire-backup.log 2>&1
O lasciate chì u stack u pianifichi: u prufilu backup esegue backup-scheduler,
chì face una copia di salvezza di basa ogni QUIRE_BACKUP_INTERVAL_HOURS (predefinitu 24),
è backup-offsite, discrittu dopu.
docker compose -f docker/compose.yaml --profile backup up -d
Copie cifrate fora di l’host
I dui volumi sò nant’à u listessu host chè a basa di dati, è una copia di salvezza nant’à a
macchina guasta ùn hè micca una copia di salvezza. backup-offsite copia ogni copia di salvezza di basa
è ogni segmentu WAL archiviatu in un magazinu separatu via a porta di almacenamentu,
cifrati, è i cunserva quì secondu a pulitica di retenzione:
Cifratura. AES-256-GCM cù QUIRE_BACKUP_ENCRYPTION_KEY (o u schedariu
indicatu da QUIRE_BACKUP_ENCRYPTION_KEY_FILE): 32 byte, generati cù
openssl rand -hex 32. Ogni schedariu hà u so propiu nonce è una
etichetta d’autentificazione, dunque una copia hè illeggibile senza a chjave è ogni mudificazione
hè rilevata. Cunservate a chjave cù QUIRE_MASTER_KEY, luntanu da questu host è luntanu
da u magazinu di salvezza. Senza a chjave ùn si pò risturà.
Locu.QUIRE_BACKUP_STORAGE_DRIVER hè s3, azure o local (un
discu remotu muntatu in QUIRE_BACKUP_STORAGE_ROOT). I paràmetri sò quelli
di almacenamentu di schedarii cù u prefissu QUIRE_BACKUP_: QUIRE_BACKUP_S3_ENDPOINT,
QUIRE_BACKUP_S3_BUCKET, QUIRE_BACKUP_S3_ACCESS_KEY_ID, è cetara. Aduprate un
bucket sfarente è, di preferenza, un contu sfarente da quellu di i schedarii, cù
credenziali chì ponu scrive ma micca sguassà, s’è u fornitore u permette.
Retenzione. E copie di salvezza di basa più recenti indicate da QUIRE_BACKUP_OFFSITE_KEEP (predefinitu
QUIRE_BACKUP_KEEP, altrimenti 7) è u WAL chì a più vechja di elle hà bisognu; l’insemi
è i segmenti più vechji sò sguassati da u magazinu.
Quandu. Ogni QUIRE_BACKUP_SHIP_INTERVAL_SECONDS (predefinitu 300). L’inviu
hè idempotente: ciò chì hè digià cunservatu hè saltatu, è una copia di salvezza di basa conta cum’è cunservata solu quandu u so manifestu hè scrittu, à a fine.
U listessu cumandu pò esse eseguitu à manu:
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
Per risturà nant’à un host novu, ricuperate prima un inseme, dopu seguitate i passi sottu
cù u cartulare ricuperatu à u locu di u volume pgbackup è u
wal-archive ricuperatu à u locu di pgwal:
bun apps/worker/src/backups/main.ts fetch base-20260924T021500Z /srv/restore
Risturà à un mumentu precisu
Aduprate questu dopu una perdita di dati: una impurtazione sbagliata, un corsu sguassatu, una migrazione di
cuntrazione ch’è vo avete bisognu d’annullà. Rimpiazza a basa di dati attiva, dunque pruvate lu
prima cù l’eserciziu sottu.
Sceglite u mumentu di destinazione, in UTC, ghjustu nanzu à u dannu:
2026-09-24 09:30:00+00. U registru d’audit (/admin/audit) mostra di solitu u
mumentu.
Arrestate tuttu ciò chì scrive:
docker compose -f docker/compose.yaml stop web content worker scheduler collab
Cunservate u cluster dannighjatu finch’è a risturazione ùn hè verificata:
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/
Scumpressate a copia di salvezza di basa più recente, più vechja chè u mumentu di destinazione, in u volume
di dati, è dumandate una ripresa mirata:
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'
Ripigliate: avviate Postgres una volta cù i paràmetri di ripresa, da un
override Compose affinchì u schedariu nurmale resti intattu:
L’override rimpiazza tuttu u cumandu, dunque ripete i dui paràmetri chì a
ripresa richiede: max_connections micca più bassu chè quellu di a basa primaria
(altrimenti a ripresa si ferma cù «insufficient parameter settings») è
u pg_hba.conf muntatu.
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"
Verificate la prima di lascià entre qualchissia: a catena d’audit
(docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts),
è chì i dati persi sò stati ricuperati.
Tornate à u funziunamentu nurmale: docker compose -f docker/compose.yaml up -d. Questu
riavvia Postgres cù l’archiviazione attivata, è principia una nova cronulugia WAL. Fate subitu una
nova copia di salvezza di basa.
U nome di u prughjettu quire hè prefissatu à ogni volume; docker volume ls mostra i
nomi esatti.
Prova di verificazione pianificata
backup-offsite esegue ancu una prova ogni QUIRE_BACKUP_DRILL_INTERVAL_HOURS
(predefinitu 168, una volta à settimana), è torna à a prossima esecuzione dopu à un fiascu. Ricupera
l’ultima copia di salvezza di basa da fora di l’host è ogni segmentu WAL dopu à ella, decifra ogni schedariu
(ciò chì prova chì a chjave pò sempre apre li è ch’elli ùn sò micca stati alterati), paraguneghja ogni
schedariu cù u so manifestu, verifica chì l’archiviu sia un cartulare di dati Postgres, è
verifica chì ùn ci sia lacune in u WAL da a copia di salvezza in avanti. U rapportu hè scrittu in
u magazinu cum’è reports/drill-<time>.json è in u registru di u serviziu; una prova fallita
nomina u schedariu o u primu segmentu mancante.
Prova di risturazione
Una copia di salvezza chì ùn hè mai stata risturata ùn hè micca una copia di salvezza. A prova ristura a
copia di salvezza di basa cumpleta più recente fatta prima di u mumentu di destinazione, cù l’archiviu WAL,
in un Postgres pruvisoriu chì ùn hà nunda in cumunu cù quellu attivu, è prova u
risultatu:
docker/scripts/restore-drill.sh # to ninety minutes agodocker/scripts/restore-drill.sh --target "2026-09-24 09:30:00+00"
U mumentu di destinazione hè UTC esattamente in quella forma. Ci vole una copia di salvezza di basa più vechja chè ella
è WAL archiviatu dopu à ella: nant’à una nova installazione, fate una copia di salvezza di basa è aspettate u prossimu
segmentu archiviatu (à u più un minutu s’ellu ci sò scritture) prima di sceglie un mumentu di destinazione dopu à a copia. A prova hà bisognu di Docker è bash nant’à l’host, nunda
altru.
Ogni passu face fallisce a prova:
Pussibilità di risturazione: u cluster pruvisoriu riproduce i registri finu à u mumentu sceltu è s’avvia.
Cumpletezza: u numeru di filari di ogni tavula hè paragunatu à a basa attiva
(tooling/restore-drill). A basa attiva hè avanzata dapoi u mumentu sceltu,
dunque una tavula pò differisce di u più grande trà 500 filari è un decimu di a so dimensione, in
e duie direzzioni (e scritture facenu chì a risturazione sia in ritardu, e cancellazioni facenu chì cuntene di più);
una partizione creata dopu à u mumentu ùn hè micca una tavula persa. Allargate a
tolleranza in un’installazione più attiva cù QUIRE_DRILL_MAX_BEHIND è
QUIRE_DRILL_MAX_DRIFT_RATIO. Una tavula mancante o sviutata face fallisce a prova.
Integrità: a catena d’hash d’audit hè verificata nantu à a copia risturata.
Usabilità: u rollu d’applicazione leghje cù a sicurezza à livellu di fila.
Durata: da l’iniziu à u risultatu verde, secondu QUIRE_DRILL_RTO_SECONDS
(predefinitu 3600).
Ùn scrive mai in a basa attiva o in i so volumi: i volumi di copia di salvezza è di WAL
sò muntati in sola lettura, è u cluster pruvisoriu hè sguassatu à a fine,
sia ch’ella passi sia ch’ella fallisca.
Stabilite QUIRE_DRILL_REPORT à un percorsu per scrive un rapportu JSON, ch’ella passi o
fallisca, è pianificate l’eserciziu da l’host Docker:
Eseguite lu ogni mese è nanzu à ogni aghjurnamentu. Una prova fallita impedisce l’aghjurnamentu.
Una volta à u trimestre, fate chì qualchissia chì ùn hà micca scrittu stu manuale eseguisca una
risturazione vera à un mumentu precisu nant’à un host di riserva, aduprendu solu stu ducumentu.
Schedarii
I schedarii lucali sò in u volume files. Fate ne una copia di salvezza à tempu chè a basa di dati,
è risturate tramindui inseme:
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 .
Cù un almacenamentu d’ogetti, attivate e versioni di bucket è cunservate 35 ghjorni di
versioni precedenti; a ripresa à un mumentu precisu di i schedarii hè tandu quella propria di u bucket.