Reka bentuknya ialah docs/architecture/23-ops.md seksyen 8. Ini ialah buku
panduan untuk produk Docker Compose. Ia ditulis untuk diikuti oleh seseorang yang
tidak menulisnya; jika sesuatu langkah tidak jelas, itu ialah satu kecacatan
dalam dokumen ini.
Apa yang dilindungi, dan bagaimana
Aset
Cara
Di mana
Pangkalan data
WAL diarkibkan berterusan, paling banyak setiap 60 saat, daripada but pertama
Volum pgwal
Pangkalan data
Sandaran asas dengan pg_basebackup, harian secara lalai (backup-scheduler)
Volum pgbackup
Pangkalan data
Salinan bersulit daripada sandaran asas dan WAL, setiap lima minit (backup-offsite)
Sebuah stor berasingan yang anda namakan
Fail
Volum files. Salin dengan alat sandaran hos anda, atau gunakan storan objek berversi
Volum files
Rahsia
docker/.env, di atas segalanya QUIRE_MASTER_KEY (dan mana-mana QUIRE_MASTER_KEY_RETIRED yang masih digunakan), QUIRE_BACKUP_ENCRYPTION_KEY, dan docker/secrets/audit-signing-key.pem
Simpan satu salinan di luar hos ini
Indeks carian, cache, rendition
Tidak disandarkan; dibina semula
Sasaran: satu titik pemulihan dalam 60 saat selepas kegagalan, dan satu pemulihan
dalam 60 minit untuk sebuah pangkalan data 500 GB.
Dua kesilapan adalah biasa. Sebuah pangkalan data yang dipulihkan tanpa failnya
memaparkan halaman yang rosak. Sebuah pangkalan data yang dipulihkan tanpa
QUIRE_MASTER_KEY tidak dapat menyahsulit kelayakan SSO, webhook dan integrasi
yang disimpannya; sehinggalah satu pusingan kunci induk selesai tanpa apa-apa yang
tidak selesai (key-rotation.md), itu termasuk kunci yang bersara.
Kedua-duanya adalah sebahagian daripada sandaran itu.
Mengambil sandaran
Satu sandaran asas untuk seluruh kelompok:
docker compose -f docker/compose.yaml --profile backup run --rm backup
Ia mengekalkan QUIRE_BACKUP_KEEP sandaran asas terbaharu (lalai 5) dan memangkas
WAL yang tidak lagi diperlukan oleh yang paling lama, supaya arkif tidak boleh
membesar tanpa batas. Jadualkannya harian dengan cron atau satu pemasa systemd pada
hos:
15 2 * * * cd /srv/quire && docker compose -f docker/compose.yaml --profile backup run --rm backup >> /var/log/quire-backup.log 2>&1
Atau biarkan tindanan itu menjadualkannya: profil backup menjalankan
backup-scheduler, yang mengambil satu sandaran asas setiap
QUIRE_BACKUP_INTERVAL_HOURS (lalai 24), dan backup-offsite, yang diterangkan
seterusnya.
docker compose -f docker/compose.yaml --profile backup up -d
Salinan bersulit di luar hos
Kedua-dua volum berada pada hos yang sama dengan pangkalan data, dan sebuah sandaran
pada mesin yang gagal bukanlah satu sandaran. backup-offsite menyalin setiap
sandaran asas dan setiap segmen WAL yang diarkibkan ke sebuah stor berasingan
melalui port storan, disulitkan, dan menyimpannya di sana di bawah pengekalan:
Penyulitan. AES-256-GCM dengan QUIRE_BACKUP_ENCRYPTION_KEY (atau fail
yang dinamakan oleh QUIRE_BACKUP_ENCRYPTION_KEY_FILE): 32 bait, daripada
openssl rand -hex 32. Setiap fail mempunyai nonce sendiri dan satu tag
pengesahan, jadi sebuah salinan tidak boleh dibaca tanpa kunci dan sebarang
perubatan kepadanya dikesan. Simpan kunci itu bersama QUIRE_MASTER_KEY, jauh
daripada hos ini dan jauh daripada stor sandaran. Tanpa kunci tiada pemulihan.
Di mana.QUIRE_BACKUP_STORAGE_DRIVER ialah s3, azure atau local
(sebuah cakera jauh yang dilekatkan pada QUIRE_BACKUP_STORAGE_ROOT). Tetapannya
ialah tetapan storan fail dengan awalan QUIRE_BACKUP_:
QUIRE_BACKUP_S3_ENDPOINT, QUIRE_BACKUP_S3_BUCKET,
QUIRE_BACKUP_S3_ACCESS_KEY_ID, dan sebagainya. Guna baldi yang berbeza dan,
sebaiknya, akaun yang berbeza daripada fail, dengan kelayakan yang boleh menulis
tetapi tidak memadam jika pembekal membenarkannya.
Pengekalan.QUIRE_BACKUP_OFFSITE_KEEP sandaran asas terbaharu (lalai
QUIRE_BACKUP_KEEP, selain itu 7) dan WAL yang diperlukan oleh yang paling lama
antaranya; set dan segmen yang lebih lama dipadam daripada stor.
Bila. Setiap QUIRE_BACKUP_SHIP_INTERVAL_SECONDS (lalai 300). Penghantaran
adalah idempoten: apa yang sudah disimpan dilangkau, dan sebuah sandaran asas
dikira sebagai disimpan hanya apabila manifesnya ditulis, terakhir.
Arahan yang sama dijalankan secara manual:
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
Untuk memulihkan pada sebuah hos baharu, bawa satu set kembali terlebih dahulu,
kemudian ikuti langkah-langkah di bawah dengan direktori yang dibawa sebagai ganti
volum pgbackup dan wal-archive yang dibawa sebagai ganti pgwal:
bun apps/worker/src/backups/main.ts fetch base-20260924T021500Z /srv/restore
Memulihkan ke satu titik masa
Guna ini selepas kehilangan data: satu import yang buruk, sebuah kursus yang
dipadam, satu migrasi kontrak yang perlu anda batalkan. Ia menggantikan pangkalan
data langsung, jadi latihkannya dengan latihan di bawah terlebih dahulu.
Pilih masa sasaran, dalam UTC, tepat sebelum kerosakan:
2026-09-24 09:30:00+00. Log audit (/admin/audit) biasanya menunjukkan
saat itu.
Hentikan segala-galanya yang menulis:
docker compose -f docker/compose.yaml stop web content worker scheduler collab
Kekalkan kelompok yang rosak sehingga pemulihan disahkan:
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/
Buka paket sandaran asas terbaharu yang lebih lama daripada masa sasaran
ke dalam volum data, dan minta pemulihan bertarget:
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'
Pulihkan: mulakan Postgres sekali dengan tetapan pemulihan, daripada satu
override Compose supaya fail biasa tidak disentuh:
Override itu menggantikan seluruh perintah, jadi ia mengulang dua tetapan yang
bergantung kepada pemulihan: max_connections tidak lebih rendah daripada
yang utama (selain itu pemulihan dibatalkan dengan “insufficient parameter
settings”) dan pg_hba.conf yang dilekatkan.
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"
Semaknya sebelum membenarkan sesiapa masuk: rantai audit
(docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts),
dan bahawa data yang hilang telah kembali.
Kembali kepada keadaan biasa: docker compose -f docker/compose.yaml up -d.
Ini memulakan semula Postgres dengan pengarkiban hidup, dan satu garis masa WAL
baharu bermula. Ambil satu sandaran asas baharu serta-merta.
Nama projek quire menjadi awalan setiap volum; docker volume ls menunjukkan
nama yang tepat.
Latihan pengesahan berjadual
backup-offsite juga menjalankan satu latihan setiap
QUIRE_BACKUP_DRILL_INTERVAL_HOURS (lalai 168, mingguan), dan sekali lagi pada
laluan seterusnya selepas satu gagal. Ia membawa masuk sandaran asas di luar hos
terbaharu dan setiap segmen WAL selepasnya, menyahsulit setiap satu (yang
membuktikan kunci itu masih membukanya dan tiada apa-apa yang diubah), membandingkan
setiap fail dengan manifesnya, menyemak bahawa arkif itu ialah satu direktori data
Postgres, dan menyemak bahawa WAL daripada sandaran dan seterusnya tiada jurang.
Laporan itu ditulis ke stor sebagai reports/drill-<time>.json dan ke log
perkhidmatan; satu latihan yang gagal menamakan fail itu atau segmen hilang yang
pertama.
Latihan pemulihan
Sebuah sandaran yang tidak pernah dipulihkan bukanlah satu sandaran. Latihan itu
memulihkan sandaran asas lengkap terbaharu yang diambil sebelum masa sasaran,
tambah arkif WAL, ke dalam sebuah Postgres sementara yang tidak berkongsi apa-apa
dengan yang langsung, dan membuktikan hasilnya:
docker/scripts/restore-drill.sh # to ninety minutes agodocker/scripts/restore-drill.sh --target "2026-09-24 09:30:00+00"
Masa sasaran ialah UTC dalam bentuk tepat itu. Ia memerlukan satu sandaran asas
yang lebih lama daripadanya dan WAL yang diarkibkan melampaunya: pada sebuah
pemasangan baharu, ambil satu sandaran asas dan tunggu segmen diarkibkan seterusnya
(paling banyak seminit dengan tulisan) sebelum memilih satu masa sasaran selepas
sandaran itu. Latihan memerlukan Docker dan bash pada hos, tiada apa-apa lagi.
Setiap langkah menggagalkan latihan itu:
Boleh dipulihkan: kelompok sementara itu dimainkan semula ke masa sasaran
dan dibuka.
Kelengkapan: kiraan baris setiap jadual terhadap pangkalan data langsung
(tooling/restore-drill). Pangkalan data langsung telah bergerak sejak masa
sasaran, jadi sebuah jadual mungkin berbeza dengan yang lebih besar antara 500
baris dan sepuluh peratus saiznya, dalam mana-mana arah (tulisan menjadikannya
ketinggalan, pemadaman menjadikan pemulihan memegang lebih); satu sekatan yang
dicipta selepas masa sasaran bukanlah sebuah jadual yang hilang. Luaskan
kelonggaran pada pemasangan yang lebih sibuk dengan QUIRE_DRILL_MAX_BEHIND
dan QUIRE_DRILL_MAX_DRIFT_RATIO. Sebuah jadual yang hilang atau dikosongkan
menggagalkan.
Integriti: rantai hash audit disahkan pada salinan yang dipulihkan.
Kebolehgunaan: peranan aplikasi membaca melalui keselamatan tahap baris.
Masa: daripada mula hingga hijau, berbanding QUIRE_DRILL_RTO_SECONDS
(lalai 3600).
Ia tidak pernah menulis ke pangkalan data langsung atau volumnya: volum sandaran
dan WAL dilekatkan hanya-baca dan kelompok sementara itu dibuang di penghujungnya,
sama ada lulus atau gagal.
Tetapkan QUIRE_DRILL_REPORT kepada satu laluan untuk memiliki satu laporan JSON
ditulis, sama ada lulus atau gagal, dan jalankannya secara berjadual daripada hos
Docker:
Jalankannya setiap bulan dan sebelum setiap naik taraf. Sebuah latihan yang gagal
menyekat naik taraf itu. Sekali setiap suku tahun, minta seseorang yang tidak
menulis buku panduan ini melakukan satu pemulihan titik masa sebenar pada sebuah
hos terbiang, menggunakan dokumen ini sahaja.
Fail
Fail setempat berada dalam volum files. Sandarkannya bersama pangkalan data,
pada masa yang sama, dan pulihkan kedua-duanya bersama:
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 .
Dengan storan objek, hidupkan penghantaran versi baldi dan kekalkan 35 hari versi
bukan semasa; pemulihan pada titik masa untuk fail kemudian ialah milik baldi itu
sendiri.