แจ้งเตือนแบ็กอัปล้มเหลว: รู้ก่อนถึงวันต้องกู้คืน

แบ็กอัปพังเงียบ ๆ ได้หลายสัปดาห์ จับข้อผิดพลาดของ restic และ borg สแนปช็อตเก่า และงานที่ไม่รัน แล้วให้โทรศัพท์ดังเมื่อแบ็กอัปพัง พร้อมสคริปต์คัดลอกใช้ได้

อัปเดตเมื่อ

สารบัญ

คนส่วนใหญ่รู้ว่าแบ็กอัปของตัวเองพังก็ตอนที่ต้องใช้มันนี่แหละ งานจบด้วยข้อผิดพลาดตั้งแต่สามสัปดาห์ก่อน ไม่มีใครเปิดอ่านล็อก และสแนปช็อตล่าสุดก็เก่ากว่าความผิดพลาดที่คุณกำลังจะย้อนกลับ

ทางแก้ไม่ใช่เครื่องมือแบ็กอัปที่ดีกว่า แต่คือการทำให้ปัญหาของแบ็กอัปไปถึงมนุษย์ภายในชั่วโมงเดียวกับที่มันเกิด คู่มือนี้แสดงวิธีทำกับ restic และ borg (รวมถึงทุกอย่างที่รันจากเชลล์) ครอบคลุมสามแบบที่แบ็กอัปล้มเหลวจริง ๆ พร้อมสคริปต์ที่คัดลอกไปใช้ได้ ขั้นสุดท้ายส่งการแจ้งเตือนไปที่โทรศัพท์ของคุณผ่าน Echobell เพื่อให้แบ็กอัปที่พังทำให้โทรศัพท์ดัง ไม่ใช่นอนอยู่ในกล่องอีเมล

สามแบบที่แบ็กอัปล้มเหลว

ความผิดพลาดที่พบบ่อยที่สุดคือเฝ้าแค่แบบแรกแบบเดียว

  1. รันแล้วล้มเหลว รีโพซิทอรีถูกล็อก ดิสก์เต็ม รหัสผ่านผิด เครือข่ายหลุด เครื่องมือจบด้วยโค้ดที่ไม่ใช่ศูนย์
  2. รันแล้วสำเร็จครึ่งเดียว restic จบด้วยโค้ด 3 เมื่อสร้างสแนปช็อตได้แต่อ่านบางไฟล์ไม่ได้ ส่วน borg จบด้วย 1 เมื่อมีคำเตือน ทั้งสองอย่างปัดทิ้งได้ง่าย และทั้งคู่อาจซ่อนปัญหาสิทธิ์ที่ข้ามไดเรกทอรีสำคัญที่สุดของคุณไปเงียบ ๆ
  3. ไม่เคยรันเลย เซิร์ฟเวอร์ดับ ไทเมอร์ถูกปิด 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 (แบบโฮสต์หรือติดตั้งเอง) ทำสิ่งนี้ได้พอดี:

  1. สร้างเช็กด้วยตารางเวลา 0 3 * * * และเวลาผ่อนผันหนึ่งหรือสองชั่วโมง
  2. ใส่ ping ของเช็กนั้นไว้ท้ายงาน เพื่อให้ยิงเฉพาะเมื่อสำเร็จ
  3. ในส่วน 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 แล้วรันสคริปต์ห่อคำสั่งสักครั้งด้วยรหัสผ่านที่ใส่ผิดไว้ เพื่อฟังเสียงมันดัง

บทความที่เกี่ยวข้อง

บทความที่เกี่ยวข้อง

แจ้งเตือนโทรเข้าจาก CloudWatch ไม่ต้องใช้ Lambda หรือ Twilio

SNS โทรเข้าโทรศัพท์ไม่ได้ ส่งต่อ CloudWatch alarm ผ่าน EventBridge ไปยังเว็บฮุกแบบโทรเข้า พร้อมวิธีตั้งค่า ตัวกรอง และข้อควรระวัง

อ่านต่อ

แจ้งเตือนแบบโทรเข้าจาก Sentry สำหรับข้อผิดพลาดร้ายแรง

Sentry ไม่มีแอ็กชันโทรออก ส่ง issue alert ผ่านเว็บฮุกเพื่อให้โทรศัพท์ดังเฉพาะข้อผิดพลาดที่ทำให้โปรดักชันพัง พร้อมวิธีตั้งค่า โครงสร้างข้อมูล และการกรอง

อ่านต่อ

แจ้งเตือน Claude Code ผ่านมือถือด้วย Hooks

รับแจ้งเตือนบนมือถือเมื่อ Claude Code ขออนุญาตหรือทำงานเสร็จ คอนฟิกพร้อมคัดลอกไปใช้ ด้วยฮุก Notification และ Stop ร่วมกับเว็บฮุก

อ่านต่อ