找回密碼
 立即註冊
惟家LINE群QRCODE
    查看: 0|回覆: 0

    3-2-1 備份原則實際怎麼落地(含自動驗證腳本)

    [複製鏈接]

    !lvup!   100%

    363

    主題

    27

    回帖

    2200萬

    積分

    管理員

    積分
    22005752
    發表於 3 天前 | 顯示全部樓層 |閱讀模式
    大家都聽過 3-2-1 備份,但很少人真的做到。
    更少人驗證過備份能不能還原

    這篇講實作。



    3-2-1 是什麼


    • 3 份資料(1 份正本 + 2 份備份)
    • 2 種不同的媒體
    • 1 份異地


    為什麼是這三個數字


    • 3 份 → 一份壞掉還有兩份
    • 2 種媒體 → 同型號硬碟可能同批次故障
    • 1 份異地 → 火災、竊盜、淹水會一次帶走所有在場的東西


    很多人的現狀


    • HA 有自動備份 ✓
    • 備份存在同一台機器上
    • NAS 有 RAID ✓(但 RAID 不是備份
    • 從來沒試過還原 ✗


    RAID 不是備份這件事要講清楚

    RAID 防的是硬碟故障。它完全防不了:


    • 誤刪檔案(會同步刪掉)
    • 勒索軟體加密(會同步加密)
    • 檔案系統損毀
    • RAID 控制器壞掉
    • 火災、竊盜、淹水
    • 人為操作錯誤


    RAID 是「可用性」,備份是「可恢復性」。兩回事。

    智能家居的實際落地方案

    第 1 份:正本


    • HA 主機的 /config
    • NAS 上的 Docker 設定
    • 路由器設定


    第 2 份:本地自動備份(NAS)
    1. # HA:用 Samba Backup 或 Google Drive Backup 附加元件
    2. # 或者用內建的備份位置設定(2025 之後的版本)
    3. # NAS 上的 Docker 設定:一個腳本
    4. #!/bin/bash
    5. DEST=/volume1/backup/configs/$(date +%F)
    6. mkdir -p "$DEST"
    7. tar czf "$DEST/docker-configs.tar.gz" \
    8.   -C /volume1/docker \
    9.   docker-compose.yml \
    10.   mosquitto/config \
    11.   zigbee2mqtt/data/configuration.yaml \
    12.   zigbee2mqtt/data/coordinator_backup.json \
    13.   zigbee2mqtt/data/database.db \
    14.   frigate/config
    15. # 路由器設定(OpenWrt)
    16. ssh root@192.168.1.1 "sysupgrade -b - " > "$DEST/openwrt.tar.gz"
    17. # 保留 30 天
    18. find /volume1/backup/configs -maxdepth 1 -type d -mtime +30 -exec rm -rf {} +
    複製代碼

    第 3 份:異地

    三個選項:


    • 雲端 —— Google Drive、OneDrive、Backblaze B2、rclone 到任何地方
    • 實體 —— 每個月拉一份到隨身碟,放公司或娘家
    • 朋友家的 NAS —— 互相備份(群暉的 Hyper Backup 支援)


    雲端的加密很重要
    1. # 用 rclone + crypt 遠端,先加密再上傳
    2. rclone sync /volume1/backup/configs crypt-gdrive:ha-backup \
    3.   --transfers 4 --checksum
    複製代碼

    備份裡面有 secrets.yaml 和各種權杖
    明文丟到雲端等於把家裡的鑰匙交出去。



    最重要的一步:驗證(幾乎沒人做)

    沒驗證過的備份等於沒有備份。

    我自己踩過的坑:
    備份檔案每天都有產生,大小看起來也正常 ——
    直到真的要還原時才發現裡面是空的

    原因是 mysqldump 的密碼抓錯,但腳本的離開碼只反映 gzip,
    所以「看起來成功」。

    三層驗證

    第一層:格式
    1. gzip -t backup.tar.gz && echo "格式 OK"
    2. tar tzf backup.tar.gz > /dev/null && echo "可解壓"
    複製代碼

    注意:空輸入壓出來的 20 bytes gz 檔,gzip -t 完全會通過。

    第二層:大小
    1. SIZE=$(stat -c%s backup.tar.gz)
    2. if [ "$SIZE" -lt 1000000 ]; then
    3.     echo "備份太小($SIZE bytes),可能是空的"
    4.     exit 1
    5. fi
    複製代碼

    第三層:內容
    1. # 確認關鍵檔案真的在裡面
    2. for f in configuration.yaml secrets.yaml .storage/core.entity_registry; do
    3.     tar tzf backup.tar.gz | grep -q "$f" || {
    4.         echo "缺少 $f"
    5.         exit 1
    6.     }
    7. done
    8. # 資料庫的話數一下表
    9. zcat db.sql.gz | grep -c "CREATE TABLE"
    複製代碼

    完整的驗證腳本
    1. #!/bin/bash
    2. # /volume1/scripts/verify_backup.sh
    3. set -u
    4. BACKUP_DIR=/volume1/backup/configs
    5. TODAY=$(date +%F)
    6. F="$BACKUP_DIR/$TODAY/docker-configs.tar.gz"
    7. HA_URL="http://192.168.1.50:8123/api/webhook/backup-status-xxxxxxxx"
    8. fail() {
    9.     echo "[FAIL] $1"
    10.     curl -s -X POST -H "Content-Type: application/json" \
    11.       -d "{"status":"fail","reason":"$1"}" "$HA_URL"
    12.     exit 1
    13. }
    14. # 1. 檔案存在
    15. [ -f "$F" ] || fail "今天的備份檔不存在"
    16. # 2. 格式
    17. gzip -t "$F" 2>/dev/null || fail "gzip 格式損毀"
    18. tar tzf "$F" > /dev/null 2>&1 || fail "tar 無法解壓"
    19. # 3. 大小
    20. SIZE=$(stat -c%s "$F")
    21. [ "$SIZE" -gt 100000 ] || fail "檔案太小($SIZE bytes)"
    22. # 4. 內容
    23. LIST=$(tar tzf "$F")
    24. for must in "docker-compose.yml" "mosquitto/config" \
    25.             "zigbee2mqtt/data/coordinator_backup.json"; do
    26.     echo "$LIST" | grep -q "$must" || fail "缺少 $must"
    27. done
    28. # 5. 真的解壓一次到暫存目錄(最徹底)
    29. TMP=$(mktemp -d)
    30. tar xzf "$F" -C "$TMP" 2>/dev/null || fail "解壓失敗"
    31. [ -s "$TMP/docker-compose.yml" ] || fail "docker-compose.yml 是空的"
    32. rm -rf "$TMP"
    33. echo "[OK] 備份驗證通過($SIZE bytes)"
    34. curl -s -X POST -H "Content-Type: application/json" \
    35.   -d "{"status":"ok","size":$SIZE}" "$HA_URL"
    複製代碼

    接進 HA:備份狀態看得見
    1. alias: 備份狀態回報
    2. triggers:
    3.   - trigger: webhook
    4.     webhook_id: backup-status-xxxxxxxx
    5.     allowed_methods: [POST]
    6.     local_only: true
    7. actions:
    8.   - action: input_datetime.set_datetime
    9.     target: {entity_id: input_datetime.last_backup_check}
    10.     data:
    11.       datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
    12.   - if: "{{ trigger.json.status == 'fail' }}"
    13.     then:
    14.       - action: notify.mobile_app_charles
    15.         data:
    16.           title: 備份驗證失敗
    17.           message: "{{ trigger.json.reason }}"
    18.           data:
    19.             push:
    20.               interruption-level: time-sensitive
    21. mode: single
    複製代碼

    再做一個「太久沒驗證」的警報
    1. template:
    2.   - binary_sensor:
    3.       - name: 備份過期
    4.         unique_id: backup_stale
    5.         device_class: problem
    6.         state: >
    7.           {{ (now() -
    8.               (states('input_datetime.last_backup_check') | as_datetime | as_local)
    9.              ).total_seconds() > 172800 }}
    複製代碼

    超過兩天沒有成功驗證就警報。



    每季做一次真的還原演練

    驗證腳本只能確認「檔案看起來沒壞」,
    不能確認「還原之後真的能跑」

    演練方法


    • 在 Proxmox 或 NAS 上開一台測試用的 HA
    • 把最近的備份還原上去
    • 確認:能登入嗎?整合都在嗎?自動化清單完整嗎?
    • 記錄花了多久
    • 測完刪掉


    我第一次演練發現的問題


    • 還原之後所有 Zigbee 裝置是 unavailable
        → 因為 Zigbee 協調器的備份(coordinator_backup.json)沒有在 HA 的備份裡,
        那是 Z2M 的檔案,要另外備份
    • 某個 HACS 整合沒有一起還原
        → 因為我把 custom_components 放進 .gitignore,
        但也忘了確認 HA 備份有沒有包含它


    兩個問題都只有演練才發現得了。

    Zigbee 網路的備份(特別提醒)

    這個最容易漏,而且後果最嚴重。


    • Z2Mdata/coordinator_backup.jsondata/database.db
    • ZHA:在 HA 的 .storage 裡,隨 HA 備份一起走


    沒有這個檔案的話,換協調器或重建系統時,
    幾十個 Zigbee 裝置要全部重新配對
    ——
    而且電池裝置要一個一個去按重置鍵,有些還在天花板上。

    我的排程
    1. 每小時:HA 自動備份(保留最近 3 份)
    2. 每天 03:00:NAS 打包所有設定
    3. 每天 04:00:驗證腳本 + 回報 HA
    4. 每天 05:00:rclone 加密上傳雲端
    5. 每週日:檢查雲端那份的檔案數量和大小
    6. 每月 1 號:手動拉一份到隨身碟
    7. 每季:完整還原演練
    複製代碼

    手動那一步為什麼保留

    全自動的東西有一個共同弱點:你不會去看它

    每個月手動做一次,會逼你確認整條鏈還活著

    ---

    最後一句話:

    備份的價值不在於「有做」,在於「需要的時候真的能用」。

    而那個只能靠演練確認。
    您需要登入後纔可以回帖 登入 | 立即註冊

    本版積分規則

    Archiver|手機版|惟家的智能論壇

    GMT+8, 2026-9-24 10:31 , Processed in 0.076918 second(s), 26 queries .

    快速回覆 返回頂部 返回列表