)
1. 為什么單 master 不是“不夠用”而是“不敢用”我第一次在某高校實驗室部署一個用于圖像處理Demo的Kubernetes集群時用的是最經(jīng)典的單 master 架構一臺8核16G的云服務器跑etcd kube-apiserver controller-manager scheduler三臺worker節(jié)點負責跑模型推理任務。初期一切順利直到某天凌晨三點監(jiān)控告警瘋狂刷屏——API Server響應延遲飆升到12秒所有kubectl命令超時正在運行的推理服務開始批量OOM重啟。運維同學緊急登錄發(fā)現(xiàn)master節(jié)點CPU持續(xù)100%、內存使用率98%而排查下來既不是業(yè)務負載突增日志顯示QPS平穩(wěn)也不是磁盤IO瓶頸iostat一切正常。最后翻到kube-controller-manager的日志里一行不起眼的報錯E0523 03:17:42.112345 1 leaderelection.go:331] error retrieving resource lock kube-system/kube-controller-manager: Get https://10.0.1.10:6443/apis/coordination.k8s.io/v1/namespaces/kube-system/leases/kube-controller-manager: context deadline exceeded這行報錯背后是一個被絕大多數(shù)新手忽略的底層事實單 master 的高可用性不是靠“它沒掛”來保障的而是靠“它不能掛”來硬扛的。只要master節(jié)點上任何一個核心組件尤其是apiserver或etcd因資源爭搶、內核OOM killer誤殺、系統(tǒng)級bug或短暫網(wǎng)絡抖動導致不可用整個集群就進入“半癱瘓”狀態(tài)——你無法擴縮容、無法查日志、無法更新配置甚至連Pod狀態(tài)都可能變成Unknown。更隱蔽的風險在于很多團隊把單master當成“過渡方案”結果一用就是半年甚至一年期間不斷往上面堆監(jiān)控、日志、CI/CD插件直到某次內核升級后etcd進程莫名退出才意識到備份快照根本沒驗證過恢復耗時47分鐘業(yè)務SLA直接違約。這不是理論推演。我在過去三年參與過的12個中等規(guī)模K8s落地項目中有7個在單master階段遭遇過至少一次超過5分鐘的控制平面中斷。其中3次源于etcd數(shù)據(jù)目錄權限被誤改2次是kubelet與apiserver證書過期未輪換還有2次純粹是宿主機內核panic——而這些故障在多master架構下本可以做到用戶無感。關鍵不在于“master會不會掛”而在于“掛了之后集群還能不能繼續(xù)提供服務”。單master的答案永遠是“不能”而多master的答案是“取決于你設計得夠不夠細”。所以“將單master升級為多master”從來不是一道簡單的“加機器”選擇題而是一次對集群治理能力的全面體檢。它逼你直面那些平時被掩蓋的問題etcd數(shù)據(jù)一致性策略是否合理證書體系是否支持滾動更新負載均衡器能否正確健康檢查apiserver的readiness端點甚至包括你的CI/CD流水線是否還硬編碼著master節(jié)點的IP地址這些問題在單master時代可以“先放一放”但在升級過程中任何一個疏漏都會讓整個遷移過程卡在凌晨三點讓你對著終端日志發(fā)呆。真正的難點從來不在“怎么做”而在“為什么必須現(xiàn)在做”。2. 多master的本質不是堆機器而是重構信任鏈很多人看到“多master”第一反應是“那我再買兩臺同配置服務器把apiserver、etcd、controller-manager全復制一份不就行了”——這是最危險的認知陷阱。多master集群不是單master的簡單橫向擴展而是一次對Kubernetes控制平面信任模型的徹底重構。它的核心目標只有一個讓集群的“大腦”具備自我診斷、自我選舉、自我恢復的能力而不是依賴某個物理節(jié)點的絕對穩(wěn)定。要理解這一點必須拆開看Kubernetes控制平面的四個核心組件如何協(xié)作etcd集群的唯一真相源Single Source of Truth存儲所有對象的狀態(tài)Pod、Service、ConfigMap等。它本身就是一個分布式鍵值數(shù)據(jù)庫天然支持多節(jié)點集群但其一致性協(xié)議Raft要求奇數(shù)節(jié)點3/5/7且對網(wǎng)絡延遲極其敏感。kube-apiserver集群的唯一入口Gateway所有讀寫請求必須經(jīng)過它。它本身是無狀態(tài)的可以水平擴展但所有實例必須連接到同一個etcd集群并共享一套認證授權配置。kube-controller-manager和kube-scheduler這兩個組件負責集群的“決策”如Pod調度、Node健康檢查、Endpoint同步。它們本身也是無狀態(tài)的但必須保證同一時刻只有一個實例在執(zhí)行關鍵操作否則會導致狀態(tài)沖突比如兩個scheduler同時給同一個Pod分配Node。問題來了如果只是把這四個組件原樣復制到三臺機器上會發(fā)生什么etcd集群能起來但三個apiserver會各自連接自己的本地etcd副本如果沒配對數(shù)據(jù)立刻分裂三個controller-manager會同時嘗試更新Node狀態(tài)導致NodeCondition反復在Ready/NotReady之間跳變負載均衡器把流量打到任意apiserver但某個apiserver背后的etcd副本落后了2秒你kubectl get pod看到的就可能是“已刪除”狀態(tài)而實際Pod還在運行。因此多master的真正技術骨架是由三組精密咬合的機制構成的2.1 etcd集群從“單點存儲”到“共識引擎”etcd不是“裝上就能用”的服務它是整個多master架構的地基。它的部署必須滿足三個硬性條件節(jié)點數(shù)必須為奇數(shù)Raft協(xié)議要求多數(shù)派quorum才能達成共識。3節(jié)點集群允許1節(jié)點宕機5節(jié)點允許2節(jié)點宕機。切記4節(jié)點集群的容錯能力與3節(jié)點完全相同都只允許1節(jié)點宕機但寫入性能反而更低因為每次寫入需獲得3票而非2票。網(wǎng)絡必須低延遲、高可靠Raft的心跳和日志復制對網(wǎng)絡RTT極其敏感。實測表明當三節(jié)點間平均RTT超過50ms時etcd leader選舉成功率開始下降超過100ms寫入延遲會指數(shù)級增長。這意味著跨可用區(qū)AZ部署etcd必須謹慎評估網(wǎng)絡質量。數(shù)據(jù)目錄必須獨立且持久化etcd的數(shù)據(jù)目錄默認/var/lib/etcd絕不能放在系統(tǒng)盤或臨時存儲上。我們曾在一個項目中因誤將etcd數(shù)據(jù)目錄掛載到云盤的臨時緩存分區(qū)導致一次宿主機重啟后etcd無法啟動因為緩存分區(qū)被清空Raft日志丟失。部署時每個etcd節(jié)點需通過--initial-cluster參數(shù)顯式聲明所有成員# 在node1上啟動etcd etcd --name infra1 \ --initial-advertise-peer-urls http://10.0.1.11:2380 \ --listen-peer-urls http://10.0.1.11:2380 \ --listen-client-urls http://10.0.1.11:2379 \ --advertise-client-urls http://10.0.1.11:2379 \ --initial-cluster-token etcd-cluster-1 \ --initial-cluster infra1http://10.0.1.11:2380,infra2http://10.0.1.12:2380,infra3http://10.0.1.13:2380 \ --initial-cluster-state new \ --data-dir /var/lib/etcd提示--initial-cluster-state new僅在首次初始化集群時使用。后續(xù)節(jié)點加入必須用existing否則會創(chuàng)建全新集群導致數(shù)據(jù)丟失。2.2 apiserver從“單一網(wǎng)關”到“無狀態(tài)服務池”apiserver是唯一可以真正水平擴展的組件。它的擴展邏輯非常清晰只要所有實例連接到同一個健康的etcd集群并共享完全一致的證書、RBAC規(guī)則和準入控制器配置它們就是完全等價的。這意味著你可以用任何標準的四層負載均衡器如HAProxy、Nginx、云廠商SLB將客戶端流量分發(fā)到多個apiserver實例。但這里有個致命細節(jié)負載均衡器的健康檢查必須指向apiserver的/readyz端點而不是簡單的TCP端口探測。因為apiserver進程存活不代表它能正常工作——它可能正卡在與etcd的連接上或者證書已過期。/readyz會主動檢查etcd連接、informer同步狀態(tài)等關鍵依賴。一個典型的HAProxy配置片段如下frontend k8s_apiserver bind *:6443 mode tcp default_backend apiserver_nodes backend apiserver_nodes mode tcp balance roundrobin option httpchk GET /readyz http-check expect status 200 server master1 10.0.1.11:6443 check fall 3 rise 2 server master2 10.0.1.12:6443 check fall 3 rise 2 server master3 10.0.1.13:6443 check fall 3 rise 2注意http-check expect status 200是關鍵。如果只用TCP檢查當apiserver因etcd斷連而無法響應readyz時HAProxy仍會把流量打過去導致客戶端收到503錯誤。2.3 controller-manager與scheduler從“單點決策”到“領導者選舉”這兩個組件的多實例部署核心在于領導者選舉Leader Election機制。Kubernetes內置了一套基于etcd的租約Lease對象的選舉協(xié)議。當多個controller-manager實例啟動時它們會嘗試在kube-system命名空間下創(chuàng)建一個名為kube-controller-manager的Lease對象。只有成功創(chuàng)建并持續(xù)續(xù)租該對象的實例才會成為Active Leader執(zhí)行所有控制循環(huán)其他實例則進入Spectator模式只監(jiān)聽Lease對象變化不做任何寫操作。這個機制的精妙之處在于它不依賴外部協(xié)調服務如ZooKeeper完全基于Kubernetes自身API構建且選舉過程對業(yè)務Pod完全透明。但這也帶來一個實操陷阱Lease對象的租約時間renewDeadline和心跳間隔leaseDuration必須與你的網(wǎng)絡環(huán)境匹配。默認值leaseDuration15s, renewDeadline10s在局域網(wǎng)內很穩(wěn)但在跨AZ部署時若網(wǎng)絡偶爾抖動導致心跳超時可能引發(fā)頻繁的leader切換造成Controller Manager日志刷屏。我們在線上環(huán)境通常將leaseDuration調至30秒renewDeadline調至20秒以換取更高的穩(wěn)定性。3. 升級路徑不是“停機重建”而是“滾動縫合”將一個運行中的單master集群升級為多master最常被問到的問題是“需要停機嗎”答案是可以做到零停機但前提是你的升級策略足夠精細且對每個環(huán)節(jié)的失敗回滾路徑了然于心。我們采用的是一種“滾動縫合”策略——像外科醫(yī)生縫合傷口一樣逐層、逐組件地將新master節(jié)點“縫入”現(xiàn)有集群每一步都可驗證、可回退。整個過程分為五個嚴格遞進的階段缺一不可3.1 階段一基礎設施準備與證書體系加固這是最容易被跳過的一步卻是后續(xù)所有步驟成敗的基礎。單master集群的證書通常是kubeadm init自動生成的其ca.crt和ca.key默認只保存在master節(jié)點上且apiserver證書的Subject Alternative Name (SAN)往往只包含master節(jié)點IP和localhost。當你新增master節(jié)點時它需要用自己的IP訪問apiserver而舊證書根本不包含這個IP握手必然失敗。因此必須首先生成一套新的、支持多IP的CA和apiserver證書。核心操作是從原master節(jié)點安全導出ca.crt和ca.key注意ca.key是最高機密傳輸必須加密創(chuàng)建一個新的kubeadm-config.yaml明確列出所有master節(jié)點的IP和DNS名稱kind: ClusterConfiguration apiVersion: kubeadm.k8s.io/v1beta3 kubernetesVersion: v1.28.0 certificatesDir: /etc/kubernetes/pki clusterName: my-cluster controlPlaneEndpoint: lb.my-cluster.local:6443 # 這是負載均衡器的VIP networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 --- kind: InitConfiguration apiVersion: kubeadm.k8s.io/v1beta3 nodeRegistration: criSocket: unix:///var/run/containerd/containerd.sock taints: [] labels: {} --- kind: JoinConfiguration apiVersion: kubeadm.k8s.io/v1beta3 controlPlane: localAPIEndpoint: advertiseAddress: 10.0.1.12 # 新master節(jié)點自己的IP bindPort: 6443 discovery: bootstrapToken: apiServerEndpoint: lb.my-cluster.local:6443 token: abcdef.0123456789abcdef caCertHashes: - sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx使用kubeadm init phase certs all --config kubeadm-config.yaml命令為所有master節(jié)點預生成證書包括apiserver、front-proxy、etcd等并將證書分發(fā)到對應節(jié)點。經(jīng)驗教訓我們曾在一個項目中因忘記為新master節(jié)點生成etcd-healthcheck-client.crt證書導致其etcd進程無法通過健康檢查被HAProxy踢出后端整整排查了3小時才定位到證書缺失。務必在分發(fā)前用openssl x509 -in /etc/kubernetes/pki/apiserver.crt -text -noout | grep DNS\|IP Address驗證所有預期IP和DNS都已寫入證書SAN字段。3.2 階段二etcd集群的“熱插入”這是整個升級中最驚心動魄的環(huán)節(jié)。目標是將原有的單節(jié)點etcd無縫融入一個三節(jié)點的新集群且全程不中斷現(xiàn)有業(yè)務。核心思路是先讓新節(jié)點以“l(fā)earner”學習者身份加入現(xiàn)有etcd集群同步完全部數(shù)據(jù)后再將其提升為正式member。具體步驟以新增node2為例在原masternode1上使用etcdctl將node2添加為learner# 在node1上執(zhí)行 ETCDCTL_API3 etcdctl --endpointshttps://127.0.0.1:2379 \ --cacert/etc/kubernetes/pki/etcd/ca.crt \ --cert/etc/kubernetes/pki/etcd/server.crt \ --key/etc/kubernetes/pki/etcd/server.key \ member add infra2 --learnertrue # 輸出類似Member 2a7b3c4d5e6f7g8h has been added to cluster 1a2b3c4d5e6f7g8h as learner在node2上啟動一個只讀的etcd實例連接到node1并指定其為learneretcd --name infra2 \ --initial-advertise-peer-urls http://10.0.1.12:2380 \ --listen-peer-urls http://10.0.1.12:2380 \ --listen-client-urls http://10.0.1.12:2379 \ --advertise-client-urls http://10.0.1.12:2379 \ --initial-cluster-token etcd-cluster-1 \ --initial-cluster infra1http://10.0.1.11:2380,infra2http://10.0.1.12:2380 \ --initial-cluster-state existing \ --data-dir /var/lib/etcd \ --learnertrue \ --learner-start-staticyes監(jiān)控learner同步進度。etcdctl --write-outtable endpoint status會顯示Is Learner列為true且Raft Term應與node1一致。等待etcdctl endpoint health返回healthy且etcdctl member list中infra2的狀態(tài)變?yōu)閟tarted。當同步完成通常需數(shù)分鐘到數(shù)十分鐘取決于數(shù)據(jù)量在node1上執(zhí)行etcdctl member promote learner-id將其提升為正式member。關鍵提示--learner-start-staticyes參數(shù)至關重要。它確保learner在啟動時不會嘗試參與選舉只專注同步數(shù)據(jù)。若省略此參數(shù)learner可能因Raft狀態(tài)混亂而崩潰。3.3 階段三新master節(jié)點的“控制平面注入”當etcd集群已穩(wěn)定為三節(jié)點后下一步是將新master節(jié)點的控制平面組件apiserver、controller-manager、scheduler接入。此時新節(jié)點上的kubelet尚未加入集群它只是一個“裸機”。我們需要用kubeadm join命令但不是加入worker節(jié)點的方式而是以--control-plane參數(shù)加入控制平面。在node2上執(zhí)行kubeadm join lb.my-cluster.local:6443 \ --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \ --control-plane \ --certificate-key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx這個命令會啟動kubelet并將其注冊為master節(jié)點帶有node-role.kubernetes.io/control-plane:NoSchedule污點將預生成的證書復制到/etc/kubernetes/pki/啟動新的apiserver、controller-manager、scheduler容器并配置它們連接到lb.my-cluster.local:6443即我們即將配置的HAProxy VIP將新master節(jié)點的etcd member信息寫入集群。執(zhí)行后用kubectl get nodes -o wide應能看到node2狀態(tài)為NotReady因為CNI插件尚未部署但kubectl get pods -n kube-system應能看到新的kube-apiserver-node2、kube-controller-manager-node2等Pod已Running。3.4 階段四負載均衡器的“流量接管”這是用戶感知最明顯的一步。在此之前所有kubectl命令和CI/CD工具都直接連接原master節(jié)點IP如10.0.1.11:6443。現(xiàn)在我們必須將所有流量切換到HAProxy的VIP如lb.my-cluster.local:6443。操作本身很簡單修改/etc/kubernetes/admin.conf文件將server:字段從https://10.0.1.11:6443改為https://lb.my-cluster.local:6443然后重新加載kubectl配置。但真正的挑戰(zhàn)在于驗證首先用curl -k https://lb.my-cluster.local:6443/readyz確認VIP可達且apiserver健康然后執(zhí)行kubectl get nodes觀察是否能穩(wěn)定返回所有節(jié)點列表包括新master最關鍵的是執(zhí)行一個“寫操作”kubectl scale deployment nginx --replicas5確認Pod能成功創(chuàng)建并調度到worker節(jié)點。實戰(zhàn)技巧在切換VIP前建議先在HAProxy配置中將新master節(jié)點node2的權重設為1而原masternode1權重設為10實現(xiàn)灰度流量導入。觀察10分鐘無異常后再將權重均等化。這樣即使新節(jié)點apiserver有兼容性問題也只影響10%的請求。3.5 階段五原master節(jié)點的“優(yōu)雅退役”當新master集群穩(wěn)定運行24小時以上且所有監(jiān)控指標API Latency P99、etcd leader changes per hour、controller-manager leader transitions均處于基線范圍內后就可以考慮將原master節(jié)點node1從控制平面中移除。移除不是簡單地關機而是要確保其etcd member和kubernetes node資源被干凈清理在node1上執(zhí)行kubeadm reset --force這會停止所有kubernetes組件并清理/etc/kubernetes/目錄在剩余任一master節(jié)點上用etcdctl member remove node1-member-id將其從etcd集群中永久刪除執(zhí)行kubectl delete node node1從kubernetes API中移除其節(jié)點記錄。至此單master到多master的升級宣告完成。整個過程從準備到最終退役我們在線上環(huán)境的標準耗時是4小時17分鐘含2小時觀察期且全程業(yè)務無感知。4. 驗證與反脆弱別只盯著“能不能用”要看“怎么失效”升級完成后很多人會松一口氣執(zhí)行幾個kubectl get命令確認一切正常就認為大功告成。這是最大的認知誤區(qū)。多master集群的價值不在于它“正常時有多好”而在于它“異常時有多穩(wěn)”。因此驗證工作必須圍繞“失效場景”展開這才是真正的反脆弱測試。我們有一套標準化的“混沌驗證清單”每次升級后必做4.1 場景一模擬單master節(jié)點宕機這是最基礎的測試。選擇一臺master節(jié)點如node2執(zhí)行sudo systemctl stop kubelet強制其離線。預期結果kubectl get nodes應在30秒內將node2狀態(tài)標記為NotReadykubectl get pods -A應能正常返回且所有Running Pod狀態(tài)不變kubectl logs、kubectl exec等交互式命令應能正常工作它們會自動重試到其他apiserverkubectl scale等寫操作應能在2秒內完成無超時。關鍵觀察點用kubectl get componentstatuses雖已棄用但仍是快速檢查controller-manager/scheduler狀態(tài)的捷徑確認controller-manager和scheduler的Status仍為Healthy且其Age字段顯示的Leader節(jié)點已切換到其他master。4.2 場景二模擬etcd網(wǎng)絡分區(qū)比單節(jié)點宕機更危險的是網(wǎng)絡分區(qū)Network Partition。例如讓node1和node2之間的網(wǎng)絡完全不通但node1-node3、node2-node3網(wǎng)絡正常。此時etcd集群會分裂為兩個子集{node1}和{node2, node3}。根據(jù)Raft協(xié)議只有擁有多數(shù)派2/3的子集{node2, node3}能繼續(xù)提供寫服務而{node1}會進入只讀狀態(tài)。測試方法在node1上執(zhí)行sudo iptables -A OUTPUT -d 10.0.1.12 -j DROP sudo iptables -A OUTPUT -d 10.0.1.13 -j DROP模擬其無法與其他節(jié)點通信。預期結果etcdctl endpoint health在node1上會顯示unhealthy而在node2/node3上顯示healthykubectl get nodes應能正常返回且node1狀態(tài)為NotReady最關鍵的是在node2或node3上執(zhí)行kubectl create deploy test --imagenginx應能成功創(chuàng)建Deployment且其Pod被調度到worker節(jié)點。這證明控制平面的寫能力未受影響。教訓分享我們曾在一個金融客戶項目中因未做此測試上線后遭遇一次跨機房網(wǎng)絡抖動導致主數(shù)據(jù)中心的master節(jié)點被隔離但集群因缺乏多數(shù)派而拒絕所有寫操作CI/CD流水線全部阻塞。此后我們將此測試納入所有集群的SOP。4.3 場景三模擬apiserver證書輪換證書過期是生產(chǎn)環(huán)境中最隱蔽的故障源。Kubernetes的證書默認有效期為1年但很多團隊從未規(guī)劃過輪換流程。多master集群的證書輪換必須確保所有master節(jié)點的證書在同一窗口期內更新否則會出現(xiàn)部分apiserver因證書過期而被客戶端拒絕的情況。標準輪換流程在任一master節(jié)點上執(zhí)行kubeadm certs renew all生成新證書將新證書/etc/kubernetes/pki/下的所有.crt和.key文件安全分發(fā)到所有master節(jié)點覆蓋舊文件逐個重啟各master節(jié)點上的kubelet服務sudo systemctl restart kubelet使其加載新證書用openssl x509 -in /etc/kubernetes/pki/apiserver.crt -dates驗證每個節(jié)點的證書有效期已更新。避坑指南kubeadm certs renew命令不會自動更新admin.conf、kubelet.conf等客戶端配置文件中的證書。你必須手動用kubeadm init phase kubeconfig all --config kubeadm-config.yaml重新生成并分發(fā)到所有管理員和CI/CD服務器。我們?yōu)榇藢iT寫了一個Ansible Playbook確保零遺漏。4.4 場景四壓力下的Leader選舉穩(wěn)定性高并發(fā)場景下controller-manager的Leader選舉是否健壯我們用一個簡單的壓測腳本來驗證# 持續(xù)每秒創(chuàng)建一個Job持續(xù)5分鐘 for i in {1..300}; do kubectl create job stress-job-$i --imagebusybox -- sh -c sleep 1 sleep 1 done同時在后臺監(jiān)控kubectl get events -n kube-system | grep leader changed。一個健康的集群在300次Job創(chuàng)建過程中l(wèi)eader切換次數(shù)應為0或1次初始選舉。如果出現(xiàn)5次以上切換則說明etcd集群或網(wǎng)絡存在隱性瓶頸需要進一步排查。5. 運維守則多master不是終點而是新運維范式的起點當集群成功升級為多master后一個全新的運維挑戰(zhàn)才真正開始。它不再是一個“單點設備”而是一個需要持續(xù)協(xié)同治理的分布式系統(tǒng)。我們總結了三條鐵律是過去所有踩坑經(jīng)驗的結晶5.1 守則一etcd集群的“黃金三角”監(jiān)控必須前置etcd的健康是整個集群的生命線但它的指標維度遠超普通服務。我們強制要求所有多master集群必須監(jiān)控以下三個核心指標并設置分級告警指標健康閾值告警級別說明etcd_disk_wal_fsync_duration_seconds_bucket(P99) 10msP1WAL寫入延遲過高預示磁盤IOPS瓶頸或硬件故障etcd_network_peer_round_trip_time_seconds_bucket(P99) 50msP2節(jié)點間網(wǎng)絡延遲跨AZ部署時此值易超標etcd_server_leader_changes_seen_total0 (24h)P1Leader頻繁切換通常由網(wǎng)絡抖動或etcd配置不當引起實操心得我們曾用PrometheusGrafana搭建了一套etcd專項看板其中最有效的視圖是一個“Raft狀態(tài)矩陣”X軸是所有etcd節(jié)點Y軸是is_leader,is_learner,raft_term,raft_index等狀態(tài)字段每個單元格用顏色標識綠色正常黃色警告紅色異常。運維人員一眼就能看出哪個節(jié)點狀態(tài)異常無需翻日志。5.2 守則二所有master節(jié)點的“配置漂移”必須零容忍在單master時代修改/etc/kubernetes/manifests/kube-apiserver.yaml是常見操作。但在多master時代任何對單個master節(jié)點配置的手動修改都是災難的種子。因為kubeadm管理的靜態(tài)Pod配置是通過kubeadm init或kubeadm upgrade統(tǒng)一生成的。如果你在node2上手動加了一個--feature-gates...參數(shù)下次kubeadm upgrade時這個參數(shù)會被覆蓋導致node2 apiserver啟動失敗。解決方案只有一條所有配置變更必須通過kubeadm config進行聲明式管理。例如要為所有master節(jié)點啟用ServerSideApply特性門控正確的做法是編輯kubeadm-config.yaml在ClusterConfiguration下添加apiServer: extraArgs: feature-gates: ServerSideApplytrue執(zhí)行kubeadm upgrade apply v1.28.0 --config kubeadm-config.yaml該命令會自動將新配置推送到所有master節(jié)點。血淚教訓某電商客戶曾因一名工程師在生產(chǎn)master上手動修改了kube-scheduler的--bind-address參數(shù)導致其無法綁定到0.0.0.0只能監(jiān)聽127.0.0.1。當HAProxy流量打過來時連接被拒絕。問題持續(xù)了17分鐘直到有人想起kubeadm的配置管理機制。從此他們將/etc/kubernetes/manifests/目錄設為只讀并在CI/CD中加入配置合規(guī)性掃描。5.3 守則三備份與恢復的“雙盲演練”必須季度執(zhí)行多master集群的備份絕不是簡單地etcdctl snapshot save。一個完整的備份策略必須包含etcd快照使用etcdctl snapshot save并驗證其完整性etcdctl snapshot statusKubernetes證書/etc/kubernetes/pki/目錄的完整歸檔kubeadm配置kubeadm-config.yaml的最新版本集群狀態(tài)快照kubectl get all --all-namespaces -o yaml cluster-state.yaml。但更重要的是恢復演練。我們要求每季度進行一次“雙盲演練”由另一組運維人員在完全不知道備份介質位置和恢復步驟的情況下僅憑文檔從零開始恢復一個測試集群。演練必須覆蓋兩種場景場景A小范圍故障僅etcd數(shù)據(jù)損壞用快照恢復etcd其他組件保持運行場景B全集群毀滅所有master節(jié)點不可用需用備份介質從頭部署全新集群并將worker節(jié)點重新加入。個人體會我在某次雙盲演練中發(fā)現(xiàn)備份腳本里一個tar命令漏寫了-C參數(shù)導致證書目錄被錯誤打包。這個Bug在三年里從未暴露直到演練時恢復失敗。那一刻我深刻意識到備份的價值不在于它存在而在于它被證明能用。現(xiàn)在我們的備份腳本末尾必定跟著一行etcdctl snapshot restore ... echo Restore OK失敗則立即告警。多master集群的終極價值不在于它讓你少操了多少心而在于它讓你在面對故障時擁有了從容選擇“何時修復”而非“是否能修”的底氣。這種底氣來自于對每一個組件原理的敬畏對每一條配置參數(shù)的審慎以及對每一次看似微小的變更都抱持著“它可能在凌晨三點毀掉一切”的警惕。這才是運維的真正修行。