Архітэктура апісана ў раздзеле 8 docs/architecture/23-ops.md. Гэтая інструкцыя прызначана для прадукту Docker Compose. Яна напісана так, каб ёю мог карыстацца чалавек, які яе не пісаў; калі нейкі крок незразумелы, гэта недахоп дакумента.
Што абаронена і якім чынам
Аб’ект
Як
Дзе
База даных
WAL бесперапынна архівуецца, з інтэрвалам не больш за 60 секунд, пачынаючы з першага запуску
том pgwal
База даных
Базавыя копіі праз pg_basebackup, звычайна штодня (backup-scheduler)
том pgbackup
База даных
Зашыфраваныя копіі базавых копій і WAL кожныя пяць хвілін (backup-offsite)
асобнае сховішча, якое вы задаяце
Файлы
Том files. Скапіруйце яго інструментам рэзервовага капіравання хоста або выкарыстоўвайце аб’ектнае сховішча з версіямі
том files
Сакрэты
docker/.env, асабліва QUIRE_MASTER_KEY (і QUIRE_MASTER_KEY_RETIRED, які яшчэ выкарыстоўваецца), QUIRE_BACKUP_ENCRYPTION_KEY і docker/secrets/audit-signing-key.pem
Захоўвайце копію па-за гэтым хостам
Пошукавыя індэксы, кэшы, вытворныя файлы
Не капіруюцца; ствараюцца нанова
Мэты: кропка аднаўлення не далей чым за 60 секунд да збою і аднаўленне на працягу 60 хвілін для базы даных памерам 500 GB.
Часта здараюцца дзве памылкі. Аднаўленне базы даных без файлаў прыводзіць да зламаных старонак. Аднаўленне базы даных без QUIRE_MASTER_KEY не дазваляе расшыфраваць захаваныя ў ёй уліковыя даныя SSO, webhook і інтэграцый; пакуль ратацыя галоўнага ключа не завершыцца без нявырашаных праблем (key-rotation.md), гэта датычыцца і старых ключоў. Абодва кампаненты павінны быць у рэзервовай копіі.
Стварэнне рэзервовых копій
Стварыце базавую копію ўсяго кластара:
docker compose -f docker/compose.yaml --profile backup run --rm backup
Сістэма пакідае найноўшыя базавыя копіі ў колькасці QUIRE_BACKUP_KEEP (першапачаткова 5) і выдаляе WAL, які больш не патрэбны для найстарэйшай копіі, каб архіў не рос бясконца. Заплануйце запуск штодня праз cron або systemd timer на хосце:
15 2 * * * cd /srv/quire && docker compose -f docker/compose.yaml --profile backup run --rm backup >> /var/log/quire-backup.log 2>&1
Або даручыце гэта стэку: профіль backup запускае backup-scheduler, які стварае базавую копію кожныя QUIRE_BACKUP_INTERVAL_HOURS (першапачаткова 24), і backup-offsite, апісаны далей.
docker compose -f docker/compose.yaml --profile backup up -d
Зашыфраваныя копіі па-за хостам
Абодва тамы знаходзяцца на тым жа хосце, што і база даных, а копія на машыне, якая выйшла са строю, не з’яўляецца рэзервовай. backup-offsite перадае кожную базавую копію і кожны архіваваны сегмент WAL у асобнае сховішча праз порт сховішча, у зашыфраваным выглядзе, і захоўвае іх там паводле палітыкі захавання:
Шыфраванне. AES-256-GCM з QUIRE_BACKUP_ENCRYPTION_KEY (або файлам, зададзеным у QUIRE_BACKUP_ENCRYPTION_KEY_FILE): 32 байты, з openssl rand -hex 32. Кожны файл мае ўласны nonce і тэга аўтэнтыфікацыі, таму копію нельга прачытаць без ключа, а любая змена будзе выяўлена. Захоўвайце ключ разам з QUIRE_MASTER_KEY, але па-за гэтым хостам і асобна ад сховішча копій. Без ключа аднаўленне немагчыма.
Месца.QUIRE_BACKUP_STORAGE_DRIVER — s3, azure або local (падключаны аддалены дыск у QUIRE_BACKUP_STORAGE_ROOT). Параметры такія ж, як для сховішча файлаў, але з прэфіксам QUIRE_BACKUP_: QUIRE_BACKUP_S3_ENDPOINT, QUIRE_BACKUP_S3_BUCKET, QUIRE_BACKUP_S3_ACCESS_KEY_ID і гэтак далей. Выкарыстоўвайце іншы bucket і, па магчымасці, іншы ўліковы запіс, чым для файлаў; уліковыя даныя павінны дазваляць запіс, але не выдаленне, калі правайдар гэта падтрымлівае.
Захаванне. Найноўшыя базавыя копіі ў колькасці QUIRE_BACKUP_OFFSITE_KEEP (першапачаткова значэнне QUIRE_BACKUP_KEEP, а калі яно не зададзена — 7) і патрэбны для іх WAL; старыя наборы і сегменты выдаляюцца са сховішча.
Частата. Кожныя QUIRE_BACKUP_SHIP_INTERVAL_SECONDS секунд (першапачаткова 300). Перадача ідэмпатэнтная: ужо захаванае прапускаецца, а базавая копія лічыцца перададзенай толькі пасля запісу яе маніфеста — апошнім.
Тыя ж каманды можна выканаць уручную:
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
Каб аднавіць сістэму на новым хосце, спачатку вярніце набор копій, а затым выканайце крокі ніжэй, выкарыстоўваючы атрыманую папку замест тома pgbackup, а wal-archive замест pgwal:
bun apps/worker/src/backups/main.ts fetch base-20260924T021500Z /srv/restore
Аднаўленне на пэўны момант часу
Выкарыстоўвайце гэтую працэдуру пасля страты даных: няўдалага імпарту, выдаленага курса або міграцыі кантракта, якую трэба адмяніць. Яна замяняе рабочую базу даных, таму спачатку адрэпетуйце працэс з дапамогай практыкавання ніжэй.
Выберыце час, у UTC, непасрэдна перад пашкоджаннем: 2026-09-24 09:30:00+00. Момант звычайна можна знайсці ў журнале аўдыту (/admin/audit).
Спыніце ўсе сэрвісы, якія запісваюць даныя: docker compose -f docker/compose.yaml stop web content worker scheduler collab
Захавайце пашкоджаны кластар, пакуль не праверыце аднаўленне:
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/
Распакуйце найноўшую базавую копію, старэйшую за мэтавы час, у том даных і ўключыце аднаўленне да зададзенага моманту:
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'
Выканайце аднаўленне: запусціце Postgres адзін раз з наладамі аднаўлення праз перавызначэнне Compose, не змяняючы звычайны файл:
Перавызначэнне замяняе ўсю каманду, таму паўтарыце два параметры, ад якіх залежыць аднаўленне: max_connections не павінна быць меншай, чым на асноўным серверы (інакш аднаўленне спыніцца з памылкай “insufficient parameter settings”), і падключаны файл 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"
Праверце вынік, перш чым пускаць карыстальнікаў: ланцуг аўдыту (docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts) і наяўнасць страчаных даных.
Вярніцеся да звычайнага рэжыму: docker compose -f docker/compose.yaml up -d. Гэта запускае Postgres зноў з уключаным архіваваннем, пачынаецца новая шкала WAL. Адразу стварыце новую базавую копію.
Назва праекта quire дадаецца да назвы кожнага тома; дакладныя назвы пакажа docker volume ls.
Запланаванае практыкаванне праверкі
backup-offsite таксама запускае практыкаванне кожныя QUIRE_BACKUP_DRILL_INTERVAL_HOURS гадзін (першапачаткова 168, штотыдзень), а пасля няўдачы паўтарае яго падчас наступнага запуску. Яно атрымлівае найноўшую базавую копію з-за межаў хоста і ўсе сегменты WAL пасля яе, расшыфроўвае кожны (так правяраецца, што ключ па-ранейшаму працуе і даныя не змяніліся), параўноўвае кожны файл з маніфестам, правярае, што архіў з’яўляецца каталогам даных Postgres, і ўпэўніваецца, што ў WAL пасля копіі няма прабелаў. Справаздача запісваецца ў сховішча як reports/drill-<time>.json і ў журнал сэрвісу; няўдалае практыкаванне ўказвае файл або першы адсутны сегмент.
Практыкаванне аднаўлення
Рэзервовая копія, якую ніколі не аднаўлялі, не з’яўляецца праверанай копіяй. Практыкаванне аднаўляе найноўшую поўную базавую копію, створаную да мэтавага часу, разам з архівам WAL у асобны часовы кластар Postgres, які не мае нічога агульнага з рабочым, і правярае вынік:
docker/scripts/restore-drill.sh # to ninety minutes agodocker/scripts/restore-drill.sh --target "2026-09-24 09:30:00+00"
Мэтавы час задаецца ў UTC менавіта ў такім фармаце. Патрэбна базавая копія, старэйшая за яго, і заархіваваны WAL пасля яго: на новай усталёўцы стварыце базавую копію і дачакайцеся наступнага архіўнага сегмента (пры запісах — не больш за хвіліну), перш чым выбіраць час пасля копіі. Для практыкавання на хосце патрэбныя толькі Docker і bash.
Кожная з наступных праверак можа спыніць практыкаванне:
Магчымасць аднаўлення: часовы кластар прайгравае даныя да мэтавага часу і запускаецца.
Паўната: колькасць радкоў у кожнай табліцы параўноўваецца з рабочай базай (tooling/restore-drill). Рабочая база змянілася пасля мэтавага часу, таму дапушчальная розніца ў кожны бок — большае з 500 радкоў і дзесятай часткі яе памеру (запісы прыводзяць да адставання, выдаленні — да большай колькасці радкоў у адноўленай базе); партыцыя, створаная пасля мэтавага часу, не лічыцца страчанай табліцай. На больш актыўнай усталёўцы павялічце дапушчальную розніцу праз QUIRE_DRILL_MAX_BEHIND і QUIRE_DRILL_MAX_DRIFT_RATIO. Адсутная або пустая табліца прыводзіць да памылкі.
Цэласнасць: хэш-ланцуг аўдыту правяраецца ў адноўленай копіі.
Прыдатнасць: роля прыкладання можа чытаць даныя з улікам бяспекі на ўзроўні радкоў.
Час: час ад пачатку да паспяховага выніку параўноўваецца з QUIRE_DRILL_RTO_SECONDS (першапачаткова 3600).
Практыкаванне ніколі не запісвае ў рабочую базу або яе тамы: тамы рэзервовых копій і WAL падключаюцца толькі для чытання, а часовы кластар выдаляецца ў канцы незалежна ад выніку.
Задайце QUIRE_DRILL_REPORT шлях, каб захаваць справаздачу JSON незалежна ад выніку, і запускайце практыкаванне па раскладзе з хоста Docker:
Запускайце яго штомесяц і перад кожным абнаўленнем. Няўдалае практыкаванне блакуе абнаўленне. Раз на квартал даручайце рэальнае аднаўленне на пэўны момант на запасным хосце чалавеку, які не пісаў гэтую інструкцыю, выкарыстоўваючы толькі гэты дакумент.
Файлы
Лакальныя файлы захоўваюцца ў томе files. Капіруйце іх разам з базай даных і аднаўляйце абодва разам:
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 .
Пры выкарыстанні аб’ектнага сховішча ўключыце версіянаванне bucket і захоўвайце неактуальныя версіі 35 дзён; у такім выпадку аднаўленне файлаў на пэўны момант забяспечваецца самім сховішчам.