Salti al enhavo

Sekurkopioj, restarigo al momento kaj restariga provo

Sekurkopii Quire, restarigi al momento kaj pruvi tion per restariga provo.

Vidi kiel Markdown

La dezajno estas en sekcio 8 de docs/architecture/23-ops.md. Jen la runbook por la produkto Docker Compose. Ĝi estas verkita por sekvado de iu neverkinta ĝin; se paŝo estas neklara, tio estas difekto de ĉi tiu dokumento.

Kio estas protektata kaj kiel

Aktivo Kiel Kie
Datumbazo WAL arkivata senĉese, maksimume po 60 sekundoj, ekde unua ekfunkciigo Volumeno pgwal
Datumbazo Bazaj sekurkopioj per pg_basebackup, defaŭlte ĉiutage (backup-scheduler) Volumeno pgbackup
Datumbazo Ĉifritaj kopioj de bazaj sekurkopioj kaj WAL ĉiun kvinan minuton (backup-offsite) Aparta konservejo nomita de vi
Dosieroj Volumeno files. Kopiu per gastiganta sekurkopiilo aŭ uzu versionitan objektostokadon Volumeno files
Sekretoj docker/.env, precipe QUIRE_MASTER_KEY (kaj ĉiu ankoraŭ uzata QUIRE_MASTER_KEY_RETIRED), QUIRE_BACKUP_ENCRYPTION_KEY kaj docker/secrets/audit-signing-key.pem Konservu kopion ekster ĉi tiu gastiganto
Serĉindeksoj, kaŝmemoroj, derivaĵoj Ne sekurkopiataj; rekonstrueblaj

Celoj: reakira punkto ene de 60 sekundoj antaŭ paneo kaj restarigo ene de 60 minutoj por 500 GB-datumbazo.

Du eraroj oftas. Datumbazo restarigita sen siaj dosieroj montras rompitajn paĝojn. Datumbazo restarigita sen QUIRE_MASTER_KEY ne povas malĉifri SSO-, webhook- kaj integrigajn legitimilojn; ĝis rotacio de ĉefa ŝlosilo finiĝas sen nesolvitaj valoroj (key-rotation.md), tio inkluzivas retiriĝintajn ŝlosilojn. Ambaŭ estas parto de sekurkopio.

Fari sekurkopiojn

Baza sekurkopio de tuta grapolo:

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

Ĝi konservas plej novajn QUIRE_BACKUP_KEEP bazajn sekurkopiojn (defaŭlte 5) kaj fortranĉas WAL, kiun la plej malnova ne plu bezonas, por ke arkivo kresku senlime. Planigu ĉiutage per cron aŭ systemd-tempigilo ĉe gastiganto:

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

Aŭ lasu stakon planigi ĝin: profilo backup rulas backup-scheduler, kiu faras bazan sekurkopion ĉiun QUIRE_BACKUP_INTERVAL_HOURS (defaŭlte 24), kaj backup-offsite, priskribitan poste.

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

Ĉifritaj kopioj ekster gastiganto

Ambaŭ volumoj troviĝas ĉe sama gastiganto kiel datumbazo, kaj sekurkopio en paneinta maŝino ne estas sekurkopio. backup-offsite kopias ĉiun bazan sekurkopion kaj ĉiun arkivitan WAL-segmenton al aparta konservejo per stokada pordo, ĉifras ilin kaj konservas laŭ reteno:

  • Ĉifrado. AES-256-GCM per QUIRE_BACKUP_ENCRYPTION_KEY (aŭ dosiero nomita de QUIRE_BACKUP_ENCRYPTION_KEY_FILE): 32 bajtoj el openssl rand -hex 32. Ĉiu dosiero havas propran nonce-on kaj aŭtentikigan etikedon, do kopio estas nelegebla sen ŝlosilo kaj ĉiu ŝanĝo estas detektata. Konservu ŝlosilon kun QUIRE_MASTER_KEY, for de ĉi tiu gastiganto kaj sekurkopiejo. Sen ŝlosilo, restarigo ne eblas.
  • Loko. QUIRE_BACKUP_STORAGE_DRIVER estas s3, azure aŭ local (muntita ekstera disko ĉe QUIRE_BACKUP_STORAGE_ROOT). Agordoj estas la samaj kiel por dosierstokado kun prefikso QUIRE_BACKUP_: QUIRE_BACKUP_S3_ENDPOINT, QUIRE_BACKUP_S3_BUCKET, QUIRE_BACKUP_S3_ACCESS_KEY_ID kaj tiel plu. Uzu alian bucketon kaj ideale alian konton ol por dosieroj; legitimiloj rajtu skribi sed ne forigi, se provizanto tion permesas.
  • Reteno. Plej novaj QUIRE_BACKUP_OFFSITE_KEEP bazaj sekurkopioj (defaŭlte QUIRE_BACKUP_KEEP, alie 7) kaj WAL bezonata de plej malnova; pli malnovaj aroj kaj segmentoj estas forigitaj el konservejo.
  • Kiam. Ĉiun QUIRE_BACKUP_SHIP_INTERVAL_SECONDS (defaŭlte 300). Sendo estas idempotenta: jam stokitaj elementoj estas preterlasataj, kaj baza sekurkopio kalkuliĝas stokita nur post la lasta skribo de ĝia manifesto.

La sama komando ruliĝas permane:

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

Por restarigi ĉe nova gastiganto, unue revenigu aron, poste sekvu paŝojn sube kun elŝutita dosierujo anstataŭ volumeno pgbackup kaj elŝutita wal-archive anstataŭ pgwal:

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

Restarigi al specifa momento

Uzu post datumperdo: malbona importo, forigita kurso, kuntira migrado malfarebla. Tio anstataŭigas aktualan datumbazon, do unue ekzercu per provo sube.

  1. Elektu celtempon en UTC, ĵus antaŭ damaĝo: 2026-09-24 09:30:00+00. Kontrolprotokolo (/admin/audit) kutime montras momenton.
  2. Haltigu ĉion skribantan: docker compose -f docker/compose.yaml stop web content worker scheduler collab
  3. Konservu difektitan grapolon ĝis restarigo estas kontrolita:
    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. Malfaldu plej novan bazan sekurkopion pli fruan ol celo en datumvolumon, kaj petu celitan reakiron:
    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. Reakiru: startigu Postgres unufoje kun reakiro-agordoj, per Compose- superregilo por ne tuŝi normalan dosieron:
    # 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]
    Superregilo anstataŭigas tutan komandon, do ĝi ripetas du agordojn bezonatajn de reakiro: max_connections ne malpli ol ĉe ĉefa datumbazo (alie reakiro ĉesas kun “insufficient parameter settings”) kaj muntita 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. Kontrolu antaŭ ol enlasi iun: kontrolĉenon (docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts) kaj revenon de perdita datumo.
  7. Reiru al normala stato: docker compose -f docker/compose.yaml up -d. Tio restartigas Postgres kun arkivado aktiva, kaj nova WAL-linio komenciĝas. Tuj faru freŝan bazan sekurkopion.

Projekt nomo quire estas prefiksata al volumoj; docker volume ls montras precizajn nomojn.

Planita kontrolprovo

backup-offsite ankaŭ rulas provon ĉiun QUIRE_BACKUP_DRILL_INTERVAL_HOURS (defaŭlte 168, ĉiusemajne), kaj denove ĉe sekva kuro post malsukceso. Ĝi prenas plej novan ekstergastigantan bazan sekurkopion kaj ĉiun WAL-segmenton post ĝi, malĉifras ĉiun (pruvante ke ŝlosilo plu malfermas ilin kaj nenio ŝanĝiĝis), komparas ĉiun dosieron kun manifesto, kontrolas ke arkivo estas Postgres-datumdosierujo kaj kontrolas ke WAL ekde sekurkopio havas neniun truon. Raporto skribiĝas en konservejo kiel reports/drill-<time>.json kaj en servoprotokolo; malsukcesa provo nomas dosieron aŭ unuan mankantan segmenton.

Restariga provo

Sekurkopio neniam restarigita ne estas sekurkopio. Provo restarigas plej novan kompletan bazan sekurkopion faritan antaŭ celo, plus WAL-arkivon, en apartan provan Postgres-on sen kunhavaĵoj kun viva instanco, kaj pruvas rezulton:

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

Celo estas UTC en precize tiu formo. Bezonata estas baza sekurkopio pli frua ol ĝi kaj arkivita WAL posta al ĝi: ĉe nova instalado, faru bazan sekurkopion kaj atendu proksiman arkivitan segmenton (maksimume minuton kun skriboj) antaŭ ol elekti celon post sekurkopio. Provo bezonas Docker kaj bash ĉe gastiganto, nenion alian.

Ĉiu paŝo povas malsukcesigi provon:

  1. Reakireblo: prova grapolo reludas ĝis celo kaj malfermiĝas.
  2. Kompleteco: kalkulo de vicoj de ĉiu tabelo kompare kun viva datumbazo (tooling/restore-drill). Viva datumbazo progresis post celo, do diferenco ĉe tablo povas esti la pli granda el 500 vicoj kaj dekono de ĝia grando, ambaŭdirekte (skriboj igas ĝin malantaŭa; forigoj lasas pli en restarigo); subdisko kreita post celo ne estas perdita tabelo. Plilarĝigu permeson ĉe pli aktiva instalo per QUIRE_DRILL_MAX_BEHIND kaj QUIRE_DRILL_MAX_DRIFT_RATIO. Mankanta aŭ malplenigita tabelo malsukcesas.
  3. Integreco: kontrola haketĉeno validas ĉe restarigita kopio.
  4. Uzeblo: aplikaĵa rolo legas laŭ row-level security.
  5. Tempo: de starto ĝis sukceso, kompare kun QUIRE_DRILL_RTO_SECONDS (defaŭlte 3600).

Ĝi neniam skribas al viva datumbazo aŭ ĝiaj volumoj: sekurkopiaj kaj WAL- volumoj estas muntitaj nurlegeble kaj prova grapolo estas forigita je fino, ĉu sukcese ĉu ne.

Agordu QUIRE_DRILL_REPORT al vojo por skribi JSON-raporton, sukcesan aŭ malsukcesan, kaj rulu laŭ horaro el Docker-gastiganto:

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

Rulu ĉiumonate kaj antaŭ ĉiu ĝisdatigo. Malsukcesa provo blokas ĝisdatigon. Ĉiukvaronjare, petu al iu neverkinta ĉi tiun runbook fari realan restarigon al specifa momento ĉe rezerva gastiganto uzante nur ĉi tiun dokumenton.

Dosieroj

Lokaj dosieroj troviĝas en volumeno files. Sekurkopiu ĝin samtempe kun datumbazo kaj restarigu ambaŭ kune:

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 .

Kun objektostokado, ŝaltu bucketan versionigon kaj konservu 35 tagojn da neaktualaj versioj; tiam la bucketo mem provizas tempopunktan reakiron de dosieroj.

Navigado

Tajpu por serĉi…

↑↓ navigi↵ elektiEsc fermi