實(shí)戰(zhàn):etcd快照與Velero雙保險方案)
自打開始正經(jīng)維護(hù) Kubernetes 集群之后我?guī)缀趺刻於紩煌粋€問題敲打如果哪天 etcd 數(shù)據(jù)盤壞了、誤刪了一個 namespace或者整臺 Master 節(jié)點(diǎn)被清空你到底能不能把集群拉回來我相信絕大多數(shù)人的第一反應(yīng)是有資源清單啊丟了重建不就行了。但真正經(jīng)歷過故障的人會明白這種想法在單機(jī)實(shí)驗(yàn)環(huán)境勉強(qiáng)成立放到生產(chǎn)環(huán)境里基本等于裸奔。因?yàn)榧豪锍?Deployment、Service 這些能kubectl get出來的對象還有大量的配置、密鑰、PVC 里的業(yè)務(wù)數(shù)據(jù)、CRD 資源、RBAC 授權(quán)關(guān)系這些東西一旦丟失想靠人工重建幾乎是不可能完成的任務(wù)。這篇博客就圍繞 Kubernetes 集群備份與恢復(fù)的完整配置與實(shí)踐展開。我會從備份思路講起逐步拆解 etcd 快照和 Velero 這兩套主流方案把命令、參數(shù)、常見坑、恢復(fù)演練的步驟全部攤開講。不管你是在自己搭的測試集群上做實(shí)驗(yàn)還是正在為生產(chǎn)集群設(shè)計(jì)容災(zāi)方案這篇內(nèi)容都能幫你在腦子里建立起一套清晰的備份恢復(fù)框架。先說明一點(diǎn)本文所有操作都基于我實(shí)際在用的集群環(huán)境驗(yàn)證過但版本差異會帶來細(xì)節(jié)上的變化閱讀時請結(jié)合你自己的集群版本做微調(diào)。1. 備份前先把思路理清楚到底要備份什么在動手配置任何工具之前我建議你先完成一輪“靈魂拷問”。因?yàn)閭浞莘桨傅脑O(shè)計(jì)本質(zhì)上是對集群資產(chǎn)做分類分類做不清楚后面所有備份動作都是盲目的。1.1 先問自己三個關(guān)鍵問題第一個問題如果集群徹底無法恢復(fù)你能否在 24 小時內(nèi)重建出所有業(yè)務(wù)這里說的業(yè)務(wù)不只是工作負(fù)載還包括它依賴的配置中心數(shù)據(jù)、數(shù)據(jù)庫內(nèi)容、消息隊(duì)列里的積壓消息、對象存儲桶以及 K8s 集群中的各種自定義資源。第二個問題你的備份是否被人為驗(yàn)證過備份文件存在那里沒有任何意義只有定期做恢復(fù)演練、并且演練成功過備份才算真正有效。第三個問題萬一發(fā)生誤刪操作你允許的數(shù)據(jù)丟失時間窗口是多久這個 RPORecovery Point Objective直接決定了你的備份頻率和備份方式。我把這些問題拿出來說是因?yàn)槲乙娺^太多人把備份等同于“對 etcd 做一個快照”。實(shí)際上etcd 快照只覆蓋 Kubernetes 控制面存儲的狀態(tài)它根本不包含業(yè)務(wù)容器寫入 PV 的數(shù)據(jù)。如果你跑的是 MySQL、Redis 這類有狀態(tài)服務(wù)PV 數(shù)據(jù)丟了etcd 再完整也只能幫你恢復(fù)出一個空殼數(shù)據(jù)庫。1.2 把資產(chǎn)拆成三個層次來看待我習(xí)慣把一個集群需要保護(hù)的資產(chǎn)分成三個層次。第一層是集群狀態(tài)層對應(yīng) etcd 中保存的幾乎所有 Kubernetes 對象包括 Deployment、Service、ConfigMap、Secret、Namespace、RBAC 規(guī)則、CRD 實(shí)例等。這一層的特點(diǎn)是數(shù)據(jù)量通常不大但變化極其頻繁任何一次kubectl apply都會改動它。第二層是持久化數(shù)據(jù)層也就是 PV/PVC 背后真正存儲的業(yè)務(wù)文件、數(shù)據(jù)庫文件這一層通常由云盤、NFS、Ceph 等外部存儲系統(tǒng)承載Kubernetes 自身并不知道里面裝了什么。第三層是外部依賴層比如鏡像倉庫里的鏡像、Helm Chart 倉庫、GitOps 倉庫里的部署清單這些資源往往不在集群內(nèi)卻是重建集群時必不可少的輸入。有了這三層視角之后你的備份策略就非常清晰了集群狀態(tài)層用 etcd 快照解決持久化數(shù)據(jù)層用 Velero 這類工具配合存儲驅(qū)動解決外部依賴層則靠日常的版本管理和倉庫鏡像同步解決。三者缺一不可。1.3 方案選型etcd 快照與 Velero 并不沖突我經(jīng)常在社區(qū)里看到有人爭論“備份到底該用 etcd 快照還是 Velero”這個問題本身就問錯了。這兩種工具解決的不是同一個問題放在一起使用才是一套完整的方案。etcd 快照負(fù)責(zé)兜底適合應(yīng)對集群級災(zāi)難比如 Master 節(jié)點(diǎn)不可用、etcd 數(shù)據(jù)全部損壞、誤刪了整個 Namespace 且資源無法重建。Velero 負(fù)責(zé)精細(xì)化和應(yīng)用級備份適合做資源遷移、版本回滾、按命名空間恢復(fù)還能借助 restic 或 Kopia 備份 PV 數(shù)據(jù)。如果你的集群所有數(shù)據(jù)都有外部備份并且一切皆代碼那你可以只依賴 GitOps 方式重建但大多數(shù)團(tuán)隊(duì)還沒做到這個程度因此快照依然是必需品??吹竭@里你基本明白了我不是讓你二選一而是建議你用“雙保險”思路搭建備份體系。后面幾節(jié)我會把兩條路線都走一遍你可以直接照抄配置。2. 動手前的環(huán)境準(zhǔn)備與配置項(xiàng)梳理不管用 etcd 快照還是 Velero集群本身需要滿足一些最基本的條件。這一節(jié)先把環(huán)境準(zhǔn)備和核心配置項(xiàng)講清楚避免后面實(shí)操時卡在一些莫名其妙的地方。2.1 確認(rèn)集群部署方式與 etcd 形態(tài)首先要確認(rèn)你的 etcd 是怎么部署的。不同集群形態(tài)會導(dǎo)致 etcd 的訪問方式完全不同這一點(diǎn)是新手最容易栽跟頭的地方。kubeadm 部署的集群etcd 以靜態(tài) Pod 方式運(yùn)行在 Master 節(jié)點(diǎn)上通過/etc/kubernetes/manifests/etcd.yaml定義證書和配置集中在/etc/kubernetes/pki/etcd/目錄。二進(jìn)制方式部署的集群etcd 通常以 systemd 服務(wù)運(yùn)行數(shù)據(jù)目錄、證書路徑、監(jiān)聽地址全部由你自定義快照時需要手動拼接參數(shù)。云廠商托管的集群如 EKS、ACK、TKE控制面 etcd 基本由云廠商管理用戶無法直接接觸此時你更需要依賴 Velero 或云廠商自帶的集群快照能力做應(yīng)用級備份。定位好你自己的集群形態(tài)后面的命令才能跑通。我下面的實(shí)踐示例基于 kubeadm 部署的集群來展開這也是社區(qū)里最常見的自建集群方式。2.2 為備份賬號準(zhǔn)備必要的權(quán)限配置如果你要用 Velero它需要一個專用的服務(wù)賬號并且這個賬號需要有足夠權(quán)限讀取集群中的所有資源。Velero 安裝時默認(rèn)會創(chuàng)建velero命名空間并部署一組 RBAC 規(guī)則正常情況下不用手動造輪子。但有一點(diǎn)容易忽略當(dāng)你計(jì)劃備份自定義資源CRD時需要確保 Velero 的服務(wù)賬號對相關(guān) CRD 有 get、list、watch 權(quán)限。如果某天你發(fā)現(xiàn)備份任務(wù)顯示成功但恢復(fù)后 CRD 實(shí)例丟了優(yōu)先檢查是不是權(quán)限不足導(dǎo)致 Velero 無法枚舉資源。這里給出一個排查用的最小 RBAC 配置它授予了備份操作所需的粗粒度權(quán)限。如果你對安全要求比較高建議按需收縮到具體資源apiVersion: v1 kind: ServiceAccount metadata: name: velero namespace: velero --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: velero-admin roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: velero namespace: velero這個配置看起來比較粗暴但它能保證 Velero 不會因?yàn)闄?quán)限問題而跳過資源。生產(chǎn)環(huán)境建議結(jié)合 Velero 官方文檔中的 RBAC 模板做進(jìn)一步裁剪。2.3 準(zhǔn)備一套獨(dú)立的對象存儲用于存放備份Velero 的備份文件需要落到對象存儲中。如果你已經(jīng)在用 AWS S3、阿里云 OSS、MinIO 這類兼容 S3 協(xié)議的服務(wù)那可以直接復(fù)用。如果還沒有我強(qiáng)烈建議你在內(nèi)網(wǎng)部署一個 MinIO專門用于存放備份。它的部署非常簡單單機(jī)版用 Docker 幾分鐘就能跑起來。用 MinIO 主要是為了兩個目的一是讓備份文件集中管理不會被隨意清理二是 Velero 官方對 S3 API 的兼容性很好選它省去很多兼容性適配的麻煩。存儲桶創(chuàng)建好后記錄下 endpoint 地址、access key、secret key后面配置 Velero 時要用到。下面是我的 MinIO 初始化命令示例實(shí)際使用時請?zhí)鎿Q成你自己的賬號密碼docker run -d \ --name minio \ -p 9000:9000 \ -p 9001:9001 \ -e MINIO_ROOT_USERvelero_backup \ -e MINIO_ROOT_PASSWORDYourStrongPass2026 \ -v /data/minio:/data \ minio/minio server /data --console-address :9001啟動后到控制臺創(chuàng)建一個名為velero-backup的 bucket并且建議開啟版本控制。原因很簡單版本控制能防止備份對象被誤刪或覆蓋相當(dāng)于給備份又加了一層保險。3. etcd 快照備份與恢復(fù)的完整實(shí)踐etcd 快照是整個集群備份體系的第一塊基石也是恢復(fù)集群控制面數(shù)據(jù)的終極手段。我不敢說它難但操作過程中稍有不慎就會造成數(shù)據(jù)不一致所以接下來我會把每一步拆得很細(xì)。3.1 配置 etcd 客戶端證書環(huán)境變量使用etcdctl做快照通常需要 TLS 證書認(rèn)證。kubeadm 部署的集群中etcd 證書位于 Master 節(jié)點(diǎn)的/etc/kubernetes/pki/etcd/目錄你需要在執(zhí)行命令前導(dǎo)出環(huán)境變量否則會提示證書校驗(yàn)失敗。我的做法是先把以下內(nèi)容寫到/etc/profile.d/etcdctl.sh中簡化后續(xù)操作export ETCDCTL_API3 export ETCDCTL_CACERT/etc/kubernetes/pki/etcd/ca.crt export ETCDCTL_CERT/etc/kubernetes/pki/etcd/server.crt export ETCDCTL_KEY/etc/kubernetes/pki/etcd/server.key export ETCDCTL_ENDPOINTShttps://127.0.0.1:2379關(guān)于證書文件有一個細(xì)節(jié)值得說明server.crt和server.key是 etcd 服務(wù)端證書用于 etcd 各成員之間通信同時也被 etcdctl 作為客戶端證書使用。如果你在某個節(jié)點(diǎn)上找不到server.*文件也可以嘗試用peer.crt和peer.key替代但首選仍是 server 證書。執(zhí)行source /etc/profile.d/etcdctl.sh后可用一條簡單的etcdctl endpoint health命令驗(yàn)證連接是否正常。3.2 執(zhí)行手動快照與定時備份完成認(rèn)證配置后做一次手動快照就非常簡單了mkdir -p /backup/etcd etcdctl snapshot save /backup/etcd/snapshot-$(date %Y%m%d-%H%M%S).db執(zhí)行成功后會輸出類似Snapshot saved at /backup/etcd/snapshot-xxxx.db的信息。此時你可以用校驗(yàn)命令確認(rèn)快照文件沒有損壞etcdctl snapshot status /backup/etcd/snapshot-xxxx.db該命令會返回快照的版本、數(shù)據(jù)大小、hash 值等信息。我每次做完快照都會順手跑一次這條命令它雖然不能百分百保證恢復(fù)成功但至少能從哈希層面排除文件在落盤過程中出現(xiàn)損壞的可能。手動快照只能救急不能作為常態(tài)化機(jī)制。更合理的做法是寫一個定時任務(wù)腳本每天在業(yè)務(wù)低峰期自動執(zhí)行快照并清理三天前的舊文件。下面是我實(shí)際在用的腳本你拿走改成自己的備份目錄就能用#!/bin/bash BACKUP_DIR/backup/etcd RETENTION_DAYS3 source /etc/profile.d/etcdctl.sh mkdir -p ${BACKUP_DIR} etcdctl snapshot save ${BACKUP_DIR}/snapshot-$(date %Y%m%d-%H%M%S).db find ${BACKUP_DIR} -name snapshot-*.db -mtime ${RETENTION_DAYS} -exec rm -f {} \;用crontab -e添加定時任務(wù)以每天凌晨 2 點(diǎn)執(zhí)行為例0 2 * * * /opt/scripts/etcd-backup.sh /var/log/etcd-backup.log 21關(guān)于快照保留周期我建議根據(jù)自己的數(shù)據(jù)量決定。etcd 快照文件一般不會很大幾百 MB 到幾個 GB 都很常見所以你完全可以把保留周期設(shè)置得長一些比如保留 7 份每日快照外加每周快照。丟失數(shù)據(jù)這件事寧可多留不可少留。3.3 恢復(fù)實(shí)操從快照還原到單機(jī)集群恢復(fù) etcd 是整個集群恢復(fù)流程中最容易手忙腳亂的部分因?yàn)槟阈枰岩粋€“已經(jīng)存在的故障集群”先停下來再手動去重建數(shù)據(jù)目錄。這里強(qiáng)調(diào)一下恢復(fù)操作必須在所有 etcd 節(jié)點(diǎn)上協(xié)調(diào)進(jìn)行不建議只對單節(jié)點(diǎn)操作而讓其他節(jié)點(diǎn)繼續(xù)運(yùn)行。下面以單節(jié)點(diǎn) etcd 為例展開。第一步停掉 kube-apiserver 和 etcd。如果是靜態(tài) Pod 方式部署最直接的做法是把/etc/kubernetes/manifests/下的etcd.yaml移走并用kubelet的靜態(tài) Pod 機(jī)制讓它自動停掉。但更穩(wěn)妥的順序是先把 apiserver 停掉避免 apiserver 在 etcd 恢復(fù)期間不斷寫入數(shù)據(jù)導(dǎo)致快照還原后的數(shù)據(jù)被再次污染。mv /etc/kubernetes/manifests/etcd.yaml /root/backup-manifests/ mv /etc/kubernetes/manifests/kube-apiserver.yaml /root/backup-manifests/ sleep 30第二步備份并清空舊的 etcd 數(shù)據(jù)目錄。默認(rèn)數(shù)據(jù)目錄是/var/lib/etcd我建議先把它整個移動到一個備份位置而不是直接刪除防止恢復(fù)失敗時還有后悔藥可吃mv /var/lib/etcd /var/lib/etcd.bak.$(date %Y%m%d)第三步用快照文件恢復(fù)數(shù)據(jù)目錄。etcdctl 的snapshot restore命令會生成一個新的數(shù)據(jù)目錄你需要通過--data-dir參數(shù)指定位置并傳入與舊集群一致的名稱和證書參數(shù)etcdctl snapshot restore /backup/etcd/snapshot-xxxx.db \ --name etcd-1 \ --initial-cluster etcd-1https://127.0.0.1:2380 \ --initial-cluster-token etcd-cluster \ --initial-advertise-peer-urls https://127.0.0.1:2380 \ --data-dir /var/lib/etcd這里有一個關(guān)鍵點(diǎn)--initial-cluster-token的值必須和原來的集群保持一致或者干脆隨意指定一個全新值。后者其實(shí)更常見因?yàn)槟阍谧龌謴?fù)時通常是想啟動一個全新的 etcd 數(shù)據(jù)實(shí)例。但如果你希望恢復(fù)后的 etcd 能重新加入原有集群拓?fù)淠蔷捅仨毐3?peer URL 與集群配置一致否則其他節(jié)點(diǎn)會認(rèn)為這是一個陌生成員。第四步把etcd.yaml和kube-apiserver.yaml移回靜態(tài) Pod 目錄等待 kubelet 自動拉起 etcd 和 apiservermv /root/backup-manifests/etcd.yaml /etc/kubernetes/manifests/ mv /root/backup-manifests/kube-apiserver.yaml /etc/kubernetes/manifests/ sleep 60最后驗(yàn)證集群狀態(tài)kubectl get nodes kubectl get pods -A如果看到 Node 狀態(tài)正常、之前的資源都回來了說明恢復(fù)成功。如果 apiserver 啟動失敗先去看 kubelet 日志和 etcd 日志絕大多數(shù)問題出在證書路徑不匹配或數(shù)據(jù)目錄權(quán)限不對上。3.4 恢復(fù)操作中的風(fēng)險控制與注意事項(xiàng)關(guān)于 etcd 恢復(fù)我吃過不少虧挑幾個最典型的提醒一下。第一恢復(fù)操作前必須停止所有寫入方。不只是 kube-apiserver如果集群里還有其他組件直接通過 etcd 客戶端接口讀寫數(shù)據(jù)比如某些定制 Operator也要一并停止。否則很可能出現(xiàn)恢復(fù)后一部分舊數(shù)據(jù)被新數(shù)據(jù)覆蓋或沖突的情況表現(xiàn)為資源狀態(tài)詭異、對象反復(fù)重建。第二不要在生產(chǎn)集群上邊跑業(yè)務(wù)邊恢復(fù)。即便恢復(fù)的是單節(jié)點(diǎn) etcd也強(qiáng)烈建議先摘掉業(yè)務(wù)流量因?yàn)榛謴?fù)過程中 kubelet 可能會根據(jù)舊數(shù)據(jù)重新創(chuàng)建 Pod造成未知影響。第三etcd 快照不保證包含最近幾秒的寫入。etcd 的 snapshot 是某一時間點(diǎn)的存儲狀態(tài)自快照時間點(diǎn)之后發(fā)生的變更都會丟失。這決定了你的 RPO 不可能為零如果你的業(yè)務(wù)對數(shù)據(jù)極其敏感需要在上層做更細(xì)粒度的備份或同步。4. Velero 應(yīng)用級備份與恢復(fù)實(shí)操etcd 快照能保住控制面但它無法備份 PVC 里的數(shù)據(jù)。所以當(dāng)業(yè)務(wù)真正跑起來之后它用的數(shù)據(jù)庫文件、上傳的文件、生成的臨時數(shù)據(jù)全都在 PV 里面這時候必須請出 Velero。4.1 Velero 的核心架構(gòu)與備份原理Velero 的工作機(jī)制可以簡單概括為兩部分一方面通過 Kubernetes API 讀取集群中的資源對象打包后上傳到對象存儲另一方面通過文件系統(tǒng)備份組件如 restic 或 Kopia讀取 PVC 掛載的數(shù)據(jù)卷內(nèi)容將其一并上傳。它不需要在集群里安裝特權(quán) DaemonSet 之外的 agent備份動作由 Velero Server 組件部署在集群內(nèi)和 Velero CLI 客戶端協(xié)同完成。CLI 下發(fā)備份指令后Velero Server 會在集群中創(chuàng)建 Backup 資源隨后 Backup Controller 負(fù)責(zé)執(zhí)行具體任務(wù)。你在使用過程中會經(jīng)??吹?Backup、Restore、Schedule、BackupStorageLocation 這幾類 CRD它們都是 Velero 的核心抽象。理解它們的層級關(guān)系對排查問題很有幫助BackupStorageLocation 定義備份文件存放位置Schedule 定義周期巡檢任務(wù)Backup 是一次具體備份動作的記錄Restore 是一次恢復(fù)動作的記錄??慈罩緯r只需要找到對應(yīng) Backup 或 Restore 資源然后通過velero backup logs name查看詳細(xì)日志即可。4.2 安裝 Velero 并配置對象存儲安裝 Velero 的工具本身并不復(fù)雜核心是把云廠商存儲的訪問憑證準(zhǔn)備好。以 MinIO 為例首先創(chuàng)建一個包含訪問密鑰的文件cat credentials-velero EOF [default] aws_access_key_id velero_backup aws_secret_access_key YourStrongPass2026 EOF然后執(zhí)行安裝命令velero install \ --provider aws \ --plugins velero/velero-plugin-for-aws:v1.9.0 \ --bucket velero-backup \ --secret-file ./credentials-velero \ --backup-location-config regionminio,s3ForcePathStyletrue,s3Urlhttp://minio.velero.svc.cluster.local:9000 \ --snapshot-location-config regionminio \ --use-restic \ --use-volume-snapshotsfalse \ --wait拆解一下這條命令中幾個容易出錯的參數(shù)--provider aws這里不是說你必須用 AWS而是 Velero 用 AWS S3 兼容協(xié)議去對接對象存儲MinIO、OSS、COS 都支持這種協(xié)議。--plugins velero/velero-plugin-for-aws:v1.9.0插件版本要和 Velero 主版本接近否則可能出現(xiàn) API 不兼容的問題。s3ForcePathStyletrueMinIO 這類私有對象存儲要求路徑風(fēng)格 URL不加這個參數(shù)會導(dǎo)致 Velero 無法找到桶。--use-restic啟用文件系統(tǒng)備份能力用來備份 PVC 數(shù)據(jù)。--use-volume-snapshotsfalse如果存儲后端沒有實(shí)現(xiàn) CSI 快照能力就關(guān)掉卷快照功能避免 Velero 一直嘗試調(diào)用不存在的快照接口。安裝完成后查看 velero 命名空間下的 Pod 狀態(tài)確保velero和restic相關(guān) Pod 都正常運(yùn)行kubectl get pods -n velero4.3 按命名空間備份先從小范圍開始Velero 上手最好的方式不是一上來就全集群備份而是先挑一個測試命名空間做驗(yàn)證。比如我需要備份wordpress命名空間下的所有資源以及 PVC 數(shù)據(jù)可以執(zhí)行velero backup create wordpress-backup \ --include-namespaces wordpress \ --default-volumes-to-restic \ --ttl 168h0m0s參數(shù)說明--include-namespaces只備份指定命名空間。--default-volumes-to-restic對 PVC 數(shù)據(jù)啟用 restic 備份。--ttl備份文件在對象存儲中的保留時間這里設(shè)置了 7 天。執(zhí)行后可能會等待一段時間你可以用velero backup get查看狀態(tài)從 New 變成 Completed 就說明備份成功了。然后模擬一次災(zāi)難直接刪掉wordpress命名空間kubectl delete namespace wordpress等命名空間完全清理干凈后執(zhí)行恢復(fù)velero restore create --from-backup wordpress-backup恢復(fù)完成后進(jìn)入命名空間檢查資源確認(rèn) Pod、PVC、Service、Ingress 都回來了。如果 PVC 里的數(shù)據(jù)文件已經(jīng)通過 restic 重新灌入新恢復(fù)的 PV 中那業(yè)務(wù)一般能無縫拉起。4.4 整個集群與全量備份策略如果你想把整個集群的所有資源都備份起來需要更加謹(jǐn)慎。我先提醒一句全集群備份并備份 PVC 數(shù)據(jù)是代價最大的方案耗時和存儲成本都不可小覷所以不要動不動就跑全量備份。Velero 默認(rèn)在velero backup create時如果不加任何篩選參數(shù)實(shí)際上就已經(jīng)備份了所有非系統(tǒng)命名空間的資源。但要注意它默認(rèn)不會備份velero、kube-system、kube-public、kube-node-lease這些系統(tǒng)級命名空間。這樣設(shè)計(jì)是合理的因?yàn)檫@些命名空間里的組件大多可以通過重建或重新安裝還原備份它們意義不大。設(shè)置了清理系統(tǒng)命名空間后如果需要做“全集群模擬恢復(fù)驗(yàn)證”可以用以下命令初始化一個 full backup 作業(yè)把白名單和黑名單調(diào)整清楚velero backup create full-backup \ --exclude-namespaces kube-system,kube-public,kube-node-lease,velero \ --exclude-resources events,events.events.k8s.io \ --default-volumes-to-restic \ --ttl 336h0m0s排除了 events 的原因是事件數(shù)據(jù)通常量大且無恢復(fù)價值既浪費(fèi)時間又浪費(fèi)存儲空間。實(shí)際需求中你再結(jié)合是否要排除一些臨時緩存類資源根據(jù)業(yè)務(wù)情況調(diào)整。4.5 跨集群遷移Velero 的高階玩法Velero 備份文件存儲在對象存儲里這意味著它天然支持跨集群恢復(fù)。假如你有 A、B 兩個集群對象存儲是同一個 MinIO那么在 A 集群做好備份后到 B 集群執(zhí)行一條恢復(fù)命令就能完成資源遷移。我在做環(huán)境遷移時常用一套組合拳A 集群創(chuàng)建備份B 集群配置相同的 BackupStorageLocation 和 credentials然后執(zhí)行恢復(fù)。步驟上你先要在 B 集群上安裝 Velero使用同樣的 MinIO 配置參數(shù)velero install \ --provider aws \ --plugins velero/velero-plugin-for-aws:v1.9.0 \ --bucket velero-backup \ --secret-file ./credentials-velero \ --backup-location-config regionminio,s3ForcePathStyletrue,s3Urlhttp://minio.velero.svc.cluster.local:9000 \ --snapshot-location-config regionminio \ --wait然后你要保證 B 集群能夠讀到一個備份名。執(zhí)行velero backup get看到 A 集群創(chuàng)建的那個備份名稱后直接執(zhí)行恢復(fù)即可。如果目標(biāo)集群中沒有對應(yīng)的 StorageClass 或不支持同樣的存儲協(xié)議PVC 可能會恢復(fù)失敗。此時可以通過 Velero 的存儲類映射功能在恢復(fù)時把源存儲類替換為目標(biāo)集群的存儲類。5. 自動化定時備份與恢復(fù)演練經(jīng)驗(yàn)手動備份能保一時備份體系的真正價值在于自動化。一個無法自動運(yùn)行的備份機(jī)制最終一定會被日常工作節(jié)奏擠掉。5.1 使用 Velero Schedule 實(shí)現(xiàn)定時備份Velero 內(nèi)置了 Schedule 概念創(chuàng)建它之后Velero 會按照 Cron 表達(dá)式周期性地生成新的 Backup。它的最大優(yōu)點(diǎn)是把備份動作納入了集群內(nèi)部狀態(tài)管理你隨時可以通過 CRD 查看備份計(jì)劃。創(chuàng)建每日全量備份計(jì)劃保留 7 天命令如下velero schedule create daily-full-backup \ --schedule0 2 * * * \ --include-namespaces wordpress,default \ --default-volumes-to-restic \ --ttl 168h0m0s你可以用velero schedule get查看調(diào)度計(jì)劃狀態(tài)用velero backup get查看它自動觸發(fā)的 Backup 是否成功。如果其中一個 Backup 失敗了Schedule 會繼續(xù)保留并不會影響下一次觸發(fā)。這種解耦設(shè)計(jì)很實(shí)用至少我不會因?yàn)橐淮问《┑艉罄m(xù)備份。關(guān)于 Cron 表達(dá)式我建議結(jié)合業(yè)務(wù)低谷期來設(shè)置。如果集群和對象存儲都相對空閑凌晨 2 點(diǎn)到 4 點(diǎn)之間跑備份是比較通用的選擇。如果備份數(shù)據(jù)量很大可能單次執(zhí)行超過 30 分鐘你還要注意 Schedule 的時間窗口不能與下一次調(diào)度重疊否則會形成備份任務(wù)堆積。5.2 對象存儲側(cè)的備份生命周期管理備份文件生成之后對象存儲側(cè)同樣要有生命周期管理規(guī)則。MinIO 提供了生命周期配置可以為 bucket 配置過期刪除規(guī)則所以 Velero 里的--ttl并不是唯一的清理機(jī)制。我的建議是兩側(cè)都設(shè)但以 Velero 的 ttl 為主MinIO 生命周期為輔。假設(shè) Velero 設(shè)置了 7 天 TTLMinIO 生命周期規(guī)則設(shè)置為 10 天過期這樣能有效防止因 Velero 控制器異常導(dǎo)致備份文件無限堆積。配置 CapEx 時應(yīng)考慮到存儲成本不要把周期設(shè)得太長也不要設(shè)得太短。比較穩(wěn)妥的做法是“本地 7 天 異地副本 30 天”這部分需要根據(jù)你公司對數(shù)據(jù)安全的要求調(diào)整。5.3 每季度做一次真實(shí)的恢復(fù)演練我沒見過哪個團(tuán)隊(duì)的備份策略是第一次就能做完美的。真正的分水嶺在于是否做了恢復(fù)演練而且不是演練一次就結(jié)束是每季度或半年固定做一次。我自己的做法是準(zhǔn)備一個獨(dú)立的演練集群這個集群規(guī)模不需要很大但安裝的 K8s 版本和插件配置盡量與生產(chǎn)一致。然后我每個月從對象存儲中隨機(jī)挑一個備份把資源恢復(fù)到演練集群再驗(yàn)證幾個核心業(yè)務(wù)是否能正常工作。曾有一次演練暴露過大問題一切資源恢復(fù)成功但業(yè)務(wù)無法啟動原因是 Secret 中的密碼在源集群里已經(jīng)輪換過而 ConfigMap 中引用的配置仍舊是舊值。如果沒做演練等真實(shí)災(zāi)難發(fā)生時這個問題會變成生產(chǎn)事故的原因。所以我說演練不是額外負(fù)擔(dān)它是備份體系中最有價值的一環(huán)。6. 常見故障與排查技巧備份恢復(fù)大概率不是一次就能順利跑通的。我把這兩年遇到的高頻問題整理成了一張速查表供你定位問題。癥狀可能原因解決方案etcdctl snapshot save 報證書錯誤未正確加載 ETCDCTL_CERT / ETCDCTL_KEY 環(huán)境變量重新 source 環(huán)境變量文件檢查證書路徑etcd snapshot restore 后 apiserver 起不來數(shù)據(jù)目錄權(quán)限不對或新舊集群 token 不一致確認(rèn)/var/lib/etcd屬主為 etcd 用戶檢查 apiserver 日志Velero backup 狀態(tài)一直停留在 NewBackupStorageLocation 無效或插件版本不匹配查看 velero 日志檢查存儲桶是否可訪問Velero 備份完成但恢復(fù)后 PVC 為空沒有啟用 restic / 卷快照被顯式關(guān)閉恢復(fù)動作加上--default-volumes-to-restic并確認(rèn) restic Pod 運(yùn)行恢復(fù)時提示 storageclass 不存在目標(biāo)集群缺少源集群的 StorageClass創(chuàng)建同名 StorageClass或用--storage-class-mapping參數(shù)做替換定時備份連續(xù)失敗但你完全沒發(fā)現(xiàn)缺少失敗告警機(jī)制為 Velero 配置監(jiān)控告警或檢查日志工具備份文件在 MinIO 中被誤刪bucket 沒有開啟版本控制開啟 bucket 版本控制并配置生命周期規(guī)則除了表格里的問題我再補(bǔ)充三個比較隱秘但很重要的經(jīng)驗(yàn)。第一Velero 備份過程中如果集群正在發(fā)生大量資源變更可能出現(xiàn)部分資源處于中間狀態(tài)導(dǎo)致恢復(fù)回來后資源版本沖突或字段不完整。對于核心數(shù)據(jù)庫這類服務(wù)我建議備份前先將應(yīng)用置于只讀或停寫狀態(tài)至少也要接受 PVC 數(shù)據(jù)本身的一致性由應(yīng)用層保證。第二restic 備份模式對 PVC 數(shù)據(jù)的備份速度較慢。如果 PVC 體積達(dá)到 TB 級別全量備份耗時可能數(shù)小時。這時候需要考慮文件系統(tǒng)層面的定期快照比如云廠商磁盤快照或數(shù)據(jù)庫自身備份工具而不是一味依賴 Velero 的每個卷備份。第三恢復(fù)時注意資源間的依賴順序。Velero 會盡力做依賴排序但有些自定義資源需要先創(chuàng)建 CRD再創(chuàng)建 CRD 實(shí)例。如果恢復(fù)后自定義資源沒有正常出現(xiàn)優(yōu)先檢查 CRD 是否已經(jīng)注冊必要時手動應(yīng)用 CRD 定義。還有一個小技巧恢復(fù)前把目標(biāo)集群的命名空間先清空或者使用一個新的命名空間做恢復(fù)驗(yàn)證避免與現(xiàn)有資源產(chǎn)生沖突。這個操作能幫你把問題邊界縮小少在環(huán)境干擾上浪費(fèi)時間。說一個我印象最深的教訓(xùn)。某次我把 etcd 快照恢復(fù)做完了節(jié)點(diǎn)全部 ReadyPod 也全部 Running表面上一切完美。結(jié)果第二天業(yè)務(wù)反饋數(shù)據(jù)缺失一查發(fā)現(xiàn)備份時間點(diǎn)在業(yè)務(wù)高峰期前一小時隨后一小時內(nèi)的寫入全部丟掉了。從此以后我在設(shè)計(jì)備份策略時都會先問一句業(yè)務(wù)能否接受這個 RPO如果能承受小時級丟失則每日備份足夠如果不能那就需要借助數(shù)據(jù)庫層的 binlog 同步或存儲層的實(shí)時快照來縮短丟失窗口。備份恢復(fù)這件事看起來只是幾條命令但真正把它做扎實(shí)需要你對集群的部署形態(tài)、業(yè)務(wù)的數(shù)據(jù)特性、存儲后端的接口能力都有清晰認(rèn)知。希望這篇基于配置與實(shí)踐的梳理能讓你在構(gòu)建自己的備份方案時少走一些彎路。下一次遇到故障時希望你想到的不是后悔沒備份而是從容地執(zhí)行演練過無數(shù)遍的恢復(fù)流程。