14.10 Disk, backup, disaster recovery
บทนี้ครอบคลุมการดูแล disk, กลยุทธ์การสำรองข้อมูล, และแผนกู้คืนจากภัยพิบัติ
สถานะปัจจุบัน
สิ่งสำคัญที่ต้องรับรู้:
- ไม่มี backup strategy ที่เป็นเอกสาร — ต้องสร้างขึ้นมาเอง
- ไม่มี disaster recovery plan — ไม่มี RTO/RPO ที่กำหนด
- ไม่มี off-site backup — ทุกอย่างอยู่ใน host เดียวกับ service
- disk usage ไม่ถูก monitor — ต้องตรวจด้วยตนเอง
- ไม่มี test restore — ไม่เคยทดสอบว่า backup ใช้งานได้จริง
การดูแล disk
การตรวจสอบ disk usage รายวัน
bash
# ดู disk ที่เหลือ
df -h
# ดู directory ที่ใช้ disk มากที่สุด
du -h --max-depth=2 /home/dev/ | sort -hr | head -20
# ดูไฟล์ใหญ่กว่า 100MB
find /home/dev/ -type f -size +100M -exec ls -lh {} \; 2>/dev/nullDirectory ที่โตเร็วที่สุด
| Path | สาเหตุ | การจัดการ |
|---|---|---|
/home/dev/vtrc-api/api-logs/ | wlog เขียนทุกวัน | ลบเก่ากว่า 30 วัน |
/home/dev/vtrc-api/nginx-log/ | access log ทุก request | ลบเก่ากว่า 30 วัน |
/home/dev/vtrc-api/api-storage/prs/ | PDF payslip | ลบเก่ากว่า 30 วัน |
/home/dev/vtrc-api/api-storage/ | file upload ทั่วไป | audit เป็นระยะ |
| Docker container log | stdout/stderr | logrotate หรือ prune |
| Docker images | image เก่า | docker image prune |
/var/lib/docker/ | Docker data | monitor |
สคริปต์ cleanup อัตโนมัติ
bash
cat > /etc/cron.daily/vtrc-cleanup <<'EOF'
#!/bin/bash
set -e
# ลบ log เก่า
find /home/dev/vtrc-api/api-logs/ -mtime +30 -delete
find /home/dev/vtrc-api/nginx-log/ -mtime +30 -delete
find /home/dev/cu-central-api/main-api/logs/ -mtime +30 -delete
# ลบ PDF payslip เก่า
find /home/dev/vtrc-api/api-storage/prs/ -mtime +30 -delete
# prune docker image ที่ไม่ได้ใช้
docker image prune -f
# แจ้งผล
echo "Cleanup completed at $(date)" >> /var/log/vtrc-cleanup.log
EOF
chmod +x /etc/cron.daily/vtrc-cleanupการ monitor disk อัตโนมัติ
bash
cat > /usr/local/bin/check-disk.sh <<'EOF'
#!/bin/bash
THRESHOLD=80
ALERT_EMAIL="ops@redcross.or.th"
df -H | awk -v threshold=$THRESHOLD '
NR>1 && $5+0 > threshold {
print "WARNING: " $5 " usage on " $6 " at " $4
}
' | while read line; do
echo "$line" | mail -s "VTRC Disk Alert" $ALERT_EMAIL
done
EOF
chmod +x /usr/local/bin/check-disk.sh
# รันทุกชั่วโมง
echo "0 * * * * /usr/local/bin/check-disk.sh" | crontab -กลยุทธ์การสำรองข้อมูล
แนวทาง 3-2-1
- 3 สำเนาของข้อมูล
- 2 ประเภทสื่อที่แตกต่างกัน (เช่น disk + tape หรือ disk + cloud)
- 1 สำเนองเก็บนอกไซต์
ปัจจุบันระบบมี 1 สำเนา (บน host เดียวกับ service) — ต้องเพิ่ม
สิ่งที่ต้องสำรอง
| ข้อมูล | วิธี backup | ความถี่ | RPO |
|---|---|---|---|
| MariaDB vtrc schema | mysqldump | ทุกวัน | 24 ชม. |
| MariaDB vtrc-centralize schema | mysqldump | ทุกวัน | 24 ชม. |
| MSSQL HRMI | BACKUP DATABASE | ทุกวัน | 24 ชม. |
| Redis dump | BGSAVE + copy | ทุกวัน | 24 ชม. |
| File storage (PDF, upload) | rsync | ทุกวัน | 24 ชม. |
| nginx config | rsync ไป backup host | ทุกสัปดาห์ | 7 วัน |
| Source code | git (มีอยู่แล้วบน Bitbucket) | ต่อ commit | นาที |
| SSL cert + key | rsync ไปที่เก็บปลอดภัย | ต่อการเปลี่ยน | ตาม |
สคริปต์ backup หลัก
bash
cat > /usr/local/bin/vtrc-backup.sh <<'EOF'
#!/bin/bash
set -e
BACKUP_DATE=$(date +%Y%m%d-%H%M)
BACKUP_ROOT=/backup
BACKUP_DIR=$BACKUP_ROOT/$BACKUP_DATE
mkdir -p $BACKUP_DIR
echo "=== Backup started at $(date) ==="
# 1. MariaDB
echo "Backing up MariaDB..."
mysqldump -h <db-host> -u root -p<password> vtrc | gzip > $BACKUP_DIR/vtrc.sql.gz
mysqldump -h <db-host> -u root -p<password> vtrc-centralize | gzip > $BACKUP_DIR/vtrc-centralize.sql.gz
# 2. Redis
echo "Backing up Redis..."
docker exec vtrc-redis redis-cli BGSAVE
sleep 5
cp /home/dev/vtrc-api/redis-db/data/dump.rdb $BACKUP_DIR/vtrc-redis.rdb
# 3. File storage
echo "Backing up file storage..."
rsync -a /home/dev/vtrc-api/api-storage/ $BACKUP_DIR/api-storage/
# 4. Config
echo "Backing up config..."
tar -czf $BACKUP_DIR/config.tar.gz \
/home/dev/vtrc-api/docker-compose.yml \
/home/dev/vtrc-api/.env \
/home/dev/vtrc-api/nginx/ \
/home/dev/vtrc-api/cert/
# 5. ส่งไปยัง off-site (เช่น GCS)
echo "Uploading to off-site..."
gsutil -m rsync -r $BACKUP_DIR gs://vtrc-backup/$BACKUP_DATE/
# 6. ลบ backup เก่ากว่า 30 วัน (local)
find $BACKUP_ROOT -maxdepth 1 -type d -mtime +30 -exec rm -rf {} \;
# 7. ลบ backup เก่ากว่า 90 วัน (off-site)
gsutil -m rm -r $(gsutil ls gs://vtrc-backup/ | head -n -90)
echo "=== Backup completed at $(date) ==="
EOF
chmod +x /usr/local/bin/vtrc-backup.sh
# รันทุกคืน 02:00
echo "0 2 * * * /usr/local/bin/vtrc-backup.sh >> /var/log/vtrc-backup.log 2>&1" | crontab -การทดสอบ restore
สำคัญมาก — backup ที่ไม่เคยทดสอบ restore ถือว่าไม่มีอยู่จริง
bash
# ทดสอบเดือนละครั้งใน UAT server
# 1. Restore database ไปยัง UAT
mysql -h <uat-db> -u root -p vtrc_test < /backup/vtrc-20250711-0200.sql
# 2. ตรวจสอบ
mysql -h <uat-db> -u root -p vtrc_test -e "SELECT COUNT(*) FROM Users;"
# 3. Restore file storage
rsync -a /backup/api-storage/ /uat/api-storage/
# 4. Start service ใน UAT แล้วทดสอบ
# 5. บันทึกผล
echo "Restore test $(date): ผ่าน" >> /var/log/vtrc-restore-test.logแผนกู้คืนจากภัยพิบัติ (DR plan)
นิยาม
- RTO (Recovery Time Objective) — เวลาสูงสุดที่ระบบสามารถ down ได้หลังเกิดเหตุ
- RPO (Recovery Point Objective) — ปริมาณข้อมูลสูงสุดที่ยอมเสียได้ (วัดเป็นเวลา)
ค่าเป้าหมายที่ควรตั้ง:
| Service | RTO | RPO |
|---|---|---|
| vtrc-api | 4 ชม. | 24 ชม. |
| vtrc-web | 2 ชม. | 24 ชม. (static ไม่ค่อยเปลี่ยน) |
| cu-central-api | 4 ชม. | 24 ชม. |
| centralize-api | 8 ชม. | 24 ชม. (สำคัญน้อยกว่า) |
| database | 2 ชม. | 1 ชม. (critical) |
สถานการณ์วิกฤตที่ต้องวางแผน
สถานการณ์ 1 — Host down
อาการ: production host ไม่สามารถเข้าถึงได้ (hardware fail, OS crash)
ขั้นตอน:
- ตรวจสอบว่าเป็นปัญหาถาวรหรือชั่วคราว
- สร้าง host ใหม่ (อาจใช้ GCP VM แทน on-prem)
- ติดตั้ง Docker, docker-compose
- ดึง image จาก GCR
- Restore database จาก backup ล่าสุด
- Restore file storage
- ปรับ DNS ให้ชี้ไป host ใหม่
- ทดสอบการทำงาน
สถานการณ์ 2 — Database corruption
อาการ: MariaDB ไม่ start หรือ data corrupt
ขั้นตอน:
- หยุด vtrc-api ทุก replica
- สำรอง data ที่เหลืออยู่ (ถ้าเป็นไปได้)
- Drop schema ที่ corrupt
- Restore จาก backup ล่าสุด
- Apply binlog ถ้ามี (เพื่อกู้ข้อมูลหลัง backup)
- Restart vtrc-api
สถานการณ์ 3 — Ransomware / data breach
อาการ: ผู้ไม่ประสงค์ดีเข้าถึงระบบ, encrypt data
ขั้นตอน:
- ตัด network — ปิด external access ทันที
- เก็บ evidence — snapshot disk, log, memory
- แจ้งทีม security และผู้บริหาร
- หยุด service ทั้งหมด
- สำรองข้อมูลที่เหลือ (ถ้ายังไม่ถูก encrypt)
- Wipe host และ rebuild จาก image ใหม่
- Restore data จาก backup off-site
- เปลี่ยน password ทั้งหมด — database, JWT secret, device key, LDAP
- Audit ว่ามีข้อมูลรั่วไหลอะไรบ้าง
- แจ้งผู้ใช้ ถ้ามีข้อมูลส่วนบุคคลรั่วไหล (PDPA obligation)
สถานการณ์ 4 — Data center failure
อาการ: on-prem data center ทั้งหมดไม่ใช้งานได้ (ไฟดับ, อัคคีภัย, อุทกภัย)
ขั้นตอน:
- เปิดใช้งาน DR site (วางแผนไว้ล่วงหน้า)
- Restore service ที่ DR site จาก off-site backup
- ปรับ DNS ให้ชี้ไป DR
- แจ้งผู้ใช้
หมายเหตุ: VTRC ยังไม่มี DR site อย่างเป็นทางการ — ต้องวางแผน
ลำดับการ restore
เมื่อเกิดเหตุและต้อง restore ทั้งระบบ ให้ทำตามลำดับนี้:
- database — MariaDB, MSSQL
- Redis — session, cache
- File storage — PDF, upload
- Backend service — vtrc-api, cu-central-api, centralize-api
- Frontend — vtrc-web, vtrc-rc-backoffice
- External integration — LDAP, KBank, FCM
การสื่อสารตอนเกิดเหตุ
- แจ้งผู้บริหารทันทีเมื่อระบบ down เกิน 15 นาที
- อัปเดตสถานะทุก 30 นาที จนกว่าจะกลับมาปกติ
- หลังเหตุสงบ ทำ postmortem ภายใน 48 ชม.
Postmortem template
หลังเกิดเหตุ ทำ postmortem เพื่อเรียนรู้:
markdown
# Postmortem: <ชื่อเหตุการณ์>
## วันเวลาที่เกิด
- เริ่ม: YYYY-MM-DD HH:MM
- กลับปกติ: YYYY-MM-DD HH:MM
- ระยะเวลา down: X ชม. Y น.
## ผลกระทบ
- ผู้ใช้ที่ได้รับผล: X คน
- Feature ที่ไม่ใช้งานได้: ...
## สาเหตุ
(อธิบาย root cause)
## Timeline
- HH:MM — ตรวจพบ
- HH:MM — เริ่มแก้ไข
- HH:MM — กลับมาปกติ
## สิ่งที่ทำได้ดี
- ...
## สิ่งที่ต้องปรับปรุง
- ...
## Action items
- [ ] ใคร: ทำอะไร ภายในเมื่อใดแนะนำ
- เก็บ backup off-site เสมอ — GCS, S3, หรือ host อื่น
- ทดสอบ restore เดือนละครั้ง — backup ที่ไม่เคย restore test ไม่มีคุณค่า
- เขียน DR runbook ให้ครบ — ทุกคนในทีมต้องทำตามได้
- เก็บ runbook นอก server — ถ้า server down, ต้องยังเข้าถึง runbook ได้
- ทำ chaos engineering — ทดสอบว่าระบบทนต่อ failure ได้แค่ไหน
- กำหนด on-call rotation — ใครรับผิดชอบตอนเกิดเหตุนอกเวลางาน