叢集管理:kubeadm、etcd 備份、升級

· tech

#kubernetes#operations

📑 目錄

前面十一篇都站在「叢集」的位置。這篇換到「建與養叢集」的位置——CKA 佔 25% 的 Cluster Architecture 裡最硬的 ops 活。三件事貫穿一個管理員的一生:怎麼把一堆機器變成叢集(kubeadm)、怎麼在災難來時把它救回來(etcd 備份)、怎麼升級而不停機(upgrade)。 第二件是全 CKA 最該練到手起刀落的一題,先講清楚它為什麼這麼重要。

kubeadm:一鍵把一堆機器變成叢集

手動拉起一個 control plane(簽一堆憑證、配 api-server、接 etcd)是惡夢。kubeadm 把這件事變成兩個指令:

Control Plane node · kubeadm init api-server scheduler controller-mgr etcd 都是 static pod:kubelet 讀 /etc/kubernetes/manifests 拉起來就自動維持 吐出 join token + 指令 kubeadm join <token> Worker node只跑 kubelet + 你的 Pod Worker node要幾台加幾台 再加 CP node(join)→ HA control plane
kubeadm init 在第一台把 control plane 組件(含 etcd)拉成 static pod、吐出一段 join token;其他機器用 kubeadm join 帶 token 加入,worker 只跑 kubelet 與你的 Pod。整個叢集的狀態,全存在那顆 etcd

control plane 的組件都以 static pod 形式跑——kubelet 監看 /etc/kubernetes/manifests 目錄,把裡面的 manifest 拉起來並維持。這也是為什麼你 debug control plane 時,是去那台機器看這幾個檔案、看這幾顆 pod,而不是用一般的 Deployment 邏輯去找。

etcd:叢集的唯一真相,也是唯一的死穴

看那張圖裡的 etcd——你叢集裡的每一個物件(Deployment、Service、Secret、RBAC…)的狀態,全部只存在 etcd 這一個地方。 第一篇說 reconcile loop 不斷把現實拉向「期望」,而那份「期望」就住在 etcd。它用 Raft 共識維持多副本一致,所以 HA 部署要奇數台(3 台容忍掛 1、5 台容忍掛 2)才湊得出多數決、避免 split-brain。

但再多副本也擋不住「誤刪」「憑證爛掉」「整個 etcd 資料毀損」。所以管理員的第一戒律是:定期把 etcd 快照存到叢集外。 這是你唯一的還原點——沒有它,叢集掛了就是從零重建。

etcd唯一真相 snapshot save snapshot.db存叢集外 / 異地 災難:etcd 毀了 / 誤刪 snapshot.db(手上這份) restore 新的 data 目錄restore 產生 etcd etcd 指向新目錄重啟 → 叢集回到「快照那一刻」的狀態
備份就一行 etcdctl snapshot save,把狀態存成 snapshot.db 放叢集外。災難時 snapshot restore 把它還原成新的 data 目錄、讓 etcd 指過去重啟,叢集就回到快照那一刻。沒有這份快照,etcd 一毀就是從零重建

指令的骨架長這樣(實際要帶 endpoints 與那三張憑證 --cacert/--cert/--key):

# 平時:定期備份,把 snapshot.db 收到叢集外
ETCDCTL_API=3 etcdctl snapshot save snapshot.db
# 災難後:還原成新目錄,再改 etcd static pod manifest 指過去、重啟
ETCDCTL_API=3 etcdctl snapshot restore snapshot.db --data-dir /var/lib/etcd-restore

「有沒有可用的 etcd 備份」這一題,幾乎定義了一個叢集的災難復原能力。 別等出事才發現快照從沒跑成功過。

升級:一次一個節點的接力賽

叢集要升 K8s 版本,規矩很硬:一次只能跳一個 minor 版本(1.29 → 1.30,不能 1.29 → 1.31),而且 control plane 要先於 worker。整個過程是一場「一次動一台、其餘照常服務」的接力賽:

鐵律:一次只跳一個 minor(1.29 → 1.30)· control plane 先、worker 後 ① Control Planekubeadm upgrade apply ② Workerkubeadm upgrade node ③ Worker …一台接一台 每一台節點,都跑這一輪四步: cordon + drain把 Pod 疏散走 升 kubeadmupgrade apply/node 升 kubelet+ kubectl,重啟 uncordon重新收 Pod 一次只動一台、其餘照常扛流量 —— 這就是「升級不停機」的原理
升級是一場接力賽:control plane 先、worker 後,一次只動一台。每台都跑同一輪四步——cordon + drain 把 Pod 疏散、升 kubeadm 跑 upgrade、升 kubelet、uncordon 讓它重新收 Pod。其餘節點照常扛流量,所以整體不中斷

第一台 control plane 用 kubeadm upgrade apply 定調整個叢集要升到的版本,其餘 control plane 與 worker 節點都用 kubeadm upgrade node 跟上。drain尊重 Deployment 的多副本:它把 Pod 從這台趕走,ReplicaSet 立刻在別台補回來,所以只要你的服務有多份、又設了 PodDisruptionBudget,滾動升級全程有服務。

反思

etcd 備份是那種「不出事沒人記得、出事沒它就完蛋」的事

我對備份的敬畏,是被真實的恐懼餵大的。叢集所有的狀態濃縮在 etcd 一個地方,這設計很優雅,但也意味著它是整座叢集的單點死穴——多副本擋得住機器掛,擋不住一次誤操作把關鍵物件刪光、或憑證過期到 etcd 起不來。那一刻,你手上有沒有一份驗證過、還原得回去的快照,是「十分鐘恢復」和「熬夜重建整個叢集」的差別。所以我把 etcd 備份當成 SRE 那幾篇講的可靠性基本功:不只要排程備份,還要真的定期演練還原——沒還原過的備份,只是一份你以為存在的安心感。

「一次一個節點」的升級哲學,其實跟滾動更新是同一件事

升級叢集看起來很嚇人,但拆開就發現它跟 Deployment 的滾動更新是同一個心法的放大版:永遠只讓一小部分處於變動中,其餘維持服務,壞了還能退。 應用層是「一次換幾顆 Pod」,叢集層是「一次升一台 node」;drain 之於 node,就像 readiness probe 之於 Pod——先把流量挪乾淨,再動手。想通這個對稱,我對「動 Production」的恐懼就小很多:方法一樣,只是把單位從 Pod 換成 node。把大動作切成一連串可回退的小步,是我在整個 K8s 世界裡看到最一致、也最值得內化的一條原則。

管理員的價值,在平時看不見的準備裡

寫到這篇我更確定:會 kubectl apply 只是入門,真正把叢集扛在肩上的能力,藏在這些平時無聲的準備裡——備份跑成功了嗎?還原演練過嗎?升級路徑試過嗎?憑證什麼時候到期? 這些事平順時毫無存在感,一出事卻是全部。這跟我對 SRE 的理解完全一致:可靠性不是出事那天才臨場發揮的英雄主義,而是出事之前、日復一日、沒人鼓掌的紀律。 系列下一篇談故障排除——當這些準備還是沒擋住問題時,怎麼一層層把它揪出來。