สารบัญ
- สามแบบที่แบ็กอัปล้มเหลว
- ขั้นที่ 1: สร้างช่องที่เรียกความสนใจคุณได้
- ขั้นที่ 2: จับความล้มเหลวด้วยสคริปต์ห่อคำสั่ง
- borg และ borgmatic
- ขั้นที่ 3: จับแบ็กอัปที่ไม่เคยรัน
- ขั้นที่ 4: ตรวจว่าแบ็กอัปใหม่และกู้คืนได้
- ขั้นที่ 5: ให้ดังเฉพาะเมื่อสำคัญ
- คำถามที่พบบ่อย
- จะรับแจ้งเตือนเมื่อแบ็กอัปล้มเหลวได้อย่างไร
- ควรแจ้งเตือนโค้ดจบการทำงานใดของ restic
- จะรู้ได้อย่างไรว่าแบ็กอัปหยุดรันไปเงียบ ๆ
- โค้ดจบการทำงานที่สำเร็จพอให้เชื่อใจแบ็กอัปไหม
- รับสายโทรเข้าแทนอีเมลได้ไหม
- สรุป
- บทความที่เกี่ยวข้อง
คนส่วนใหญ่รู้ว่าแบ็กอัปของตัวเองพังก็ตอนที่ต้องใช้มันนี่แหละ งานจบด้วยข้อผิดพลาดตั้งแต่สามสัปดาห์ก่อน ไม่มีใครเปิดอ่านล็อก และสแนปช็อตล่าสุดก็เก่ากว่าความผิดพลาดที่คุณกำลังจะย้อนกลับ
ทางแก้ไม่ใช่เครื่องมือแบ็กอัปที่ดีกว่า แต่คือการทำให้ปัญหาของแบ็กอัปไปถึงมนุษย์ภายในชั่วโมงเดียวกับที่มันเกิด คู่มือนี้แสดงวิธีทำกับ restic และ borg (รวมถึงทุกอย่างที่รันจากเชลล์) ครอบคลุมสามแบบที่แบ็กอัปล้มเหลวจริง ๆ พร้อมสคริปต์ที่คัดลอกไปใช้ได้ ขั้นสุดท้ายส่งการแจ้งเตือนไปที่โทรศัพท์ของคุณผ่าน Echobell เพื่อให้แบ็กอัปที่พังทำให้โทรศัพท์ดัง ไม่ใช่นอนอยู่ในกล่องอีเมล
สามแบบที่แบ็กอัปล้มเหลว
ความผิดพลาดที่พบบ่อยที่สุดคือเฝ้าแค่แบบแรกแบบเดียว
- รันแล้วล้มเหลว รีโพซิทอรีถูกล็อก ดิสก์เต็ม รหัสผ่านผิด เครือข่ายหลุด เครื่องมือจบด้วยโค้ดที่ไม่ใช่ศูนย์
- รันแล้วสำเร็จครึ่งเดียว restic จบด้วยโค้ด
3เมื่อสร้างสแนปช็อตได้แต่อ่านบางไฟล์ไม่ได้ ส่วน borg จบด้วย1เมื่อมีคำเตือน ทั้งสองอย่างปัดทิ้งได้ง่าย และทั้งคู่อาจซ่อนปัญหาสิทธิ์ที่ข้ามไดเรกทอรีสำคัญที่สุดของคุณไปเงียบ ๆ - ไม่เคยรันเลย เซิร์ฟเวอร์ดับ ไทเมอร์ถูกปิด crontab ถูกเขียนทับ ไม่มีข้อผิดพลาดเพราะไม่มีโปรเซส นี่คือความล้มเหลวที่ทำให้คนเสียหายหนักที่สุด
แต่ละแบบต้องใช้ตัวตรวจจับคนละอย่าง เราจะสร้างครบทั้งสาม
ขั้นที่ 1: สร้างช่องที่เรียกความสนใจคุณได้
ใน Echobell สร้างช่องชื่อ backups และตั้งประเภทการแจ้งเตือนเป็น โทรเข้า (Calling) สำหรับงานที่สำคัญ แล้วคัดลอก URL เว็บฮุกของช่อง:
https://hook.echobell.one/t/<channel-token>
ใส่เทมเพลตที่อ่านเข้าใจแม้ตอนยังงัวเงีย โดยใช้ฟิลด์ที่เราจะส่งไปด้านล่าง:
หัวเรื่อง: Backup {{status}} on {{host}}
เนื้อหา: {{job}}: {{detail}}
ดูไวยากรณ์ได้ในคู่มืออ้างอิงเทมเพลต
ขั้นที่ 2: จับความล้มเหลวด้วยสคริปต์ห่อคำสั่ง
สคริปต์เล็ก ๆ ที่ห่อคำสั่งไว้จะแปลงโค้ดที่จบการทำงานเป็นการแจ้งเตือน บันทึกเป็น /usr/local/bin/backup-run:
#!/usr/bin/env bash
set -uo pipefail
HOOK="https://hook.echobell.one/t/<channel-token>"
JOB="nightly-restic"
alert() {
curl -fsS -m 10 -X POST "$HOOK" \
-H "Content-Type: application/json" \
-d "{\"job\":\"$JOB\",\"host\":\"$(hostname)\",\"status\":\"$1\",\"detail\":\"$2\"}" || true
}
restic backup /srv /etc --exclude-caches
code=$?
case $code in
0) ;; # สำเร็จ: เงียบไว้
3) alert "incomplete" "Snapshot saved, but some files were unreadable" ;;
11) alert "locked" "Repository is locked by another process" ;;
12) alert "auth-failed" "Wrong repository password" ;;
*) alert "failed" "restic exited with code $code" ;;
esac
exit $code
รายละเอียดที่สำคัญ:
- จงใจ ไม่ใช้
set -eเพื่อให้สคริปต์ยังไปถึงการแจ้งเตือนได้หลัง restic ล้มเหลว || trueหลังcurlทำให้เว็บฮุกที่เข้าถึงไม่ได้ไม่บดบังโค้ดจบการทำงานที่แท้จริง-m 10ป้องกันการเรียกเครือข่ายที่ค้างไม่ให้บล็อกรอบรันถัดไป
โค้ดจบการทำงานของ restic ที่ใช้ข้างบนมีระบุไว้ในคู่มือของ restic: 0 สำเร็จ, 1 ข้อผิดพลาดร้ายแรง, 3 สร้างสแนปช็อตแล้วแต่อ่านบางไฟล์ต้นทางไม่ได้, 10 ไม่มีรีโพซิทอรี, 11 ล็อกไม่สำเร็จ, 12 รหัสผ่านผิด ตรวจสอบกับ restic version บนเครื่องของคุณเอง เพราะมีการเพิ่มโค้ดเข้ามาเรื่อย ๆ
borg และ borgmatic
borg คืนค่า 0 เมื่อสำเร็จ 1 เมื่อมีคำเตือน และ 2 ขึ้นไปเมื่อเกิดข้อผิดพลาด ไฟล์ที่เปลี่ยนระหว่างแบ็กอัปทำให้ได้ 1 ซึ่งเป็นเรื่องปกติของไดเรกทอรีล็อก วิธีที่นิยมคือโทรเรียกเฉพาะ 2 ขึ้นไป และส่งการแจ้งเตือนแบบเงียบสำหรับ 1:
borg create --stats ::'{hostname}-{now}' /srv /etc
code=$?
if [ "$code" -ge 2 ]; then
alert "failed" "borg exited with code $code"
elif [ "$code" -eq 1 ]; then
alert "warning" "borg finished with warnings"
fi
ถ้าใช้ borgmatic ฮุก on_error จะรันคำสั่งเมื่อ borgmatic เองเจอข้อผิดพลาด ซึ่งเป็นที่เหมาะสำหรับ curl ตัวเดิม แต่ให้ระวังข้อจำกัดที่เอกสารของ borgmatic บอกไว้เอง: ถ้า borgmatic ไม่ได้รันเลย on_error ก็ไม่ทำงาน นั่นคือความล้มเหลวแบบที่สาม ซึ่งต้องใช้ขั้นที่ 3
ขั้นที่ 3: จับแบ็กอัปที่ไม่เคยรัน
สคริปต์ห่อคำสั่งรายงานได้เฉพาะรอบที่รันจริง การจับความเงียบต้องกลับตรรกะ: แบ็กอัปส่งสัญญาณไปที่ตัวเฝ้าระวังเมื่อ สำเร็จ และตัวเฝ้าระวังจะแจ้งเตือนคุณเมื่อสัญญาณ มาช้า เรียกว่า dead man's switch
Healthchecks.io (แบบโฮสต์หรือติดตั้งเอง) ทำสิ่งนี้ได้พอดี:
- สร้างเช็กด้วยตารางเวลา
0 3 * * *และเวลาผ่อนผันหนึ่งหรือสองชั่วโมง - ใส่ ping ของเช็กนั้นไว้ท้ายงาน เพื่อให้ยิงเฉพาะเมื่อสำเร็จ
- ในส่วน integrations ของเช็ก เพิ่ม Webhook ที่ชี้ไปที่ URL ช่อง Echobell ของคุณ
ping อยู่ท้ายสคริปต์ห่อคำสั่ง:
# ใน backup-run วางไว้ก่อน `exit $code` บรรทัดสุดท้าย ping เฉพาะเมื่อสำเร็จ
if [ $code -eq 0 ]; then
curl -fsS -m 10 --retry 3 -o /dev/null https://hc-ping.com/<your-uuid>
fi
Healthchecks ยังรองรับ ping แบบ /start และ /fail และรับโค้ดจบการทำงานใน URL ได้ ดังนั้นเช็กเดียวจึงจับงานที่ค้างได้ด้วย ผลลัพธ์คือ เซิร์ฟเวอร์ที่ดับ ไทเมอร์ที่ถูกปิด และบรรทัด crontab ที่ถูกลบ ล้วนจบแบบเดียวกัน คือโทรศัพท์ดัง สำหรับรูปแบบทั่วไปและตัวเฝ้าระวังอื่น ๆ ดูการแจ้งเตือนเมื่อ cron job ล้มเหลว
ขั้นที่ 4: ตรวจว่าแบ็กอัปใหม่และกู้คืนได้
แบ็กอัปอาจรันตามเวลา จบด้วย 0 แล้วก็ยังใช้ไม่ได้ เช่น เมื่อคุณแบ็กอัปไดเรกทอรีว่างเพราะเมานต์ล้มเหลว เพิ่มการตรวจสอบง่าย ๆ สองอย่างในงานรายวันแยกต่างหาก:
อายุของสแนปช็อต แจ้งเตือนถ้าสแนปช็อตล่าสุดเก่ากว่าที่คาดไว้:
latest=$(restic snapshots --latest 1 --json | jq -r '.[0].time')
age_h=$(( ( $(date +%s) - $(date -d "$latest" +%s) ) / 3600 ))
if [ "$age_h" -gt 30 ]; then
alert "stale" "Newest snapshot is ${age_h}h old"
fi
ความสมบูรณ์ของรีโพซิทอรี restic check ตรวจโครงสร้างของรีโพซิทอรี รันสัปดาห์ละครั้ง สำหรับรีโพซิทอรีขนาดใหญ่ restic check --read-data-subset=5% สุ่มตรวจข้อมูลโดยไม่ต้องอ่านทั้งหมด แจ้งเตือนเมื่อจบด้วยโค้ดที่ไม่ใช่ศูนย์
ทั้งสองอย่างแทนการทดสอบกู้คืนจริงไม่ได้ ไตรมาสละครั้ง ลองกู้คืนไฟล์ที่ตรวจสอบได้ไปยังไดเรกทอรีชั่วคราว มันคือการทดสอบเดียวที่พิสูจน์ว่าแบ็กอัปใช้งานได้
ขั้นที่ 5: ให้ดังเฉพาะเมื่อสำคัญ
ถ้าทุกคำเตือนโทรหาคุณ คุณจะปิดเสียงช่อง แล้วมันก็จะไม่ดังในเรื่องที่สำคัญจริง ใช้เงื่อนไขของ Echobell แยกระดับบนช่องเดียว:
status == "failed" || status == "stale" || status == "auth-failed"
ส่ง incomplete และ warning ไปยังช่องที่สอง แบบ สำคัญตามเวลา (Time Sensitive) หรือแบบปกติ เพื่อให้ขึ้นบนหน้าจอล็อกโดยไม่ส่งเสียงเรียก เพิ่มช่วงเวลาได้ถ้าต้องการให้ความล้มเหลวช่วงกลางวันเงียบ โดยใช้ตัวแปร UTC ที่อธิบายไว้ในคู่มืออ้างอิงเงื่อนไข
คำถามที่พบบ่อย
จะรับแจ้งเตือนเมื่อแบ็กอัปล้มเหลวได้อย่างไร
ห่อคำสั่งแบ็กอัป อ่านโค้ดจบการทำงาน และส่งเว็บฮุกเมื่อได้โค้ดที่ไม่ใช่ศูนย์ แล้วเพิ่ม dead man's switch อย่าง Healthchecks.io เพื่อให้รู้เรื่องรอบที่ไม่เคยเริ่มด้วย
ควรแจ้งเตือนโค้ดจบการทำงานใดของ restic
แจ้งเตือนแบบดังสำหรับ 1, 10, 11 และ 12 ซึ่งหมายถึงความล้มเหลวจริง ส่วน 3 (สร้างสแนปช็อตแล้วแต่อ่านบางไฟล์ไม่ได้) ให้ถือเป็นคำเตือนที่ต้องตรวจสอบ เพราะอาจซ่อนปัญหาสิทธิ์
จะรู้ได้อย่างไรว่าแบ็กอัปหยุดรันไปเงียบ ๆ
ใช้ heartbeat: งานส่ง ping ไปที่ตัวเฝ้าระวังเมื่อสำเร็จ และตัวเฝ้าระวังแจ้งเตือนเมื่อ ping มาช้า ฮุกข้อผิดพลาดจับกรณีนี้ไม่ได้ เพราะไม่มีอะไรรันขึ้นมาเพื่อให้เกิดข้อผิดพลาด
โค้ดจบการทำงานที่สำเร็จพอให้เชื่อใจแบ็กอัปไหม
ไม่พอ มันบอกแค่ว่าเครื่องมือทำงานเสร็จ ไม่ได้บอกว่าข้อมูลครบหรือกู้คืนได้ ตรวจอายุสแนปช็อต รันการตรวจความสมบูรณ์เป็นระยะ และทดสอบกู้คืนสม่ำเสมอ
รับสายโทรเข้าแทนอีเมลได้ไหม
ได้ อีเมลพลาดได้ง่าย ช่องแบบโทรเข้าใน Echobell ทำงานเหมือนสายเรียกเข้าและทะลุโหมดโฟกัสของ iOS ได้ ดังนั้นแบ็กอัปที่ล้มเหลวตอนตีสามจะไม่ถูกมองข้าม
สรุป
ตัวตรวจจับสามอย่างครอบคลุมความล้มเหลวสามแบบ: สคริปต์ห่อคำสั่งที่ดูโค้ดจบการทำงานสำหรับรอบที่ล้มเหลว การตรวจความสดใหม่สำหรับรอบที่สำเร็จแต่ใช้ไม่ได้ และ heartbeat สำหรับรอบที่ไม่เคยเกิดขึ้น ส่งทั้งหมดไปที่ช่องแบบโทรเข้า เก็บคำเตือนไว้ในช่องที่เงียบกว่า แล้วแบ็กอัปที่พังจะกลายเป็นงานแก้ห้านาที ไม่ใช่สุดสัปดาห์ที่สูญเปล่า
ดาวน์โหลด Echobell สำหรับ iPhone หรือ รับบน Google Play สร้างช่อง backups แล้วรันสคริปต์ห่อคำสั่งสักครั้งด้วยรหัสผ่านที่ใส่ผิดไว้ เพื่อฟังเสียงมันดัง