K8s HA、Quorum 與 Split-brain
K8s HA、Quorum 與 Split-brain的重點整理。
K8s HA、Quorum 與 Split-brain
Split-brain 是分散式系統因網路分割而出現互相衝突的 active side,不專指 Kubernetes master。對使用 Raft 的 datastore,提交新寫入需要多數 voting members,少數派不能自行形成合法的提交多數。
Quorum 的公式、成員數與容錯表見 Consensus Algorithms。在 3 個 etcd voting members 的例子中,至少需要 2 個確認;Control-plane Node 數量不一定等於 etcd 成員數。
共識原理見 Consensus Algorithms;與另一種共識演算法的對照見 Consensus Algorithms。Raft 主要處理非拜占庭故障,PBFT 則考慮節點任意偏離協議的情況,兩者不能直接套用同一個容錯門檻。
MicroK8s 的 HA datastore 使用 dqlite;worker-only 節點不會增加 control-plane HA 能力。不要把 dqlite 的操作方式寫成 etcd 的操作方式。參考:MicroK8s High Availability。
原對話決定先練 CNI 網路,因此這裡保留概念,不把故障注入列為目前網路 Lab 的必要步驟。未來驗證時可觀察正常、失去一個 voter、失去 quorum,以及 1/2 網路分割的寫入行為。控制平面失去 quorum 不表示現有容器立即消失,但排程與需要 datastore 的控制操作會受影響。
etcd 寫入:Leader 協調,多數確認後提交
寫入由 Raft Leader 協調;3 個 voting members 只要 2 個確認即可提交,而且這 2 個包含 Leader 自己。 不是另外需要 2 個 Follower 確認。
Client 可以連到任一成員;需要共識的寫入若先到 Follower,會轉交 Leader。Leader 排定日誌順序、記錄日誌,再複寫給 Followers。
flowchart TD
R[Client 寫入請求] --> E[任一 etcd 成員]
E -->|若為 Follower,轉交 Leader| A[Leader A 記錄日誌並複寫]
A --> B[Follower B 記錄日誌]
A --> C[Follower C 記錄日誌]
B --> Q[B 或 C 至少一個確認]
C --> Q
Q --> M[Leader A 自己 + 一個 Follower = 2/3]
M --> S[Leader 提交並套用,回覆成功]
- A+B 或 A+C 都足夠,不必等待三個成員全部確認;落後的成員之後補齊日誌。
- 「確認」指日誌已記錄,並非只是收到網路請求。Leader 不是唯一保存資料的成員。
- 無法取得多數確認時,就無法繼續提交新寫入;只有一個成員存活也不夠。
- 選 Leader 的投票與每次寫入的日誌複寫確認是不同事情,兩者都需要多數。
參考:etcd FAQ:Leader、Follower 與共識請求、Raft 原始論文。
kube-controller-manager:Leader Election
多個 controller-manager 副本先選一個 Leader,由它執行主要控制工作,其餘待命;Leader 故障或無法續租後,其他副本可接手。 這是高可用,不是各副本平分工作。
kube-controller-manager --leader-elect=true
此參數預設為 true。一般透過 API Server 中的 Lease 協調領導權,Leader 持續續租;它與 etcd/datastore 的 quorum 是不同機制。
| 參數 | 預設 | 意義 |
|---|---|---|
--leader-elect-lease-duration |
15s | 候選者觀察到租約不再更新後,等待租約期限再嘗試取得領導權 |
--leader-elect-renew-deadline |
10s | Leader 無法成功續租達此期限,就放棄領導權 |
--leader-elect-retry-period |
2s | 取得/續租的重試間隔 |
記法:10 秒是 Leader 自己的放手期限,15 秒是候選者判斷能否接手的租約期限,2 秒是重試節奏。不是 15+10=25 秒,也不保證固定第 15 秒完成接手;實際時間受重試、API 連線與設定影響。
查看預設選主租約:
kubectl get lease kube-controller-manager -n kube-system -o yaml
看 spec.holderIdentity 確認目前持有者。若更改過選主租約名稱/namespace,需查對應物件。
參考:kube-controller-manager 官方參數與預設值。
Stacked 與 External etcd Topology
Stacked:etcd 和控制平面元件放同一批機器;External:etcd 放獨立機器,與控制平面分開。 External 的意思是外部,不是 eternal(永恆)。
| 拓撲 | 典型部署例子(不含 worker 與 LB) | 取捨 |
|---|---|---|
| Stacked etcd | 3 台控制平面,各自運行一個 etcd member | 機器較少、架構較簡單;壞一台同時失去控制平面副本與 etcd member |
| External etcd | 3 台控制平面 + 3 台獨立 etcd | 分離故障與資源競爭;機器與維運成本較高,需另外建立管理 etcd 叢集 |
Stacked:
CP-1 [API Server + etcd-1]
CP-2 [API Server + etcd-2]
CP-3 [API Server + etcd-3]
External:
CP-1/CP-2/CP-3 的 API Servers
→ 獨立的 etcd 叢集 [etcd-1、etcd-2、etcd-3]
兩者的 etcd 都需 quorum,External 不代表 etcd 不用選主,也不代表自動具有更高故障容忍數;3 個 voting members 仍需至少 2 個才能提交寫入。API Server 可多副本提供服務;controller-manager 的 Lease 選主與 etcd 的 Raft leader 是不同機制。
參考:Kubernetes HA Topology 官方對照圖。
etcd 備份與還原:etcdctl、etcdutl
備份用 etcdctl snapshot save;檢查與還原用 etcdutl snapshot status/restore。備份完成後不需要立即還原,只有需要回復資料時才 restore。
| 操作 | 工具與指令 | 是否連線到 etcd |
|---|---|---|
| 匯出部分 Resource 設定 | kubectl get all -A -o yaml > all.yml |
透過 API Server 讀取資源 |
| 備份 etcd 資料庫 | etcdctl snapshot save snapshot.db |
是,從運作中的 etcd 取得快照 |
| 檢查快照 metadata | etcdutl snapshot status snapshot.db -w table |
否,讀取本機檔案 |
| 還原到新資料目錄 | etcdutl snapshot restore snapshot.db --data-dir=/var/lib/etcd-restored |
否,讀取本機檔案並建立資料目錄 |
kubectl get all的all不是所有資源,不包含 Secret、ConfigMap、PVC、Ingress、RBAC 等;匯出 YAML 不是完整 etcd 備份。- etcd snapshot 保存叢集狀態,包括 PV/PVC 物件設定,不包含儲存卷內的檔案或資料庫內容。
etcdctl是網路用戶端;etcdutl直接處理本機資料檔。官方 etcdutl 3.5/3.6 沒有etcdutl backup指令,不要記成能自動複製 data directory 與 WAL。etcdctl snapshot status在 3.5 已棄用、3.6 移除;統一記etcdutl snapshot status。
備份:連線、驗證,再儲存快照
先確認工具版本:
etcdctl version
etcdutl version
官方簡化範例($ENDPOINT 須先設為實際位址):
ETCDCTL_API=3 etcdctl --endpoints=$ENDPOINT snapshot save snapshot.db
省略 TLS 參數不代表不用驗證。 kubeadm 常見環境啟用 HTTPS 與用戶端憑證驗證,使用下列完整範例;工具需已安裝,路徑與位址須符合實際環境:
sudo etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
--key=/etc/kubernetes/pki/etcd/healthcheck-client.key \
snapshot save /opt/etcd-backup.db
| 參數 | 用途 |
|---|---|
--endpoints |
etcd 的位址,常見 client port 為 2379 |
--cacert |
etcdctl 用來驗證 etcd Server 的 CA 憑證 |
--cert、--key |
etcd Server 用來驗證用戶端身分的憑證與私鑰 |
snapshot save |
將快照寫入指定檔案 |
課程範例有時用 server.crt/server.key;是否可當 client 使用,取決於憑證用途與伺服器驗證設定。這裡使用 kubeadm 常見的 healthcheck-client 憑證組;不能只憑檔名假設任意 Server 憑證都能當 Client 憑證。
檢查與還原
sudo etcdutl snapshot status /opt/etcd-backup.db --write-out=table
查看 hash、revision、total keys、size 等 metadata;這不等於已驗證整個叢集能成功還原。
建立還原資料目錄的基本語法:
sudo etcdutl snapshot restore /opt/etcd-backup.db \
--data-dir=/var/lib/etcd-restored
這只建立還原資料目錄,不會自動切換正在運作的 etcd。 實際恢復叢集還需要:
- 停止所有 API Server 的寫入與要替換的 etcd instance。
- 依成員名稱、peer URL 與叢集拓撲還原;多成員使用同一份快照並設定各自 membership。
- 讓 etcd 使用還原後的目錄。kubeadm Static Pod 常見要調整
etcd.yaml中etcd-data的hostPath.path,對齊容器內的--data-dir與掛載位置。 - 啟動 etcd,確認健康後恢復 API Server 與其他控制元件並驗證資源。
Kubernetes 還原也要處理舊 revision 對 informer cache 的影響:官方建議搭配 --bump-revision 與 --mark-compacted,數值與完整參數依對應版本的 recovery 文件決定。
還原從本機快照讀取資料,不需要備份時的 TLS 連線參數。快照包含敏感叢集資料,需妥善保存;CA 私鑰、節點設定、Secret 儲存加密金鑰與卷內資料也要另外備份。
官方文件與查詢關鍵詞
| 連結 | 重點/關鍵詞 |
|---|---|
| Kubernetes:Backing up an etcd cluster | backing up etcd、snapshot save、TLS 憑證參數 |
| etcd v3.5:Disaster recovery 原始文件 | snapshot status、snapshot restore、revision bump、data-dir |
| etcd v3.6:Disaster recovery | 依實際 etcd 版本查還原流程 |
| etcdutl v3.6 指令說明 | 本機檔案操作與支援的子指令 |
| 補充影片 | 保留影片連結供複習;指令版本以官方文件為準 |