Mục lục
- Ba cách một backup thất bại
- Bước 1: Tạo một kênh đủ sức gây chú ý
- Bước 2: Bắt lỗi bằng một script bao ngoài
- borg và borgmatic
- Bước 3: Bắt backup chưa bao giờ chạy
- Bước 4: Kiểm tra backup còn mới và khôi phục được
- Bước 5: Chỉ đổ chuông khi thật sự cần
- Câu hỏi thường gặp
- Làm sao để được thông báo khi backup thất bại?
- Nên cảnh báo với những mã thoát nào của restic?
- Làm sao biết backup đã âm thầm ngừng chạy?
- Mã thoát thành công có đủ để tin một backup không?
- Tôi có thể nhận cuộc gọi thay vì email không?
- Tổng kết
- Bài liên quan
Phần lớn mọi người chỉ phát hiện backup của mình đã hỏng vào đúng ngày họ cần đến nó. Job đã thoát với lỗi từ ba tuần trước, không ai đọc log, và snapshot mới nhất lại cũ hơn cả sai lầm mà bạn đang muốn hoàn tác.
Giải pháp không phải là một công cụ backup tốt hơn. Giải pháp là bảo đảm vấn đề của backup đến tay một con người ngay trong giờ nó xảy ra. Bài này chỉ cách làm điều đó cho restic và borg (và bất cứ thứ gì chạy từ shell), bao quát ba cách backup thực sự thất bại, kèm các script bạn có thể sao chép. Bước cuối cùng gửi cảnh báo tới điện thoại của bạn qua Echobell, để một backup hỏng sẽ đổ chuông thay vì nằm yên trong hộp thư.
Ba cách một backup thất bại
Chỉ giám sát cách đầu tiên là sai lầm phổ biến nhất.
- Chạy rồi thất bại. Repository bị khóa, đầy đĩa, sai mật khẩu, rớt mạng. Công cụ thoát với mã khác 0.
- Chạy nhưng chỉ thành công một nửa. restic thoát với mã
3khi snapshot đã được tạo nhưng một số file không đọc được. borg thoát với1cho cảnh báo. Cả hai đều dễ bị bỏ qua, và cả hai có thể che giấu một vấn đề về quyền truy cập khiến thư mục quan trọng nhất của bạn bị bỏ sót trong im lặng. - Không bao giờ chạy. Máy chủ đã tắt, timer bị vô hiệu hóa, crontab bị ghi đè. Không có lỗi vì không có tiến trình nào. Đây là kiểu thất bại giết người.
Mỗi kiểu cần một bộ phát hiện khác nhau, nên chúng ta sẽ xây cả ba.
Bước 1: Tạo một kênh đủ sức gây chú ý
Trong Echobell, tạo một kênh tên backups và đặt loại thông báo là Cuộc gọi cho những job quan trọng. Sao chép URL webhook của nó:
https://hook.echobell.one/t/<channel-token>
Hãy đặt template sao cho đọc được cả khi đang ngái ngủ, dùng các trường chúng ta sẽ gửi bên dưới:
Tiêu đề: Backup {{status}} trên {{host}}
Nội dung: {{job}}: {{detail}}
Xem tài liệu tham khảo template để biết cú pháp.
Bước 2: Bắt lỗi bằng một script bao ngoài
Một script bao nhỏ biến mã thoát thành cảnh báo. Lưu nó thành /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) ;; # thành công: giữ im lặng
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
Vì sao các chi tiết này quan trọng:
set -eđược cố ý không dùng, để script vẫn chạy tới phần cảnh báo sau khi restic thất bại.|| trueởcurlnghĩa là webhook không truy cập được sẽ không che mất mã thoát thật.-m 10ngăn một lệnh gọi mạng bị treo chặn lần chạy theo lịch kế tiếp.
Các mã thoát của restic dùng ở trên được ghi trong tài liệu của restic: 0 thành công, 1 lỗi nghiêm trọng, 3 snapshot đã tạo nhưng một số file nguồn không đọc được, 10 repository không tồn tại, 11 không khóa được, 12 sai mật khẩu. Hãy đối chiếu với restic version trên máy của bạn, vì các mã được bổ sung dần theo thời gian.
borg và borgmatic
borg trả về 0 khi thành công, 1 cho cảnh báo và 2 trở lên cho lỗi. Một file thay đổi giữa lúc backup sinh ra 1, điều rất bình thường với thư mục log, nên cách làm phổ biến là chỉ gọi điện từ 2 trở lên và gửi thông báo êm cho 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
Nếu bạn dùng borgmatic, hook on_error của nó chạy một lệnh khi chính borgmatic gặp lỗi, đó là chỗ tự nhiên để đặt cùng lệnh curl. Lưu ý giới hạn mà chính tài liệu borgmatic nêu ra: nếu borgmatic không bao giờ chạy thì on_error không bao giờ kích hoạt. Đó là kiểu thất bại số ba, và nó cần Bước 3.
Bước 3: Bắt backup chưa bao giờ chạy
Một script bao chỉ báo cáo được về lần chạy đã xảy ra. Để bắt sự im lặng, hãy đảo logic: backup ping một monitor khi thành công, và monitor cảnh báo bạn khi ping đến trễ. Cơ chế này gọi là dead man's switch.
Healthchecks.io (hosted hoặc tự host) làm đúng việc này:
- Tạo một check với lịch
0 3 * * *và grace time một hoặc hai giờ. - Thêm ping của nó vào cuối job để chỉ gửi khi thành công.
- Trong phần integration của check, thêm một Webhook trỏ tới URL kênh Echobell của bạn.
Ping được đặt ở cuối script bao:
# trong backup-run, ngay trước `exit $code` cuối cùng; chỉ ping khi thành công
if [ $code -eq 0 ]; then
curl -fsS -m 10 --retry 3 -o /dev/null https://hc-ping.com/<your-uuid>
fi
Healthchecks cũng hỗ trợ các biến thể ping /start và /fail và có thể nhận mã thoát trong URL, nên một check duy nhất còn bắt được cả job bị treo. Kết quả: máy chủ chết, timer bị tắt và dòng crontab bị xóa đều dẫn tới cùng một kết cục, điện thoại đổ chuông. Về mô hình chung và các monitor khác, xem cảnh báo cron job thất bại.
Bước 4: Kiểm tra backup còn mới và khôi phục được
Một backup có thể chạy đúng lịch, thoát với 0, mà vẫn vô dụng, ví dụ khi bạn backup một thư mục rỗng vì mount đã thất bại. Hãy thêm hai kiểm tra rẻ tiền vào một job hằng ngày riêng:
Tuổi của snapshot. Cảnh báo nếu snapshot mới nhất cũ hơn mức bạn mong đợi:
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
Tính toàn vẹn của repository. restic check xác minh cấu trúc repository. Chạy hằng tuần; với repository lớn, restic check --read-data-subset=5% lấy mẫu dữ liệu mà không phải đọc hết. Cảnh báo khi mã thoát khác 0.
Cả hai đều không thay thế được một lần restore thử thật sự. Mỗi quý một lần, hãy khôi phục một file mà bạn có thể kiểm chứng vào một thư mục tạm. Đó là phép thử duy nhất chứng minh backup hoạt động.
Bước 5: Chỉ đổ chuông khi thật sự cần
Nếu cảnh báo nào cũng gọi điện cho bạn, bạn sẽ tắt tiếng kênh, và rồi nó sẽ không reo ở lần quan trọng. Dùng điều kiện của Echobell để tách các tầng trên cùng một kênh:
status == "failed" || status == "stale" || status == "auth-failed"
Gửi incomplete và warning tới một kênh thứ hai loại Nhạy thời gian hoặc thường, để chúng hiện trên màn hình khóa mà không reo. Thêm khung giờ nếu bạn muốn các lỗi ban ngày êm hơn, dùng các biến UTC được mô tả trong tài liệu điều kiện.
Câu hỏi thường gặp
Làm sao để được thông báo khi backup thất bại?
Bao lệnh backup lại, đọc mã thoát và gửi webhook với bất kỳ mã khác 0 nào. Thêm một dead man's switch như Healthchecks.io để bạn cũng biết về những lần chạy chưa bao giờ bắt đầu.
Nên cảnh báo với những mã thoát nào của restic?
Cảnh báo mạnh với 1, 10, 11 và 12, vốn có nghĩa là thất bại thật. Coi 3 (snapshot đã tạo nhưng một số file không đọc được) là cảnh báo cần điều tra, vì nó có thể che giấu vấn đề về quyền truy cập.
Làm sao biết backup đã âm thầm ngừng chạy?
Dùng heartbeat: job ping một monitor khi thành công, và monitor cảnh báo khi ping đến trễ. Một hook lỗi không bắt được trường hợp này vì không có gì chạy để phát sinh lỗi.
Mã thoát thành công có đủ để tin một backup không?
Không. Nó chỉ cho biết công cụ đã chạy xong, chứ không bảo đảm dữ liệu đầy đủ hay khôi phục được. Hãy kiểm tra tuổi snapshot, chạy kiểm tra toàn vẹn định kỳ và thử restore thường xuyên.
Tôi có thể nhận cuộc gọi thay vì email không?
Được. Email rất dễ bị bỏ lỡ. Kênh cuộc gọi trong Echobell hành xử như một cuộc gọi đến và xuyên qua chế độ Tập trung của iOS, nên một backup hỏng lúc 3 giờ sáng vẫn được nhận ra.
Tổng kết
Ba bộ phát hiện bao phủ ba kiểu thất bại: script bao theo mã thoát cho các lần chạy thất bại, kiểm tra độ mới cho các lần chạy thành công nhưng vô dụng, và heartbeat cho các lần chạy không bao giờ xảy ra. Đưa chúng vào một kênh cuộc gọi, để cảnh báo nhẹ ở kênh yên tĩnh hơn, và một backup hỏng sẽ chỉ là việc sửa năm phút thay vì một cuối tuần mất trắng.
Tải Echobell cho iPhone hoặc lấy trên Google Play, tạo kênh backups, rồi chạy script bao một lần với mật khẩu cố tình sai để nghe nó reo.