ข้ามไปที่เนื้อหา

การสำรองข้อมูลและการกู้คืน

การสำรองข้อมูล HEMMS ที่สมบูรณ์มี สองส่วน: ฐานข้อมูล Postgres (เรกคอร์ด การตั้งค่า ร่องรอยการตรวจสอบ) และ filestore ของ Odoo (สิ่งแนบ — ไฟล์ ปจป. ที่สแกน PDF สัญญาบริการที่ลงนาม รูปถ่ายเครื่องมือแพทย์) หากคุณสำรองข้อมูลเพียง อย่างใดอย่างหนึ่ง คุณจะกู้คืนได้ไม่ครบถ้วน

หน้านี้ครอบคลุมว่า make backup-private ทำอะไรจริง ๆ วิธีเพิ่ม filestore เข้าไปในการสำรองข้อมูลนั้น วิธีกู้คืน และความถี่ที่ Trinity Roots แนะนำสำหรับการติดตั้งใน production

อะไรบ้างที่ถูกสำรองข้อมูล

สินทรัพย์ อยู่ใน จะสูญเสียอะไรหากหายไป
ฐานข้อมูล วอลุ่ม Postgres (db_private_data / db_gov_data) เรกคอร์ดทั้งหมด: เครื่องมือแพทย์ คำขอ สัญญา audit log ผู้ใช้ สิทธิ์
Filestore วอลุ่ม Odoo (odoo_private_data / odoo_gov_data) path /var/lib/odoo/.local/share/Odoo/filestore/<dbname>/ สิ่งแนบทุกชิ้น: PDF ที่ลงนาม รูปถ่าย ไฟล์ XLSX ที่นำเข้า ฐานข้อมูลอ้างอิงไฟล์เหล่านี้ด้วย hash — หากไม่มี filestore การดาวน์โหลดสิ่งแนบจะคืนค่า 404
Source addons/ Git repo บนดิสก์ โค้ดที่กำหนดเอง — อยู่ใน version control บน GitHub แล้ว ไม่ได้เป็นส่วนหนึ่งของการสำรองข้อมูล
config/*.conf repo บนดิสก์ admin password ข้อมูลรับรองฐานข้อมูล — อยู่ใน version control แล้ว ไม่ได้เป็นส่วนหนึ่งของการสำรองข้อมูล

target สำรองข้อมูลใน Makefile จับเฉพาะฐานข้อมูลเท่านั้น

make backup-private รัน pg_dump และ ไม่ คัดลอก filestore ซึ่งใช้ได้กับฐานข้อมูล demo ที่อายุสั้น (ข้อมูล demo ที่เพาะไว้จะเติม filestore ตอนติดตั้ง) แต่ ไม่เพียงพอ สำหรับ production ดูที่ การเพิ่ม filestore เข้าไปในการสำรองข้อมูล ด้านล่าง

การสำรองฐานข้อมูล — make backup-private

คำสั่งหลัก:

make backup-private    # or make backup-gov

คำสั่งนี้เรียกใช้ scripts/backup_db.sh ซึ่งรัน pg_dump ภายในคอนเทนเนอร์ Postgres และส่งผลลัพธ์ผ่านท่อ ไปยัง gzip:

docker exec hemms_db_private pg_dump -U odoo_private hemms_private \
    | gzip > ./backups/private_<timestamp>.sql.gz

จุดที่ผลลัพธ์ตกลง:

./backups/private_YYYYMMDD_HHMMSS.sql.gz
./backups/gov_YYYYMMDD_HHMMSS.sql.gz

สคริปต์จะสร้าง ./backups/ หากยังไม่มี ไฟล์จะถูกประทับเวลา ถึงระดับวินาที ดังนั้นการสำรองข้อมูลสองครั้งในนาทีเดียวกันจะไม่ชนกัน

Sandbox คอนเทนเนอร์ DB user ชื่อฐานข้อมูล ชื่อไฟล์สำรอง
private hemms_db_private odoo_private hemms_private private_<ts>.sql.gz
gov hemms_db_gov odoo_gov hemms_gov gov_<ts>.sql.gz

การเพิ่ม filestore เข้าไปในการสำรองข้อมูล

สำหรับ production ให้ห่อ make backup-private ด้วยการคัดลอก filestore:

#!/usr/bin/env bash
set -euo pipefail
TS=$(date +%Y%m%d_%H%M%S)
SANDBOX=private
DB=hemms_private
CONTAINER_ODOO=hemms_odoo_private

# 1. DB dump (via the Makefile target)
make backup-${SANDBOX}

# 2. Filestore tarball — read from inside the Odoo container
docker exec ${CONTAINER_ODOO} tar -czf - \
    -C /var/lib/odoo/.local/share/Odoo/filestore ${DB} \
    > ./backups/${SANDBOX}_filestore_${TS}.tar.gz

echo "==> Filestore backup complete: ./backups/${SANDBOX}_filestore_${TS}.tar.gz"

ตอนนี้การสำรองข้อมูลแต่ละครั้งมี สองไฟล์ ที่มีเวลาประทับตรงกัน:

./backups/private_20260523_020005.sql.gz
./backups/private_filestore_20260523_020005.tar.gz

เก็บทั้งสองไว้ด้วยกัน — ต้องกู้คืนเป็นคู่

ขั้นตอนการกู้คืน

การกู้คืนที่สะอาดจะลบฐานข้อมูลที่มีอยู่ สร้างใหม่ replay dump และแตก filestore

การกู้คืนเป็นการทำลายข้อมูล

การกู้คืนจะแทนที่ฐานข้อมูลที่ใช้งานอยู่ ให้สำรองข้อมูลใหม่ก่อน (make backup-private) เพื่อให้คุณ roll forward ได้หากการกู้คืน ผิดพลาด หยุด Odoo ก่อนกู้คืน — การเขียนพร้อมกันระหว่างการกู้คืน จะทำให้ฐานข้อมูลเสียหาย

ขั้นที่ 1 — หยุด Odoo ให้ Postgres ทำงานต่อไป

docker stop hemms_odoo_private
# leave hemms_db_private running

ขั้นที่ 2 — ลบและสร้างฐานข้อมูลใหม่

docker exec -it hemms_db_private psql -U odoo_private -d postgres \
    -c "DROP DATABASE IF EXISTS hemms_private;"
docker exec -it hemms_db_private psql -U odoo_private -d postgres \
    -c "CREATE DATABASE hemms_private OWNER odoo_private;"

ขั้นที่ 3 — replay SQL dump

gunzip -c ./backups/private_20260523_020005.sql.gz \
    | docker exec -i hemms_db_private psql -U odoo_private -d hemms_private

คำสั่งนี้กู้คืนทุกแถวแต่ ไม่ กู้ filestore

ขั้นที่ 4 — กู้คืน filestore

# Wipe the existing filestore for this DB first
docker exec hemms_odoo_private rm -rf \
    /var/lib/odoo/.local/share/Odoo/filestore/hemms_private

# Unpack the tarball into the same parent directory
docker exec -i hemms_odoo_private tar -xzf - \
    -C /var/lib/odoo/.local/share/Odoo/filestore \
    < ./backups/private_filestore_20260523_020005.tar.gz

ขั้นที่ 5 — เริ่ม Odoo ตรวจสอบ

docker start hemms_odoo_private
make logs-private    # watch for "Modules loaded."

เปิด UI เข้าสู่ระบบ และสุ่มตรวจ:

  1. Maintenance → Equipment — จำนวนเรกคอร์ดตรงกับฐานข้อมูลต้นทาง
  2. เปิดสัญญาบริการที่ลงนามแล้วและคลิกที่สิ่งแนบ — ควร ดาวน์โหลดได้ (พิสูจน์ว่า filestore ครบถ้วน)
  3. HA Report → Annual Reports — เปิดรายงานของปีที่แล้วและตรวจสอบว่า PDF render ได้

หากสิ่งแนบขึ้น 404 แสดงว่าการกู้คืน filestore ตกขั้นตอนไป — ทำขั้นที่ 4 ซ้ำ

เมื่อใด ทำอะไร
รายคืน สำรองข้อมูลฐานข้อมูล + filestore ตั้ง cron ให้สคริปต์ที่ห่อไว้ เก็บการสำรองข้อมูลรายวัน 14 ชุด
รายสัปดาห์ เลื่อนการสำรองข้อมูลรายคืนหนึ่งชุดเป็นรายสัปดาห์ เก็บการสำรองข้อมูลรายสัปดาห์ 8 ชุด (≈ 2 เดือน)
รายเดือน เลื่อนการสำรองข้อมูลรายสัปดาห์หนึ่งชุดเป็นรายเดือน เก็บการสำรองข้อมูลรายเดือน 12 ชุด (≈ 1 ปี)
ก่อนการติดตั้ง / อัปเกรดโมดูลทุกครั้ง make backup-private + filestore tarball ทำด้วยมือ ตามที่ต้องการ
ก่อนการทดสอบกู้คืนทุกครั้ง snapshot สถานะที่ใช้งานอยู่ก่อน
รายปี — การซ้อมกู้คืนจากภัยพิบัติ กู้คืนเต็มรูปแบบบน host ที่ไม่ใช่ production วัด RTO บันทึกผล

การสำรองข้อมูลควรถูก คัดลอกออกจาก Docker host ไปยัง object storage (S3, GCS หรือ NFS share บนเครื่องอื่น) การสำรองข้อมูลบนดิสก์เดียวกัน กับฐานข้อมูลที่ใช้งานอยู่จะไม่รอดจากความเสียหายของดิสก์

การซ้อมกู้คืนจากภัยพิบัติ

จัดตารางรายปี การซ้อมจะตอบสองคำถาม: ขั้นตอนการกู้คืน ทำงานได้จริงหรือไม่? และ ใช้เวลานานแค่ไหน?

  1. เลือก host ที่ไม่ใช่ production (แล็ปท็อปหรือ VM ราคาถูก)
  2. โคลน repo make up-private แต่ อย่า make install-private คุณต้องการฐานข้อมูลว่างเพื่อกู้คืนเข้าไป
  3. คัดลอกคู่การสำรองข้อมูลนอกสถานที่ล่าสุดไปยัง ./backups/
  4. รันขั้นตอนการกู้คืนข้างต้นตั้งแต่ต้นจนจบ จับเวลา
  5. ตรวจสอบการสุ่มตรวจในขั้นที่ 5
  6. บันทึก:
    • RTO (recovery time objective) — การกู้คืนใช้เวลานานเท่าไร
    • RPO (recovery point objective) — ช่องว่างระหว่างการสำรองข้อมูลครั้งล่าสุดกับ เวลาที่ซ้อม
    • ขั้นตอนใดก็ตามที่ล้มเหลวหรือทำให้คุณประหลาดใจ — ป้อนกลับเข้าสู่เอกสารนี้

เก็บรายงานการซ้อมไว้กับเอกสาร HA Thailand ของคุณ ผู้ตรวจสอบ HA มองหาหลักฐานว่ามีการซ้อมการกู้คืนจากภัยพิบัติ ไม่ใช่แค่บันทึกไว้

ข้อผิดพลาดที่พบบ่อย

เวอร์ชัน pg_dump ไม่ตรงกัน

หากคุณอัปเกรด Postgres บน host หรือในคอนเทนเนอร์ ไฟล์ dump เก่า ยังคง replay ได้ — แต่ไฟล์ dump ใหม่ ไม่สามารถ replay บน Postgres ที่เก่ากว่าได้ ทำให้เวอร์ชันใหญ่ของเวลาที่ dump และเวลาที่กู้คืน ตรงกัน (ปัจจุบันคือ postgres:15)

การใช้ดิสก์ของ filestore โตขึ้นอย่างเงียบ ๆ

PDF ที่ลงนามทุกไฟล์ รูปถ่าย และ XLSX ที่นำเข้าอยู่ใน filestore ตรวจสอบ docker exec hemms_odoo_private du -sh /var/lib/odoo/.local/share/Odoo/filestore/ เป็นรายเดือน หากโรงพยาบาลอัปโหลดรูปถ่ายเครื่องมือแพทย์ความละเอียด 4K filestore อาจ โตเร็วกว่าฐานข้อมูล

การเข้ารหัสการสำรองข้อมูลสำหรับการจัดเก็บนอกสถานที่

ข้อมูลที่เกี่ยวข้องกับผู้ป่วยอยู่ภายใน HEMMS (หมายเลขซีเรียลเครื่องมือแพทย์ ที่เชื่อมโยงกับหอผู้ป่วย สิ่งแนบ) เข้ารหัสการสำรองข้อมูลขณะพักก่อน ส่งออกจาก host — gpg --symmetric backup.sql.gz เป็นขั้นต่ำ