iT邦幫忙

2026 iThome 鐵人賽

DAY 27
0
Kubernetes

從零到一:使用 K8S + GitOps 打造異構技術棧的資料分析平台系列 第 27

[Day 27] 災難恢復:K8S 叢集備份與數據復原策略 —— 面對最壞的情況,我們如何快速重建整套 BI 平台。

  • 分享至 

  • xImage
  •  

Day 27: 災難恢復:K8S 叢集備份與數據復原策略

面對最壞的情況,我們如何快速重建整套 BI 平台。

1. 為什麼需要備份策略

K8S 的宣告式特性讓「重建服務本身」變得容易——只要 Git repo 還在,kubectl apply 或 ArgoCD 就能把 Deployment、Service 這些資源原樣生出來。但這解決不了資料的問題:資料庫裡的實際內容、PVC 裡的檔案,這些是叢集「聲明」不出來的狀態,一旦遺失就是真的沒了。備份策略要解決的正是這一塊。

2. Velero 的角色

Velero 是 K8S 生態圈常見的備份工具,能把一個 Namespace 下的所有資源定義(Deployment、Service、ConfigMap、PVC 等)連同 PV 的實際內容打包,存到物件儲存(S3 或相容服務)。復原時反向操作,把整包定義與資料還原到叢集(同一個或另一個)。

本機測試用 MinIO 當 S3 相容的備份目標:

helm install minio minio/minio --namespace velero --set mode=standalone

velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.11.0 \
  --bucket velero-backups \
  --use-node-agent \
  --backup-location-config region=minio,s3ForcePathStyle=true,s3Url=http://minio.velero.svc.cluster.local:9000

--use-node-agent 會在每個節點部署一個 DaemonSet,負責執行檔案系統層級的卷備份(底層用 Kopia 或 Restic)。

3. 實測:完整的備份與復原流程

postgres 裡插入一筆標記資料,備份,然後模擬「手殘刪除」整組資源:

$ velero backup create wafer-bi-daily-backup --include-namespaces k8sdemo \
    --default-volumes-to-fs-backup --wait
Backup completed with status: Completed

$ kubectl delete deployment postgres && kubectl delete pvc postgres-pvc && kubectl delete svc postgres-service
deployment.apps "postgres" deleted
persistentvolumeclaim "postgres-pvc" deleted
service "postgres-service" deleted

postgres 的 Deployment、Service、PVC 定義全部消失。執行復原:

$ velero restore create wafer-bi-restore-01 --from-backup wafer-bi-daily-backup --wait
Restore completed with status: Completed

4. 一個真實的限制:hostPath 卷不支援檔案系統備份

過程中發現一個問題:kubectl get pvc 顯示 PVC 恢復了,但 Pod 一直卡在 Pendingdescribe 顯示綁定的 PV 名稱已經不存在。檢查備份日誌找到真正的原因:

Volume pgdata in pod k8sdemo/postgres-... is a hostPath volume
which is not supported for pod volume backup, skipping

Docker Desktop 的預設 StorageClass 是用 hostPath 供應 PV 的,而 Velero 的檔案系統備份機制(Kopia/Restic)明確不支援 hostPath 卷——這是本機開發叢集特有的限制。在真正 CSI 驅動卷的環境(例如 OKE 的 Block Volume、AWS 的 EBS)用的是真正的塊儲存,Velero 對 CSI 卷有原生的 snapshot 支援,理論上不會遇到這個問題,但目前還沒有實際的雲端環境可以驗證(Day 9 提過,雲端部署暫時擱置)。

這提醒了一件事:本機測試通過,不代表雲端環境行為一致——存儲後端的實作方式差異,可能導致同一套備份流程在不同環境下的行為完全不同。真的上雲之後,務必針對目標環境的實際存儲類型重新驗證一次,不能直接假設本機測過就沒事。

5. 補上資料庫層的備份

Velero 的檔案系統備份是「整顆卷」等級的備份,而資料庫這類工作負載,業界更常見的做法是額外搭配應用層級的邏輯備份(pg_dump/pg_restore),原因有二:不受限於卷的儲存後端類型,而且復原時可以做到「只還原某幾張表」的精細度,而不是整顆卷一次全上。

$ kubectl exec deploy/postgres -- pg_dump -U waferbi waferbi_db > waferbi_backup.sql

# 復原後的資料庫是全新空的
$ kubectl exec deploy/postgres -- psql -U waferbi -d waferbi_db -c "\dt"
Did not find any relations.

# 灌回備份內容
$ cat waferbi_backup.sql | kubectl exec -i deploy/postgres -- psql -U waferbi -d waferbi_db

$ kubectl exec deploy/postgres -- psql -U waferbi -d waferbi_db -c "SELECT id, username, name FROM users;"

完整實測畫面:

https://ithelp.ithome.com.tw/upload/images/20260829/20182549icohRQEFJm.png

▲ Velero 災難復原實測:插入標記資料 → 備份 → 刪除全部 postgres 資源 → 復原 → 標記資料確實回來,中間記錄了 hostPath 限制的真實排查過程

備份時間點之後才插入的 dr-test-user 標記資料,在整個刪除又復原的流程走完後依然存在——這證明備份確實涵蓋了完整內容,而不是只有結構。

6. 小結

Velero 負責 K8S 資源定義的備份與復原,資料庫這類有狀態工作負載額外用 pg_dump 補上一層應用層備份,兩者互補。同時也踩到了一個環境相依的真實限制——本機測試環境跟正式環境的存儲後端不同,備份行為可能不一樣,這點在制定 DR 策略時要納入考量。明天討論資源調優:如何根據 Java 與 Python 各自的特性設定合理的資源限制。


上一篇
[Day 26] 資料庫演進:在 K8S 上使用 Liquibase 管理 DB 遷移 —— 自動化更新資料庫 Schema,告別手動執行 SQL 的風險。
下一篇
[Day 28] 效能調優:JVM 與 Python 容器的資源限制與優化 —— 針對異構語言特性,調整 K8S 資源分配以達到最佳效能。
系列文
從零到一:使用 K8S + GitOps 打造異構技術棧的資料分析平台30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言