રચના docs/architecture/23-ops.md ના વિભાગ 8 માં છે. આ Docker Compose
પ્રોડક્ટ માટેની runbook છે. જે વ્યક્તિએ આ લખ્યું નથી તે અનુસરી શકે એ રીતે લખી છે;
કોઈ પગલું અસ્પષ્ટ હોય તો આ દસ્તાવેજમાં ખામી છે.
શું સુરક્ષિત છે અને કેવી રીતે
સંપત્તિ
રીત
સ્થાન
ડેટાબેઝ
પ્રથમ boot થી સતત WAL archive, વધુમાં વધુ દર 60 સેકન્ડે
pgwal volume
ડેટાબેઝ
pg_basebackup વડે આધાર બેકઅપ, મૂળભૂત રીતે દરરોજ (backup-scheduler)
pgbackup volume
ડેટાબેઝ
આધાર બેકઅપ અને WAL ની એન્ક્રિપ્ટ કરેલી નકલો દર પાંચ મિનિટે (backup-offsite)
તમે પસંદ કરેલો અલગ store
Files
files volume. તમારા host ના backup tool થી નકલ કરો અથવા versioned object storage વાપરો
files volume
Secrets
docker/.env, ખાસ કરીને QUIRE_MASTER_KEY (અને વપરાશમાં હોય તેવી QUIRE_MASTER_KEY_RETIRED), QUIRE_BACKUP_ENCRYPTION_KEY અને docker/secrets/audit-signing-key.pem
આ host ની બહાર નકલ રાખો
Search indexes, caches, renditions
બેકઅપ લેવાતાં નથી; ફરી બનાવાય છે
લક્ષ્યો: નિષ્ફળતા પછી 60 સેકન્ડની અંદરનો recovery point, અને 500 GB ડેટાબેઝ માટે
60 મિનિટની અંદર પુનઃસ્થાપન.
બે ભૂલો વારંવાર થાય છે. Files વિના પુનઃસ્થાપિત ડેટાબેઝ તૂટેલા પાનાં આપે છે.
QUIRE_MASTER_KEY વિના પુનઃસ્થાપિત ડેટાબેઝ તેમાં રહેલા SSO, webhook અને
integration ઓળખપત્રો decrypt કરી શકતું નથી; unresolved કંઈ બાકી ન રહે ત્યાં સુધી
master key rotation પૂર્ણ ન થાય (key-rotation.md), ત્યાં સુધી તેમાં
retired keys પણ આવે છે. બંને બેકઅપનો ભાગ છે.
બેકઅપ લેવું
આખા cluster નો આધાર બેકઅપ:
docker compose -f docker/compose.yaml --profile backup run --rm backup
તે તાજેતરના QUIRE_BACKUP_KEEP આધાર બેકઅપ રાખે છે (મૂળભૂત 5) અને સૌથી જૂનાને હવે
જરૂર ન હોય તે WAL કાઢી નાખે છે, જેથી archive અપરિમિત ન વધે. Host પર 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
અથવા stack ને સમય નક્કી કરવા દો: backup profile backup-scheduler ચલાવે છે, જે
દર QUIRE_BACKUP_INTERVAL_HOURS (મૂળભૂત 24) કલાકે આધાર બેકઅપ લે છે, અને આગળ
વર્ણવેલું backup-offsite પણ ચલાવે છે.
docker compose -f docker/compose.yaml --profile backup up -d
Host ની બહાર એન્ક્રિપ્ટ કરેલી નકલો
બંને volumes ડેટાબેઝવાળા એ જ host પર છે; નિષ્ફળ થયેલા મશીન પરનો બેકઅપ બેકઅપ નથી.
backup-offsite દરેક આધાર બેકઅપ અને દરેક archived WAL segment ને storage port મારફતે
અલગ store માં એન્ક્રિપ્ટ કરીને નકલ કરે છે અને retention નીતિ અનુસાર ત્યાં રાખે છે:
એન્ક્રિપ્શન.QUIRE_BACKUP_ENCRYPTION_KEY વડે AES-256-GCM (અથવા
QUIRE_BACKUP_ENCRYPTION_KEY_FILE દ્વારા દર્શાવેલી file): 32 bytes,
openssl rand -hex 32 માંથી. દરેક file નો પોતાનો nonce અને authentication
tag હોય છે; તેથી key વિના નકલ વાંચી શકાતી નથી અને તેમાં કોઈ ફેરફાર થયો હોય તો
પકડાય છે. Key ને QUIRE_MASTER_KEY સાથે આ host અને backup store થી દૂર રાખો.
Key વિના પુનઃસ્થાપન શક્ય નથી.
સ્થાન.QUIRE_BACKUP_STORAGE_DRIVER નું મૂલ્ય s3, azure અથવા local
( QUIRE_BACKUP_STORAGE_ROOT પર mount કરેલી remote disk) છે. સેટિંગ્સ file storage
વાળી જ છે, ફક્ત આગળ QUIRE_BACKUP_ prefix છે: QUIRE_BACKUP_S3_ENDPOINT,
QUIRE_BACKUP_S3_BUCKET, QUIRE_BACKUP_S3_ACCESS_KEY_ID વગેરે. Files માટેના
bucket થી જુદો અને શક્ય હોય તો જુદો account વાપરો; provider મંજૂરી આપે તો લખી શકે
પણ કાઢી ન શકે એવા credentials રાખો.
Retention. નવા QUIRE_BACKUP_OFFSITE_KEEP આધાર બેકઅપ (મૂળભૂત રીતે
QUIRE_BACKUP_KEEP, નહિતર 7) અને સૌથી જૂનાને જરૂરી WAL રાખાય છે; જૂના sets અને
segments store માંથી કાઢી નાખાય છે.
ક્યારે. દરેક QUIRE_BACKUP_SHIP_INTERVAL_SECONDS (મૂળભૂત 300 સેકન્ડે).
Shipping idempotent છે: પહેલેથી સંગ્રહેલી વસ્તુઓ છોડાય છે, અને આધાર બેકઅપનો
manifest છેલ્લે લખાય ત્યારે જ તેને સંગ્રહાયેલો ગણાય છે.
આ જ આદેશ હાથેથી પણ ચલાવી શકાય છે:
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
નવા host પર પુનઃસ્થાપન માટે પહેલાં એક set પાછો લાવો, પછી નીચેના પગલાંમાં મેળવેલી
directory ને pgbackup volume ના બદલે અને મેળવેલા wal-archive ને pgwal ના બદલે વાપરો:
bun apps/worker/src/backups/main.ts fetch base-20260924T021500Z /srv/restore
ચોક્કસ સમય સુધી પુનઃસ્થાપિત કરવું
ડેટા ગુમાય ત્યારે વાપરો: ખોટો import, કાઢી નાખેલો course, અથવા પાછી ફેરવવાની
જરૂરિયાતવાળી contract migration. આ live ડેટાબેઝ બદલે છે, તેથી પહેલાં નીચેના અભ્યાસથી
રીહર્સલ કરો.
લક્ષ્ય સમય પસંદ કરો, UTC માં, નુકસાન થવાની ક્ષણથી તરત પહેલાંનો:
2026-09-24 09:30:00+00. Audit log (/admin/audit) સામાન્ય રીતે સમય બતાવે છે.
લખતી દરેક વસ્તુ રોકો:
docker compose -f docker/compose.yaml stop web content worker scheduler collab
પુનઃસ્થાપન ચકાસાય ત્યાં સુધી નુકસાન પામેલું cluster રાખો:
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/
લક્ષ્ય સમય પહેલાંનો સૌથી નવો આધાર બેકઅપ data volume માં ખોલો અને નિશાનિત
recovery માગો:
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'
પુનઃપ્રાપ્તિ કરો: સામાન્ય file અસ્પર્શિત રહે તે માટે Compose override માંથી
recovery સેટિંગ સાથે Postgres એક વાર શરૂ કરો:
Override આખો command બદલે છે, તેથી recovery ને જરૂરી બંને સેટિંગ ફરી આપે છે:
max_connections primary કરતાં ઓછું નહીં (નહિતર recovery
“insufficient parameter settings” સાથે અટકે છે) અને mount કરેલું 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"
કોઈને પ્રવેશ આપવા પહેલાં તપાસો: audit chain
(docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts)
અને ગુમાયેલો ડેટા પાછો આવ્યો છે તેની ખાતરી કરો.
સામાન્ય સ્થિતિમાં પાછા ફરો: docker compose -f docker/compose.yaml up -d.
આ Postgres ને archiving ચાલુ રાખીને ફરી શરૂ કરે છે અને નવી WAL timeline શરૂ થાય છે.
તરત જ નવો આધાર બેકઅપ લો.
Project નું નામ quire દરેક volume પહેલાં લાગે છે; ચોક્કસ નામો docker volume ls
બતાવે છે.
નક્કી કરેલો ચકાસણી અભ્યાસ
backup-offsite દર QUIRE_BACKUP_DRILL_INTERVAL_HOURS (મૂળભૂત 168, સાપ્તાહિક)
કલાકે અભ્યાસ પણ ચલાવે છે અને નિષ્ફળતા પછીના આગામી ચક્રમાં ફરી ચલાવે છે. તે સૌથી
નવો host બહારનો આધાર બેકઅપ અને ત્યાર પછીના બધા WAL segments મેળવે છે, દરેકને decrypt
કરે છે (આથી key તેમને ખોલે છે અને તેમાં ફેરફાર થયો નથી તેની ખાતરી થાય છે), દરેક file
ને તેના manifest સાથે સરખાવે છે, archive Postgres data directory છે તે તપાસે છે અને
બેકઅપ પછીથી WAL માં કોઈ ખાલી જગ્યા નથી તેની ખાતરી કરે છે. અહેવાલ store માં
reports/drill-<time>.json તરીકે અને service log માં લખાય છે; નિષ્ફળ અભ્યાસ file અથવા
પહેલો ગુમ થયેલો segment જણાવે છે.
પુનઃસ્થાપન અભ્યાસ
ક્યારેય પુનઃસ્થાપિત ન કરેલો બેકઅપ બેકઅપ નથી. અભ્યાસ સૌથી નવા સંપૂર્ણ આધાર બેકઅપને,
લક્ષ્ય પહેલાંના સમયનો, અને WAL archive ને live ડેટાબેઝથી સંપૂર્ણ અલગ scratch Postgres
માં પુનઃસ્થાપિત કરે છે અને પરિણામ સાબિત કરે છે:
docker/scripts/restore-drill.sh # to ninety minutes agodocker/scripts/restore-drill.sh --target "2026-09-24 09:30:00+00"
લક્ષ્ય ચોક્કસ આ સ્વરૂપમાં UTC હોવું જોઈએ. તેના પહેલાંનો આધાર બેકઅપ અને તેના પછીનો
archived WAL જરૂરી છે: નવા install પર આધાર બેકઅપ લો અને લક્ષ્ય પસંદ કરતાં પહેલાં
આગળનો archived segment આવે ત્યાં સુધી રાહ જુઓ (લખાણ હોય તો વધુમાં વધુ એક મિનિટ).
અભ્યાસ માટે host પર Docker અને bash જોઈએ, બીજું કશું નહીં.
દરેક પગલું અભ્યાસ નિષ્ફળ કરી શકે છે:
પુનઃપ્રાપ્યતા: scratch cluster લક્ષ્ય સમય સુધી replay થઈને ખુલે છે.
સંપૂર્ણતા: live database સામે દરેક table ની row ગણતરી (tooling/restore-drill).
Live database લક્ષ્ય સમય પછી આગળ વધી ગયો હોય છે, એટલે કોઈ table માં બંને દિશામાં
500 rows અથવા તેના કદના દસમા ભાગમાંથી જે મોટું હોય તેટલો તફાવત માન્ય છે (લખાણો
તેને પાછળ રાખે, deletions પુનઃસ્થાપિત નકલમાં વધારે રાખે); લક્ષ્ય પછી બનેલો partition
ગુમાયેલો table નથી. વધુ વ્યસ્ત install માં QUIRE_DRILL_MAX_BEHIND અને
QUIRE_DRILL_MAX_DRIFT_RATIO વડે મર્યાદા વધારો. ગુમ થયેલો અથવા ખાલી કરેલો table
નિષ્ફળ જાય છે.
અખંડિતતા: પુનઃસ્થાપિત નકલ પર audit hash chain ચકાસાય છે.
ઉપયોગિતા: application role row-level security મારફતે વાંચી શકે છે.
સમય: શરૂઆતથી સફળતા સુધી QUIRE_DRILL_RTO_SECONDS સામે તપાસાય છે
(મૂળભૂત 3600).
તે live database અથવા તેના volumes માં ક્યારેય લખતું નથી: backup અને WAL volumes
માત્ર વાંચવા માટે mount થાય છે અને પરિણામ સફળ હોય કે નિષ્ફળ, અંતે scratch cluster
કાઢી નાખાય છે.
QUIRE_DRILL_REPORT ને કોઈ path પર સેટ કરો તો સફળતા કે નિષ્ફળતા બંને સ્થિતિમાં JSON
અહેવાલ લખાય છે; Docker host પરથી schedule કરો:
તે દર મહિને અને દરેક upgrade પહેલાં ચલાવો. નિષ્ફળ અભ્યાસ upgrade અટકાવે છે. દર
ત્રિમાસિક કોઈ એવી વ્યક્તિને, જેણે આ runbook લખી નથી, ફક્ત આ દસ્તાવેજ વાપરીને spare
host પર ખરેખર ચોક્કસ-સમય પુનઃસ્થાપન કરવા કહો.
Files
સ્થાનિક files files volume માં રહે છે. ડેટાબેઝ સાથે એ જ સમયે તેનો બેકઅપ લો અને
બંનેને સાથે પુનઃસ્થાપિત કરો:
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 .
Object storage હોય તો bucket versioning ચાલુ કરો અને 35 દિવસ સુધી જૂની versions
રાખો; પછી files માટે ચોક્કસ-સમય પુનઃપ્રાપ્તિ bucket પોતે સંભાળે છે.