ຂ້າມໄປຫາເນື້ອຫາ

ການສຳຮາງ, ການຟື້ນຟູຕາມຈຸດເວລາ ແລະ ການຝຶກການກູ້ຄືນ

ສຳຮາງ Quire, ຟື້ນຟູມັນໄປຫາຈຸດໜຶ່ງໃນເວລາ, ແລະ ພິສູດມັນດ້ວຍການຝຶກການກູ້ຄືນ.

ເບິ່ງໃນຮູບແບບ Markdown

ດີຊາຍນແມ່ນ docs/architecture/23-ops.md ບົດທີ 8. ນີ້ແມ່ນ runbook ສຳລັບຜະລິດຕະພັນ Docker Compose. ມັນຖືກຂຽນເພື່ອໃຫ້ຄົນທີ່ບໍ່ໄດ້ ຂຽນມັນດຳເນີນຕາມ; ຖ້າຂັ້ນຕອນໜຶ່ງບໍ່ຊັດເຈນ ນັ້ນແມ່ນຂໍ້ບົກ ຜ່ອງໃນເອກະສານສະບັບນີ້.

ສິ່ງທີ່ຖືກປົກປ້ອງ ແລະ ວິທີ

ຊັບພະຍາກອນ ວິທີ ບ່ອນ
ຖານຂໍ້ມູນ WAL ຈັດເກັບຕໍ່ເນື່ອງ, ທຸກໆ 60 ວິນາທີສູງສຸດ, ນັບແຕ່ການບູດຄັ້ງທຳອິດ volume pgwal
ຖານຂໍ້ມູນ base backups ດ້ວຍ pg_basebackup, ປະຈຳມື້ໂດຍຄ່າເລີ່ມຕົ້ນ (backup-scheduler) volume pgbackup
ຖານຂໍ້ມູນ ສຳເນົາທີ່ລະຫັດຂອງ base backups ແລະ WAL, ທຸກໆ 5 ນາທີ (backup-offsite) ຮ້ານເກັບແຍກທີ່ທ່ານຕັ້ງຊື່
ໄຟລ໌ volume files. ຄັດລອກມັນດ້ວຍເຄື່ອງມືສຳຮາງຂອງເຊີບເວີຂອງທ່ານ ຫຼື ໃຊ້ການເກັບ object ທີ່ມີເວີຊັນ volume files
ຄວາມລັບ docker/.env, ເໜືອທຸກຢ່າງ QUIRE_MASTER_KEY (ແລະ QUIRE_MASTER_KEY_RETIRED ໃດໆທີ່ຍັງໃຊ້ຢູ່), QUIRE_BACKUP_ENCRYPTION_KEY, ແລະ docker/secrets/audit-signing-key.pem ເກັບສຳເນົາໄວ້ນອກເຊີບເວີນີ້
index ການຄົ້ນຫາ, caches, renditions ບໍ່ສຳຮາງ; ສ້າງຄືນ

ເປົ້າໝາຍ: ຈຸດຟື້ນຟູພາຍໃນ 60 ວິນາທີຂອງຄວາມລົ້ມແຫຼວ, ແລະ ການຟື້ນຟູພາຍໃນ 60 ນາທີສຳລັບຖານຂໍ້ມູນ 500 GB.

ຄວາມຜິດສອງຢ່າງແມ່ນເລື້ອຍ. ຖານຂໍ້ມູນທີ່ຟື້ນຟູ ໂດຍບໍ່ມີ ໄຟລ໌ຂອງມັນ ສະແດງໜ້າທີ່ຫັກເສຍ. ຖານຂໍ້ມູນທີ່ຟື້ນຟູ ໂດຍບໍ່ມີ QUIRE_MASTER_KEY ບໍ່ສາມາດຖອກລະຫັດລະຫັດເຂົ້າ ເຖິງ SSO, webhook ແລະ ລະຫັດເຂົ້າເຖິງຂອງການເຊື່ອມຕໍ່ທີ່ມັນ ຖືກໄວ້; ຈົນກວ່າການປ່ຽນ master key ຈະສຳເລັດໂດຍບໍ່ມີຫຍັງ ຄ້າງ (key-rotation.md), ນັ້ນລວມທັງກະແຈ ທີ່ຫຍັກລົບແລ້ວ. ທັງສອງເປັນສ່ວນໜຶ່ງຂອງການສຳຮາງ.

ການເອົາການສຳຮາງ

base backup ຂອງ cluster ທັງໝົດ:

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

ມັນຮັກສາ base backups ໃໝ່ສຸດ QUIRE_BACKUP_KEEP (ຄ່າເລີ່ມຕົ້ນ 5) ແລະ ຕັດ WAL ທີ່ base backup ເກົ່າສຸດບໍ່ຕ້ອງການອີກ ດັ່ງນັ້ນ ສະຖານທີ່ເກັບບໍ່ສາມາດຂະຫຍາຍໂດຍບໍ່ມີຂີດຈຳກັດ. ຕາຕະລາປັບ ມັນປະຈຳມື້ດ້ວຍ 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 ຕາຕະລາປັບມັນ: profile backup ແລ່ນ backup-scheduler, ເຊິ່ງເອົາ base backup ທຸກ QUIRE_BACKUP_INTERVAL_HOURS (ຄ່າເລີ່ມຕົ້ນ 24), ແລະ backup-offsite ທີ່ຈະອະທິບາຍຕໍ່ໄປ.

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

ສຳເນົານອກເຊີບເວີທີ່ລະຫັດ

volume ທັງສອງຢູ່ເຊີບເວີດຽວກັນກັບຖານຂໍ້ມູນ ແລະການສຳຮາງ ຢູ່ເຄື່ອງທີ່ລົ້ມແຫຼວບໍ່ແມ່ນການສຳຮາງ. backup-offsite ຄັດລອກ base backup ທຸກໆອັນ ແລະ segment WAL ທີ່ຈັດເກັບທຸກໆອັນໄປຮ້ານ ເກັບແຍກຜ່ານ storage port, ທີ່ລະຫັດ, ແລະ ເກັບພວກມັນໄວ້ ທີ່ນັ້ນພາຍໃຕ້ retention:

  • ການລະຫັດ. AES-256-GCM ດ້ວຍ QUIRE_BACKUP_ENCRYPTION_KEY (ຫຼືໄຟລ໌ທີ່ QUIRE_BACKUP_ENCRYPTION_KEY_FILE ລະບຸ): 32 ໂບຍ, ຈາກ openssl rand -hex 32. ໄຟລ໌ແຕ່ລະອັນມີ nonce ເອງ ແລະ authentication tag ຂອງຕົນ ດັ່ງນັ້ນສຳເນົາໜຶ່ງອ່ານ ບໍ່ໄດ້ໂດຍບໍ່ມີກະແຈ ແລະການປ່ຽນແປງໃດໆກັບມັນຈະຖືກ ຈັບໄດ້. ເກັບກະແຈໄວ້ກັບ QUIRE_MASTER_KEY, ຫ່າງຈາກ ເຊີບເວີນີ້ ແລະຫ່າງຈາກຮ້ານສຳຮາງ. ໂດຍບໍ່ມີກະແຈບໍ່ມີ ການຟື້ນຟູ.
  • ບ່ອນໃດ. QUIRE_BACKUP_STORAGE_DRIVER ແມ່ນ s3, azure ຫຼື local (ດິດທາງໄກທີ່ mount ໄວ້ທີ່ QUIRE_BACKUP_STORAGE_ROOT). ການຕັ້ງຄ່າແມ່ນການຕັ້ງຄ່າ ໄຟລ໌ເກັບພ້ອມປ້າຍເບື້ອງຕົ້ນ QUIRE_BACKUP_: QUIRE_BACKUP_S3_ENDPOINT, QUIRE_BACKUP_S3_BUCKET, QUIRE_BACKUP_S3_ACCESS_KEY_ID, ແລະອື່ນໆ. ໃຊ້ bucket ທີ່ແຕກຕ່າງ ແລະໂດຍສະເພາະບັນຊີທີ່ແຕກຕ່າງຈາກໄຟລ໌, ພ້ອມລະຫັດເຂົ້າເຖິງທີ່ສາມາດຂຽນແຕ່ບໍ່ສາມາດລຶບຖ້າ ຜູ້ໃຫ້ບໍລິການອະນຸຍາດ.
  • Retention. base backups ໃໝ່ສຸດ QUIRE_BACKUP_OFFSITE_KEEP (ຄ່າເລີ່ມຕົ້ນ QUIRE_BACKUP_KEEP, ບໍ່ແມ່ນດັ່ງນັ້ນ 7) ແລະ WAL ທີ່ເກົ່າສຸດຂອງພວກມັນຕ້ອງການ; ຊຸດ ແລະ segment ທີ່ເກົ່າກວ່າຈະຖືກລຶບອອກຈາກຮ້ານເກັບ.
  • ເມື່ອໃດ. ທຸກ QUIRE_BACKUP_SHIP_INTERVAL_SECONDS (ຄ່າເລີ່ມຕົ້ນ 300). ການຂົນສົ່ງເປັນ idempotent: ສິ່ງທີ່ ເກັບໄວ້ແລ້ວຈະຖືກຂ້າມ, ແລະ base backup ນັບເປັນສຳເລັດ ແຕ່ເມື່ອ manifest ຂອງມັນຖືກຂຽນແລ້ວ, ສຸດທ້າຍ.

ຄຳສັ່ງດຽວກັນແລ່ນດ້ວຍມື:

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

ເພື່ອຟື້ນຟູໃນເຊີບເວີໃໝ່ ນຳຊຸດກັບມາກ່ອນ, ຈາກນັ້ນດຳເນີນ ຂັ້ນຕອນຂ້າງລຸ່ມດ້ວຍຟັງເດີທີ່ດຶງມາແທນ volume pgbackup ແລະ wal-archive ທີ່ດຶງມາແທນ pgwal:

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

ການຟື້ນຟູຕາມຈຸດເວລາ

ໃຊ້ສິ່ງນີ້ຫຼັງຈາກການສູນເສດຂໍ້ມູນ: ການນຳເຂົ້າທີ່ຜິດ, ຫຼັກສູດທີ່ຖືກລຶບ, ການຍ້າຍ contract ທີ່ທ່ານຕ້ອງການຍົກ ເລີກ. ມັນແທນຖານຂໍ້ມູນທີ່ເຮັດວຽກຢູ່ ດັ່ງນັ້ນຝຶກມັນ ດ້ວຍການຝຶກຂ້າງລຸ່ມກ່ອນ.

  1. ເລືອກເວລາເປົ້າໝາຍ, ໃນ UTC, ກ່ອນຄວາມເສຍຫາຍໜຶ່ງ ນາທີ: 2026-09-24 09:30:00+00. ບັນທຶກການກວດກາ (/admin/audit) ມັກຈະສະແດງຈຸດນັ້ນ.
  2. ຢຸດທຸກສິ່ງທີ່ຂຽນ: docker compose -f docker/compose.yaml stop web content worker scheduler collab
  3. ຮັກສາ cluster ທີ່ເສຍຫາຍ ຈົນກວ່າການຟື້ນຟູຈະຖືກ ກວດສອບ:
    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. ແກ້ຊຸດ base backup ໃໝ່ສຸດທີ່ເກົ່າກວ່າເວລາເປົ້າມາຍ ເຂົ້າ volume ຂໍ້ມູນ ແລະ ຂໍການຟື້ນຟູເປົ້າມາຍ:
    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. ຟື້ນຟູ: ເລີ່ມ Postgres ໜຶ່ງຄັ້ງດ້ວຍການຕັ້ງຄ່າການ ຟື້ນຟູ, ຈາກ Compose override ເພື່ອໃຫ້ໄຟລ໌ປົກກະຕິບໍ່ຖືກ ແຕະ:
    # 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]
    Override ແທນທີ່ຄຳສັ່ງທັງໝົດ ດັ່ງນັ້ນມັນຊ້ຳການຕັ້ງຄ່າ ສອງຢ່າງທີ່ການຟື້ນຟູພັງພາ: max_connections ບໍ່ຕ່ຳກວ່າ ຂອງ primary (ບໍ່ດັ່ງນັ້ນການຟື້ນຟູຈະຍົກເລີກດ້ວຍ “insufficient parameter settings”) ແລະ pg_hba.conf ທີ່ mount ໄວ້.
    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. ກວດສອບມັນ ກ່ອນທີ່ຈະອະນຸຍາດໃຜເຂົ້າ: ເສັ້ນການ ກວດກາ (docker compose -f docker/compose.yaml run --rm worker bun tooling/audit-verify/run.ts), ແລະ ວ່າຂໍ້ມູນທີ່ສູນເສດກັບມາແລ້ວ.
  7. ກັບຄືນສະພາບປົກກະຕິ: docker compose -f docker/compose.yaml up -d. ນີ້ເລີ່ມ Postgres ຄືນພ້ອມການຈັດເກັບເປີດ ແລະ timeline WAL ໃໝ່ໜຶ່ງເລີ່ມຕົ້ນ. ເອົາ base backup ໃໝ່ທັນທີ.

ຊື່ໂຄງການ quire ເປັນປ້າຍເບື້ອງຕົ້ນຂອງແຕ່ລະ volume; docker volume ls ສະແດງຊື່ທີ່ແນ່ນອນ.

ການຝຶກການກວດສອບຕາມຕາຕະລາ

backup-offsite ຍັງແລ່ນການຝຶກທຸກ QUIRE_BACKUP_DRILL_INTERVAL_HOURS (ຄ່າເລີ່ມຕົ້ນ 168, ລາຍອາທິດ), ແລະອີກຄັ້ງໃນການຜ່ານຕໍ່ໄປ ຫຼັງຈາກໜຶ່ງຄັ້ງລົ້ມແຫຼວ. ມັນດຶງ base backup ນອກເຊີບເວີ ໃໝ່ສຸດ ແລະ segment WAL ທຸກໆອັນຫຼັງຈາກມັນ, ຖອກລະຫັດ ແຕ່ລະອັນ (ເຊິ່ງພິສູດວ່າກະແຈຍັງເປີດພວກມັນໄດ້ ແລະບໍ່ມີ ຫຍັງຖືກດັດແປງ), ປຽບທຽບແຕ່ລະໄຟລ໌ກັບ manifest ຂອງມັນ, ກວດສອບວ່າສະຖານທີ່ເກັບເປັນ data directory ຂອງ Postgres, ແລະ ກວດສອບວ່າ WAL ນັບແຕ່ການສຳຮາງເປັນຕົ້ນມາບໍ່ມີຊ່ອງ ຫວ່າງ. ລາຍງານຖືກຂຽນໄປຮ້ານເກັບເປັນ reports/drill-<time>.json ແລະໄປບັນທຶກຂອງບໍລິການ; ການຝຶກ ທີ່ລົ້ມແຫຼວລະບຸຊື່ໄຟລ໌ ຫຼື segment ທຳອິດທີ່ຂາດ.

ການຝຶກການກູ້ຄືນ

ການສຳຮາງທີ່ບໍ່ເຄີຍຖືກຟື້ນຟູບໍ່ແມ່ນການສຳຮາງ. ການຝຶກຟື້ນຟູ base backup ທີ່ຄົບຖ້ວນໃໝ່ສຸດທີ່ເອົາມາກ່ອນເວລາເປົ້າມາຍ, ບວກ WAL archive, ເຂົ້າ Postgres ຊົ່ວຄາວທີ່ບໍ່ແບ່ງປັນຫຍັງ ກັບອັນທີ່ເຮັດວຽກຢູ່, ແລະ ພິສູດຜົນລັບ:

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

ເວລາເປົ້າມາຍແມ່ນ UTC ໃນຮູບແບບນັ້ນເພື່ອແນ່ນອນ. ມັນຕ້ອງການ base backup ທີ່ເກົ່າກວ່າມັນ ແລະ WAL ທີ່ຈັດເກັບເກີນມັນ: ໃນການຕິດຕັ້ງໃໝ່ ເອົາ base backup ແລະ ລໍຖ້າ segment ທີ່ ຈັດເກັບຕໍ່ໄປ (ສູງສຸດໜຶ່ງນາທີຖ້າມີການຂຽນ) ກ່ອນທີ່ຈະ ເລືອກເວລາເປົ້າມາຍຫຼັງການສຳຮາງ. ການຝຶກຕ້ອງການ Docker ແລະ bash ຢູ່ເຊີບເວີ, ບໍ່ມີຫຍັງອື່ນ.

ແຕ່ລະຂັ້ນຕອນຈະເຮັດໃຫ້ການຝຶກລົ້ມແຫຼວ:

  1. ຄວາມສາມາດຟື້ນຟູ: cluster ຊົ່ວຄາວ replay ໄປເຖິງເວລາ ເປົ້າມາຍ ແລະເປີດໄດ້.
  2. ຄວາມຄົບຖ້ວນ: ຈຳນວນແຖວຂອງແຕ່ລະຕາຕະລາງທຽບກັບ ຖານຂໍ້ມູນທີ່ເຮັດວຽກຢູ່ (tooling/restore-drill). ຖານ ຂໍ້ມູນທີ່ເຮັດວຽກຢູ່ໄດ້ເຄື່ອນໜີຈາກເວລາເປົ້າມາຍແລ້ວ ດັ່ງນັ້ນຕາຕະລາງໜຶ່ງອາດແຕກຕ່າງເທົ່າກັບຄ່າທີ່ໃຫຍ່ ກວ່າລະຫວ່າງ 500 ແຖວ ແລະໜຶ່ງສ່ວນສິບຂອງຂະໜາດຂອງມັນ, ໃນທິດທາງໃດກໍ່ໄດ້ (ການຂຽນເຮັດໃຫ້ມັນຊ້າ, ການລຶບ ເຮັດໃຫ້ການຟື້ນຟູຖືກຫຼາຍກວ່າ); partition ທີ່ສ້າງຫຼັງ ເວລາເປົ້າມາຍບໍ່ແມ່ນຕາຕະລາງທີ່ສູນເສດ. ຂະຫຍາຍເກນ ອະນຸຍາດໃນການຕິດຕັ້ງທີ່ຍຸ້ນຍາກກວ່າດ້ວຍ QUIRE_DRILL_MAX_BEHIND ແລະ QUIRE_DRILL_MAX_DRIFT_RATIO. ຕາຕະລາງທີ່ຂາດຫຼືຖືກລ້າງວ່າງຈະລົ້ມແຫຼວ.
  3. ຄວາມຖືກຕ້ອງ: ແສນ hash chain ຂອງການກວດກາຜ່ານການ ກວດສອບໃນສຳເນົາທີ່ຟື້ນຟູແລ້ວ.
  4. ຄວາມໃຊ້ງານ: ບົດບາດແອັບພັກອ່ານຜ່ານການປ້ອງກັນ ຂັ້ນແຖວ.
  5. ເວລາ: ນັບຈາກເລີ່ມຈົນເຂິ່ວ, ທຽບກັບ QUIRE_DRILL_RTO_SECONDS (ຄ່າເລີ່ມຕົ້ນ 3600).

ມັນບໍ່ເຄີຍຂຽນເຂົ້າຖານຂໍ້ມູນທີ່ເຮັດວຽກຢູ່ຫຼື volume ຂອງ ມັນ: volume ຂອງການສຳຮາງ ແລະ WAL ຖືກ mount ເປັນແຕ່ອ່ານ ແລະ cluster ຊົ່ວຄາວຖືກລຶບທີ່ຈຸດຈົກ, ຜ່ານ ຫຼື ບໍ່ຜ່ານ.

ຕັ້ງ QUIRE_DRILL_REPORT ເປັນເສັ້ນທາງເພື່ອໃຫ້ລາຍງານ JSON ຖືກຂຽນ, ຜ່ານ ຫຼື ບໍ່ຜ່ານ, ແລະ ແລ່ນມັນຕາມຕາຕະລາຈາກ Docker host:

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

ແລ່ນມັນທຸກເດືອນ ແລະກ່ອນການອັບເດດທຸກຄັ້ງ. ການຝຶກທີ່ລົ້ມ ແຫຼວກັດການອັບເດດ. ທຸກໜຶ່ງໄຕມາດ, ໃຫ້ຄົນທີ່ບໍ່ໄດ້ຂຽນ runbook ນີ້ດຳເນີນການຟື້ນຟູຕາມຈຸດເວລາແທ້ໆຢູ່ເຊີບເວີ ສຳຮາງ, ໂດຍໃຊ້ເອກະສານສະບັບນີ້ເທົ່ານັ້ນ.

ໄຟລ໌

ໄຟລ໌ທ້ອງຖິ່ນຢູ່ໃນ volume 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 .

ດ້ວຍການເກັບ object ເປີດ bucket versioning ແລະ ຮັກສາ 35 ມື້ ຂອງເວີຊັນທີ່ບໍ່ແມ່ນປັດຈຸບັນ; ການຟື້ນຟູຕາມຈຸດເວລາສຳລັບ ໄຟລ໌ຈາກນັ້ນແມ່ນຂອງ bucketເອງ.

ການນຳທາງ

ພິມເພື່ອຄົ້ນຫາ…

↑↓ ນຳທາງ↵ ເລືອກEsc ປິດ