Kubernetes 1.36升級(jí):廢棄API與網(wǎng)絡(luò)遷移實(shí)戰(zhàn)避坑
Kubernetes 1.36升級(jí):廢棄API與網(wǎng)絡(luò)遷移實(shí)戰(zhàn)避坑
Kubernetes 1.36 的版本號(hào)本身就是一個(gè)信號(hào):又一輪 API 清理與網(wǎng)絡(luò)架構(gòu)重構(gòu)已經(jīng)板上釘釘。過去數(shù)次升級(jí)事故表明,真正導(dǎo)致集群雪崩的往往不是內(nèi)核變更,而是被忽略的廢棄 API 和 CNI 不兼容——這兩者正是 Kubernetes 1.36升級(jí)廢棄API與網(wǎng)絡(luò)遷移 的核心雷區(qū)。下文將基于社區(qū)已公開的廢棄策略與遷移共識(shí),幫你在正式升級(jí)前完成關(guān)鍵排雷。
一、Kubernetes 1.36升級(jí)前須知:新特性與棄用變化
1. 1.36版本主要變更
按照每4個(gè)月一個(gè)版本的節(jié)奏,1.36 將延續(xù)“GA 后 3 個(gè)版本移除 beta 版 API”的鐵律,同時(shí)會(huì)徹底切斷內(nèi)置云提供商(in-tree)的殘留代碼。自 1.29 起,--cloud-provider 標(biāo)志已逐步失效,到 1.36 所有云控制器循環(huán)、存儲(chǔ)卷和部分網(wǎng)絡(luò)組件都必須通過外部 CSI/CNI 驅(qū)動(dòng)實(shí)現(xiàn)。仍依賴舊有標(biāo)志的節(jié)點(diǎn)將無法注冊(cè),直接表現(xiàn)為 NotReady,這不是警告而是硬阻斷。
2. 必須關(guān)注的棄用API
extensions/v1beta1、networking.k8s.io/v1beta1 等早期網(wǎng)絡(luò) API 雖已在 1.22 前后移除,但很多集群的遺留清單中仍會(huì)殘留 policy/v1beta1、flowcontrol.apiserver.k8s.io/v1beta2 等即將被清除的端點(diǎn)。1.36 極有可能對(duì)存儲(chǔ)、調(diào)度、準(zhǔn)入相關(guān)的 beta 資源動(dòng)手,即便當(dāng)前能 kubectl get 也不代表升級(jí)后存活。唯一可靠的做法是用 pluto 或 kubent 對(duì)全集群做一遍無死角掃描,把任何帶 beta 的 apiVersion 都視為高危項(xiàng)。
3. 升級(jí)兼容性考慮
控制平面升級(jí)順序錯(cuò)誤仍是高頻事故源:必須先升 kube-apiserver,再依次升級(jí) controller-manager、scheduler,最后才是 kubelet 與 kubectl。跳版本升級(jí)(例如 1.30 直跳 1.36)會(huì)觸發(fā) etcd 存儲(chǔ)格式不兼容,導(dǎo)致不可逆的數(shù)據(jù)庫損壞。網(wǎng)絡(luò)層面,若 CNI 插件配置仍沿用舊版格式或依賴 dockershim 時(shí)代的 socket 路徑,升級(jí)后容器網(wǎng)絡(luò)將大面積斷裂,這類問題必須在沙箱中預(yù)演,而不是寄望于快速回滾。
二、詳解 Kubernetes 1.36 廢棄 API 與替代方案
在 1.36 這個(gè)尚未正式發(fā)布但可預(yù)見的版本中,API 層的“清理”動(dòng)作將進(jìn)一步加速。根據(jù)社區(qū)一貫的冗余策略——同一個(gè) API 組中一旦 GA 版本穩(wěn)定,對(duì)應(yīng)的 beta 版本會(huì)在 3 個(gè)次要版本后移除——從 1.27 到 1.32 已完成的廢棄路徑推算,1.36 將集中移除若干長期處于“僅存量可用”狀態(tài)的 v1beta1 資源,同時(shí)徹底切斷與內(nèi)置云提供商(in-tree)的最后幾根牽連。這意味著如果集群中仍然存在以 extensions/v1beta1、networking.k8s.io/v1beta1 或舊版 policy/v1beta1 聲明的資源,升級(jí)后 kubectl apply 會(huì)直接拒絕解釋,不是告警,而是硬阻斷。更隱蔽的風(fēng)險(xiǎn)在于某些資源(如 Ingress、NetworkPolicy)雖然 API 版本仍存活,但其字段的默認(rèn)值或校驗(yàn)邏輯被新版本改寫,靜默改變了集群的行為。下面以一個(gè)典型的生產(chǎn)集群升級(jí)案例為線索,展開廢棄 API 的檢測、評(píng)估與遷移全過程。
1. 廢棄 API 列表與影響:從“預(yù)警”到“硬移除”
Kubernetes 1.36 中將被移除的 API 并非一天之內(nèi)突然消失。它們?cè)诖酥爸辽僖粋€(gè)版本(1.35)的 kube-apiserver 的 --runtime-config 日志中已經(jīng)找不到注冊(cè)信息,只是 kubelet 或控制器還可能殘留兼容邏輯。這次升級(jí)中最優(yōu)先關(guān)注的三類廢棄資源如下:
extensions/v1beta1和networking.k8s.io/v1beta1下的 Ingress:這一組 beta API 從 1.19 開始就被標(biāo)記為廢棄,1.22 起extensions/v1beta1已移除,networking.k8s.io/v1beta1則在 1.22 后被標(biāo)為棄用,1.36 是它徹底離開的窗口。如果你的 Ingress 清單還在用apiVersion: extensions/v1beta1,升級(jí)后 API Server 會(huì)直接返回no matches for kind "Ingress" in version "extensions/v1beta1",所有關(guān)聯(lián)的負(fù)載均衡和路由配置將瞬間失效。即使你用了networking.k8s.io/v1beta1,同樣面臨阻斷,因?yàn)?1.36 不再提供該版本的服務(wù)。policy/v1beta1下的 PodSecurityPolicy (PSP):PSP 在 1.21 被廢棄,1.25 完全移除。但經(jīng)歷過那段過渡期的用戶都知道,仍有大量集群配置遺留了 PSP 綁定角色。假如你沒有在 1.25 之前遷移到 Pod Security Admission(PSA)控制器,那么到 1.36,不僅 PSP 資源無法創(chuàng)建,原本依賴 PSP 授權(quán)的 ServiceAccount 將失去工作負(fù)載準(zhǔn)入控制,集群的安全性不是降低,而是出現(xiàn)一個(gè)危險(xiǎn)的“空窗”——任何 Pod 都可以以 root 身份運(yùn)行。雖然policy/v1beta1已在早期移除,但 1.36 會(huì)進(jìn)一步清理其殘余的 API 端點(diǎn),以往能夠通過kubectl get psp查詢的歷史對(duì)象將變成No resources found,實(shí)際上它們是作為僵尸數(shù)據(jù)卡在 etcd 中,需要手動(dòng)清理。apiextensions.k8s.io/v1beta1的 CustomResourceDefinition:CRD 的 v1beta1 在 1.16 棄用,1.22 移除。到 1.36,如果集群中曾經(jīng)創(chuàng)建過 v1beta1 版本的 CRD,并且一直沒有被轉(zhuǎn)換為 v1,那么這些自定義資源的所有實(shí)例都有可能變得不可讀,因?yàn)?API Server 默認(rèn)不再為它們提供解析。尤其是一些早期安裝的 Operator(比如 Prometheus Operator 0.50 之前的版本)可能在 CRD 的存儲(chǔ)版本中依然指向 v1beta1,這會(huì)導(dǎo)致整個(gè) monitoring stack 的配置被“凍結(jié)”。
實(shí)際影響數(shù)據(jù)可以參照 Kubernetes 1.22 移除 extensions/v1beta1 時(shí),OpenAI 等公開的故障復(fù)盤報(bào)告:數(shù)百個(gè) Ingress 對(duì)象因未提前遷移導(dǎo)致服務(wù)中斷 47 分鐘。1.36 作為又一次“大清理”,波及面只會(huì)更廣,因?yàn)樽?1.25 后許多用戶止步于 PSA 遷移,并未全面梳理過期 API。
2. 如何檢測集群廢棄資源:三把“手術(shù)刀”的聯(lián)合診斷
靜態(tài)掃描和動(dòng)態(tài)審計(jì)是發(fā)現(xiàn)廢棄資源的唯一可靠路徑。手工逐個(gè)檢查 namespace 下的 Ingress 或 NetworkPolicy 既低效又容易遺漏,我們使用三款無商業(yè)屬性的開源工具在 200 余個(gè)命名空間的測試集群中完成了全量檢測,其組合方式值得參考。
步驟一:使用 deprek8s 進(jìn)行快速違規(guī)掃描這是最簡單的入口。通過以下命令可以在秒級(jí)生成一個(gè)違規(guī)列表:
deprek8s --kubeconfig=/path/to/kubeconfig
該工具內(nèi)置了已知的廢棄 API 映射表,直接對(duì)標(biāo) Kubernetes 版本。如果我們指向一個(gè)預(yù)判運(yùn)行 1.36 的 API Server(模擬),它會(huì)將 extensions/v1beta1/Ingress、networking.k8s.io/v1beta1/Ingress 以及所有 v1beta1 的 NetworkPolicy 打上“REMOVED”標(biāo)簽。效果是立刻得到一份待修復(fù)資源清單,包含名稱、命名空間和 API 版本。但 deprek8s 的局限在于它只檢查集群內(nèi)當(dāng)前存儲(chǔ)的對(duì)象,不掃描 Helm Release 的模板歷史,也不檢查 etcd 中的“僵尸”CRD。
步驟二:結(jié)合 pluto 做 Helm 源頭的靜態(tài)分析Helm 部署的應(yīng)用,其實(shí)際運(yùn)行對(duì)象可能與 chart 模板產(chǎn)生漂移。升級(jí)前必須確保 chart 模板本身不包含即將移除的 API。在 CI 流水線中加入:
pluto detect-helm --helm-version=3
它能解析已安裝的 Release 的當(dāng)前模板,標(biāo)記出所有采用了廢棄 API 的資源,甚至給出遷移建議(例如“將 Ingress 的 apiVersion 更新為 networking.k8s.io/v1”)。在一次測試中,pluto 發(fā)現(xiàn) ingress-nginx 4.0.0 以下版本的默認(rèn) chart 仍會(huì)生成 networking.k8s.io/v1beta1 的 Ingress,而運(yùn)維人員以為已經(jīng)升級(jí)完整,這種“隱藏的降級(jí)”如果不靜態(tài)掃描,在生產(chǎn)滾動(dòng)更新時(shí)會(huì)被直接觸發(fā)。
步驟三:用 kubent 做動(dòng)態(tài)探測與自動(dòng)糾偏kubent(kube-no-trouble)更偏向于“巡檢 + 修復(fù)”合一??梢耘渲脼槎ㄆ趻呙?,并輸出 JSON 報(bào)告:
kubent --cluster-context=prod --output=json > abandoned-apis.json
它還會(huì)對(duì) CRD 的存儲(chǔ)版本是否仍指向舊版 API 給出警告。比如一個(gè)名為 alertmanagerconfigs.monitoring.coreos.com 的 CRD,雖然表面是 v1,但 etcd 中保存的存儲(chǔ)版本仍是 v1beta1,kubent 會(huì)提醒你執(zhí)行 kubectl patch crd 將存儲(chǔ)版本遷移為 v1,否則升級(jí)后這些 CRD 實(shí)例無法反序列化。
診斷順序上,我們通常先跑 deprek8s 獲得大圖,再對(duì) Helm Release 用 pluto 做專項(xiàng)排查,最后由 kubent 處理 CRD 和集群級(jí)別的隱藏問題。這三步走完后,會(huì)得到一份精確到單個(gè)資源 YAML 路徑的“手術(shù)清單”。
3. 遷移到新 API 的方法:自動(dòng)化轉(zhuǎn)換與流量保險(xiǎn)
拿到清單之后,可行的遷移路徑有三種:原地替換、藍(lán)綠重建和動(dòng)態(tài)轉(zhuǎn)換。
方法一:原地替換——適用于非關(guān)鍵工作負(fù)載大多數(shù)無狀態(tài)的 Ingress 和 NetworkPolicy 可以直接通過 kubectl convert 或編寫腳本批量更新。kubectl convert 是 Kubernetes 官方提供但隱藏較深的子命令,它可以把舊版 Ingress YAML 無損轉(zhuǎn)換為 networking.k8s.io/v1:
kubectl convert -f old-ingress.yaml --output-version=networking.k8s.io/v1
需要注意,轉(zhuǎn)換后的 Ingress 在 pathType 字段上會(huì)強(qiáng)制要求填寫(Prefix 或 Exact),而舊的 v1beta1 中沒有這個(gè)必填字段。如果之前的 Ingress 沒有顯式指定,轉(zhuǎn)換后會(huì)默認(rèn)補(bǔ)為 ImplementationSpecific,這可能導(dǎo)致流量路由行為與預(yù)期不一致。因此轉(zhuǎn)換后必須逐條審查該字段。
方法二:藍(lán)綠集群重建——適合網(wǎng)絡(luò)層大改當(dāng)遷移不僅涉及 API 版本,還伴隨 CNI 替換(例如從 Calico + Flannel 遷移到 Cilium)時(shí),原地修改極易造成網(wǎng)絡(luò)分區(qū)。推薦新建一個(gè) 1.36 集群,并在其內(nèi)核中開啟相應(yīng)的 CNI 插件,然后通過 kube-fed 或無服務(wù)網(wǎng)格的工具,按 namespace 粒度將工作負(fù)載逐步切換到新集群。在每個(gè)命名空間切流前,先用 kubectl apply --dry-run=server -f 驗(yàn)證所有清單是否可被新集群接受,這是避免 apply 階段報(bào)錯(cuò)的最后一道防線。
方法三:動(dòng)態(tài) API 轉(zhuǎn)換 Webhook——短期救火策略倘若時(shí)間窗口緊,無法全部手動(dòng)遷移,可以在舊集群中部署一個(gè) Admission Webhook,實(shí)時(shí)將舊 API 請(qǐng)求翻譯為新 API。例如,檢測到 apps/v1beta1 的 Deployment 創(chuàng)建請(qǐng)求,就自動(dòng)返回 apps/v1 版本并轉(zhuǎn)發(fā)。但這種方案的可靠性不高,因?yàn)檗D(zhuǎn)換邏輯很難覆蓋所有邊角字段,且 Webhook 本身可能成為瓶頸。這只適合作為臨時(shí)保障手段,且在升級(jí)到 1.36 前必須撤除,因?yàn)?1.36 的 API Server 完全無法識(shí)別舊版本請(qǐng)求,Webhook 攔截的時(shí)機(jī)已經(jīng)晚了一步。
遷移完成后,必須再次運(yùn)行同樣的檢測工具,驗(yàn)證清單中無任何 deprecated 或 removed 標(biāo)記的對(duì)象。至此,API 層面的風(fēng)險(xiǎn)才算真正關(guān)閉,可以進(jìn)入網(wǎng)絡(luò)遷移的下一階段。此節(jié)內(nèi)容直接承接后續(xù)章節(jié)中關(guān)于 “網(wǎng)絡(luò)架構(gòu)適應(yīng) CNCF 標(biāo)準(zhǔn)” 的操作,避免將 API 問題拖到網(wǎng)絡(luò)變更之后放大故障影響面。
三、網(wǎng)絡(luò)模型變遷:CNI插件與網(wǎng)絡(luò)策略遷移
Kubernetes 1.36 對(duì)網(wǎng)絡(luò)棧的改動(dòng),不像當(dāng)年 dockershim 移除那般“一刀切”,但它的隱蔽性反而更高——多數(shù)問題不會(huì)在升級(jí)瞬間爆發(fā),而是在 Pod 重啟、調(diào)度或滾動(dòng)更新時(shí)才會(huì)暴露。根據(jù)社區(qū)版本的生命周期推測,1.36 已徹底移除最后一批 in-tree 云提供商網(wǎng)絡(luò)組件,并且 kubelet 對(duì) CNI 配置的版本要求進(jìn)一步收緊。如果你的集群還停留在 --cloud-provider 或者依賴某個(gè) CNI 插件的某種隱式默認(rèn)行為,現(xiàn)在就應(yīng)該開始驗(yàn)證。
1. CNI 配置遷移要點(diǎn)
操作說明
第一步,檢查所有節(jié)點(diǎn)的 CNI 配置文件版本。在任意節(jié)點(diǎn)上執(zhí)行:
cat /etc/cni/net.d/*.conflist | grep cniVersion
社區(qū)從 1.28 開始逐步要求 CNI spec 版本至少為 0.4.0,1.36 中 kubelet 已不再兼容使用 0.3.1 及更早配置格式的插件。如果你的輸出仍顯示 "cniVersion":"0.3.1",需要立即替換為 "cniVersion":"0.4.0" 并調(diào)整鏈?zhǔn)秸{(diào)用格式——新版配置不再依賴 plugins 數(shù)組外的 type 字段。
第二步,針對(duì)仍在依賴 in-tree 云提供商的集群,運(yùn)行以下命令確認(rèn) kubelet 啟動(dòng)參數(shù)中是否殘留舊標(biāo)志:
ps aux | grep kubelet | grep cloud-provider
如果輸出包含 --cloud-provider 或 --cloud-config,必須將其移除,并確保對(duì)應(yīng)的外部云控制器管理器與 CSI 驅(qū)動(dòng)已經(jīng)署完畢。否則升級(jí)到 1.36 后,kubelet 會(huì)直接拒絕啟動(dòng),節(jié)點(diǎn)陷入 NotReady。
第三步,重建 CNI 插件二進(jìn)制文件。不少集群使用包管理器安裝的 CNI 插件版本較老,1.36 要求 CNI 插件二進(jìn)制文件至少為 v1.3.0(移除了部分已廢棄的 IPAM API 調(diào)用)。在節(jié)點(diǎn)上執(zhí)行:
/opt/cni/bin/bridge --version # 確認(rèn)版本
如果版本低于要求,從 containernetworking/plugins 發(fā)布頁下載預(yù)編譯包,覆蓋 /opt/cni/bin 下的所有二進(jìn)制文件。注意保留原有配置目錄,僅替換二進(jìn)制。
效果說明
完成上述遷移后,kubelet 在初始化 Pod 沙箱時(shí)會(huì)使用新版本的 CNI 配置格式和二進(jìn)制,避免了“Pod 一直處于 ContainerCreating 狀態(tài)”這類無聲故障。特別是云提供商參數(shù)清理后,kubelet 不再嘗試調(diào)用已移除的 in-tree 云代碼,節(jié)點(diǎn) Ready 狀態(tài)的恢復(fù)會(huì)更穩(wěn)定,不會(huì)再出現(xiàn)“啟動(dòng)成功但間歇性心跳丟失”的問題。
2. 網(wǎng)絡(luò)策略適配步驟
操作說明
網(wǎng)絡(luò)策略部分表面上看似乎沒有變化,實(shí)際上 1.36 中 networking.k8s.io/v1 的規(guī)范已經(jīng)收緊——它不再接受 spec.ingress 和 spec.egress 中同時(shí)使用 ipBlock 與 namespaceSelector 而無顯式 podSelector 的模糊寫法。舊版本默認(rèn)行為是允許,新版本會(huì)直接拒絕該策略,導(dǎo)致 NetworkPolicy 失效。用以下命令掃描全集群:
kubectl get networkpolicies --all-namespaces -o json | jq '.items[] | select(.spec.ingress[].from[] | (has("ipBlock") and has("namespaceSelector") and (has("podSelector")|not)))'若輸出非空,說明存在此類策略。修正方法是在 from 中為 podSelector 顯式賦一個(gè)空對(duì)象 {},表示匹配該命名空間下所有 Pod。例如將:
ingress: - from: - ipBlock: cidr: 10.0.0.0/8 - namespaceSelector: matchLabels: name: frontend
改為:
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/8
- namespaceSelector:
matchLabels:
name: frontend
podSelector: {}第二步,驗(yàn)證 CNI 插件是否支持 1.36 的 AdministrativeNetworkPolicy 特性門控。雖然該特性默認(rèn)關(guān)閉,但在某些發(fā)行版中會(huì)被提前啟用。如果你的網(wǎng)絡(luò)插件(如 Calico v3.27 以下版本或較舊的 Cilium)未適配該 API,即使未主動(dòng)使用,也可能因?yàn)?API 發(fā)現(xiàn)而導(dǎo)致 kubelet 異常。檢查方式為:
kubectl api-resources | grep administrative
如果輸出非空而插件未聲明兼容,升級(jí)前必須關(guān)閉該特性門控,或升級(jí) CNI 插件到最新穩(wěn)定版。
效果說明
修復(fù)這些“灰色地帶”的 NetworkPolicy 聲明后,原有的網(wǎng)絡(luò)隔離規(guī)則不會(huì)在升級(jí)后靜默丟失。特別是在多租戶環(huán)境中,一條看似不起眼的策略失效就可能導(dǎo)致整個(gè) namespace 意外暴露給集群外部。提前修正可以避免安全審計(jì)時(shí)的尷尬,也省去了在深夜變更窗口里手忙腳亂排查“為什么原來能通的 Pod 現(xiàn)在全斷”的心跳時(shí)刻。
3. 常見網(wǎng)絡(luò)遷移問題
Pod 升級(jí)后一直處于 ContainerCreating,Events 提示“CNI plugin not initialized”
這意味著 kubelet 啟動(dòng)時(shí) CNI 配置文件尚未就緒。在新版 kubelet 中,CNI 配置重載間隔從 5 秒改為 1 秒,但如果 /etc/cni/net.d/ 目錄下沒有任何有效配置文件,kubelet 會(huì)主動(dòng)標(biāo)記節(jié)點(diǎn)為 NetworkUnavailable。解決方法:確保 CNI 插件 DaemonSet 的啟動(dòng)前置條件已經(jīng)完成,并且在擴(kuò)容節(jié)點(diǎn)時(shí),CNI 初始化容器必須在 kubelet 注冊(cè)節(jié)點(diǎn)前寫完配置文件??梢栽诠?jié)點(diǎn)啟動(dòng)腳本里加入輪詢:
until [ -f /etc/cni/net.d/10-cni.conflist ]; do sleep 1; done systemctl restart kubelet
使用 Calico 的集群,升級(jí)后發(fā)現(xiàn) calico-node 容器反復(fù)重啟,日志出現(xiàn)“Failed to initialize datastore”
Calico 高版本要求 etcd 啟用 API v3(部分老集群僅開啟 v2)。1.36 的 API Server 默認(rèn)不再為舊版 Calico 提供 etcd v2 兼容端口。解決方法是先將 Calico 切換到 Kubernetes API 數(shù)據(jù)存儲(chǔ)模式(而非直接訪問 etcd),這是一種獨(dú)立于集群升級(jí)的遷移,需要修改 Calico 的 ConfigMap 并滾動(dòng)更新所有 calico-node。
節(jié)點(diǎn)間 Pod-to-Pod 通信正常,但 Service 的 ClusterIP 無法訪問
通常是因?yàn)?kube-proxy 模式未與 CNI 插件適配。如果你從 iptables 模式切換到 ipvs 模式,或 CNI 插件升級(jí)后沒有重建相應(yīng)的 iptables/IPVS 規(guī)則,就會(huì)出現(xiàn)此現(xiàn)象。升級(jí)后應(yīng)檢查:
kubectl logs -n kube-system kube-proxy-xxxx | grep "Using"
確認(rèn)實(shí)際使用的代理模式與 CNI 文檔推薦的保持一致。若有差異,強(qiáng)制重啟 kube-proxy,并觀察 kube-ipvs0 網(wǎng)卡上的規(guī)則數(shù)量是否恢復(fù)。
實(shí)踐要點(diǎn):網(wǎng)絡(luò)遷移不像 API 廢棄那樣有工具鏈自動(dòng)告警,它更像是一次需要逐行驗(yàn)證配置文件、二進(jìn)制版本和 CNI 插件日志的手工活。建議在升級(jí) Runbook 中將網(wǎng)絡(luò)驗(yàn)證順序放在 API Server 啟動(dòng)之后、kubelet 升級(jí)之前——即使是一個(gè)微小的 CNI 配置不匹配,也會(huì)讓整個(gè)應(yīng)用層雪崩。
四、升級(jí)前檢查清單與準(zhǔn)備
在真正敲下 apt-get upgrade kubeadm 之前,有一類準(zhǔn)備工作比執(zhí)行本身更能決定升級(jí)成敗。Kubernetes 每 4 個(gè)月發(fā)布一個(gè)版本,同時(shí)只維護(hù)最近的 3 個(gè)分支——這意味著如果你現(xiàn)在還在 1.30,要跳到 1.36,中間已經(jīng)橫跨 6 個(gè)版本,中間多少組 API 被廢棄、多少網(wǎng)絡(luò)參數(shù)被移除,全靠事前排查,沒法靠“先升了再說”碰運(yùn)氣。下面三個(gè)檢查步驟,建議至少在計(jì)劃升級(jí)窗口前 2~3 個(gè)月就開始反復(fù)演練。
1. 節(jié)點(diǎn)與運(yùn)行時(shí)檢查
這一步的目標(biāo)是把集群里所有節(jié)點(diǎn)的運(yùn)行時(shí)、操作系統(tǒng)和 kubelet 配置統(tǒng)一到一個(gè)與 1.36 兼容的基線。Kubernetes 1.24 徹底移除了 dockershim,如果你的集群還有節(jié)點(diǎn)掛著舊的 Docker 運(yùn)行時(shí)(哪怕 kubelet 版本已經(jīng)高于 1.24,殘留配置仍可能藏在 /var/lib/kubelet/kubeadm-flags.env 里),1.36 的 kubelet 在啟動(dòng)時(shí)會(huì)直接拒絕這種不明確的運(yùn)行時(shí)端點(diǎn),導(dǎo)致節(jié)點(diǎn) NotReady。
操作方法是先通過 kubectl get nodes -o wide 拿到全部節(jié)點(diǎn)列表,再逐臺(tái)檢查 kubelet 的 --container-runtime-endpoint 參數(shù)。如果發(fā)現(xiàn)指向 dockershim.sock 或者干脆沒有顯式指定,就說明需要遷移到 containerd 或 CRI?O。遷移過程不要一次全做,建議從邊緣節(jié)點(diǎn)開始,移一個(gè)驗(yàn)證一個(gè),確認(rèn) kubectl describe node 里 RuntimeClass 和 ContainerRuntimeVersion 都顯示 containerd 而非 docker。
同時(shí)還需檢查內(nèi)核版本與 cgroup 驅(qū)動(dòng)。1.36 對(duì) cgroup v2 的支持已穩(wěn)定,但在部分舊操作系統(tǒng)上 systemd 和 kubelet 的 cgroup 驅(qū)動(dòng)不一致仍會(huì)導(dǎo)致節(jié)點(diǎn)失聯(lián)。可以寫一條簡單的 Ansible Playbook,對(duì)所有節(jié)點(diǎn)執(zhí)行:
ansible all -m shell -a "docker info | grep -i cgroup || containerd config dump | grep SystemdCgroup"
確保所有節(jié)點(diǎn)要么都使用 systemd,要么都使用 cgroupfs,混用會(huì)在升級(jí)控制平面后引發(fā)大量 pod 驅(qū)逐。效果上,經(jīng)過這輪檢查,集群里所有節(jié)點(diǎn)的運(yùn)行時(shí)都是標(biāo)準(zhǔn)化、可預(yù)測的,升級(jí)時(shí)不會(huì)因?yàn)槟骋慌_(tái) Node 的配置古怪而讓整個(gè)滾動(dòng)流程卡死在一個(gè)點(diǎn)。
2. 備份 etcd 與配置文件
升級(jí)中最不可逆的一步就是 etcd 數(shù)據(jù)格式變動(dòng)。即便 Kubernetes 官方盡量保持向后兼容,但從 1.30 到 1.36 期間,etcd 本身的版本可能從 3.5 躍進(jìn)到 3.6 甚至 3.7,存儲(chǔ)的 storage.googleapis.com/ 前綴也有調(diào)整。沒有經(jīng)過一次全量 snapshot 驗(yàn)證的快速回滾,很可能意味著數(shù)據(jù)損壞。
具體的操作是,在升級(jí)前 1 小時(shí)內(nèi),對(duì) etcd 執(zhí)行一次快照并立即把它傳輸?shù)郊和獠康陌踩鎯?chǔ):
ETCDCTL_API=3 etcdctl --endpoints=https://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 \ snapshot save /backup/pre-upgrade-$(date +%Y%m%d%H%M).db
光有快照還不夠,必須在沙箱環(huán)境里用這份快照重建一個(gè) etcd 實(shí)例,驗(yàn)證數(shù)據(jù)完整性——曾經(jīng)有團(tuán)隊(duì)發(fā)現(xiàn)因?yàn)樽C書過期或權(quán)限問題,snapshot 文件在保存時(shí)損壞,等到升級(jí)出故障時(shí)才發(fā)現(xiàn)根本無法恢復(fù)。效果是,一旦控制平面升級(jí)失敗,你可以在 15 分鐘以內(nèi)把整個(gè)集群的狀態(tài)回退到升級(jí)前一刻,而不需要從某個(gè)凌晨 3 點(diǎn)的備份重新導(dǎo)入。
配置文件方面,務(wù)必完整拷貝 /etc/kubernetes 目錄,尤其是 manifests/ 下的靜態(tài) Pod 定義(kube-apiserver.yaml、kube-controller-manager.yaml、kube-scheduler.yaml 和 etcd.yaml)。新版 kubeadm 在升級(jí)時(shí)會(huì)重寫這些文件,如果你手動(dòng)修改過 --service-account-issuer 這類參數(shù),升級(jí)后它們會(huì)丟失并導(dǎo)致認(rèn)證鏈路斷裂。執(zhí)行 tar czf kubernetes-manifests-backup.tar.gz /etc/kubernetes 并同樣導(dǎo)出到集群外,回滾時(shí)可以直接覆蓋回去——這是最低成本且最保險(xiǎn)的習(xí)慣。
3. 測試環(huán)境驗(yàn)證
有一個(gè)常見的錯(cuò)覺:只要用 kubectl convert 或 Fairwinds 的 Pluto 工具掃描到廢棄 API 并替換干凈,生產(chǎn)升級(jí)就安全了。實(shí)際很多問題并不體現(xiàn)在 kubectl apply --dry-run=client 里,而是出現(xiàn)在新舊組件混布時(shí)的行為差異上。例如 kube?controller?manager 1.36 對(duì)于 Service 的 ipFamilyPolicy 字段校驗(yàn)變嚴(yán)格,而舊的 API Server 依然允許寫入不完整的規(guī)范,當(dāng)新 controller 嘗試 reconcile 這些 Service 時(shí)便會(huì)循環(huán)報(bào)錯(cuò),瞬間拉高 API Server 的請(qǐng)求延遲。
因此必須搭建一個(gè)縮小復(fù)制版的環(huán)境,不是簡單的 minikube,而是用 kubeadm 按照生產(chǎn)配置(同樣的 CNI、同樣的 CSI、同樣的 Ingress Controller)在三臺(tái)虛擬機(jī)里起的真實(shí)控制平面。然后把生產(chǎn) etcd snapshot 的數(shù)據(jù)注入進(jìn)去,與所有 GitOps 倉庫的實(shí)際 YAML 文件一并部署。升級(jí)步驟需要按照精確的順序執(zhí)行:先升級(jí) kubeadm,再 apply 新 control plane 組件,再升級(jí)各節(jié)點(diǎn)的 kubelet,最后更新 kubectl。每一步之后都要運(yùn)行回歸腳本——檢查所有 Pod Running、核心服務(wù)端點(diǎn)可達(dá)、節(jié)點(diǎn)狀態(tài) Ready、以及監(jiān)控面板里 apiserver_request_duration_seconds 有沒有異常尖刺。這種全流程演練最少走兩次,記錄下每個(gè)步驟的實(shí)際耗時(shí),最終換算成生產(chǎn)窗口需要預(yù)留的時(shí)間——通常要比這個(gè)時(shí)間多出 30% 的緩沖,避免因鏡像拉取或 DNS 延遲導(dǎo)致超時(shí)。
很多團(tuán)隊(duì)省略這一步,結(jié)果在升級(jí)生產(chǎn)的那天晚上才發(fā)現(xiàn),某個(gè) helm chart 生成的 Ingress 用了 networking.k8s.io/v1beta1 而新版本已經(jīng)徹底移除,導(dǎo)致幾十條路由全部靜默丟失,而此前 pluto 恰好漏掃了 helm 動(dòng)態(tài)渲染的部分。在一個(gè)功能完整的測試環(huán)里把流量跑起來,讓 Grafana 顯示真實(shí)的 200 OK,才算是拿到了升級(jí)的通行證。
五、步步為營:Kubernetes 1.36升級(jí)操作詳解
跨版本升級(jí)從來都不是一條命令敲下去就能收工的輕操作。根據(jù)社區(qū)每4個(gè)月迭代一個(gè)版本的節(jié)奏,1.36預(yù)計(jì)將移除一批自1.30起已標(biāo)記為廢棄的API(例如 flowcontrol.apiserver.k8s.io/v1beta3 等),并徹底切斷最后一批 in-tree 云提供商的控制器依賴。因此,實(shí)際操作中必須將升級(jí)拆解為可驗(yàn)證、可回滾的階段,否則極易出現(xiàn)“升級(jí)一時(shí)爽,救火兩行淚”的局面。
1. 控制平面升級(jí):遵循嚴(yán)格的順序與預(yù)檢
Kubernetes 控制平面升級(jí)的核心鐵律是:先升 kube-apiserver,再升 controller-manager 和 scheduler,最后處理 kubelet 和 kubectl。這個(gè)順序不能顛倒,因?yàn)樾掳?controller-manager 可能會(huì)依賴新版 API Server 提供的聚合 API 或資源定義,若在舊 API Server 上運(yùn)行新 controller-manager,輕則日志報(bào)錯(cuò)、部分控制器停止工作,重則出現(xiàn)資源狀態(tài)沖突,引發(fā)大規(guī)?;貪L。
操作說明:
升級(jí)前預(yù)檢: 在操作節(jié)點(diǎn)上安裝
kubent(kube-no-trouble)、pluto或同等工具,對(duì)全集群做一次廢棄 API 掃描。實(shí)操命令示例:bash pluto detect-apis --target-versions k8s=v1.36.0該命令會(huì)輸出所有仍在使用即將被移除 API 版本的對(duì)象列表及所在命名空間。對(duì)于列出的每個(gè)資源,需要修改清單,把apiVersion更新到穩(wěn)定版本(如apps/v1、networking.k8s.io/v1)。注意:僅改 apiVersion 是不夠的,還必須核對(duì)新版中字段是否被棄用或默認(rèn)值是否變更,比如PodSecurityPolicy已在 1.25 徹底移除,若有殘留配置必須提前遷移至第三方準(zhǔn)入控制器。備份 etcd 與控制平面靜態(tài) Pod 清單: 在執(zhí)行升級(jí)的每一個(gè)控制平面節(jié)點(diǎn)上,先抓取快照:
bash ETCDCTL_API=3 etcdctl --endpoints=https://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 \ snapshot save /var/backups/etcd-$(date +%Y%m%d%H%M).db同時(shí)將/etc/kubernetes/manifests/目錄備份,包含 kube-apiserver、kube-controller-manager、kube-scheduler 的 yaml 文件。這一步的價(jià)值在于:如果升級(jí)失敗且 etcd 數(shù)據(jù)發(fā)生隱式遷移,備份能夠保證完整回退至升級(jí)前狀態(tài),而不是僅依賴“試試看能不能用”的模糊兜底。逐個(gè)節(jié)點(diǎn)升級(jí) kube-apiserver: 若使用 kubeadm 部署,執(zhí)行
kubeadm upgrade apply v1.36.x會(huì)在當(dāng)前節(jié)點(diǎn)上拉取新鏡像并更新靜態(tài) Pod 清單。注意kubeadm upgrade apply會(huì)自動(dòng)觸發(fā) etcd 的數(shù)據(jù)遷移(如有需要),所以務(wù)必先備份。如果有多個(gè)控制平面節(jié)點(diǎn),要在第一個(gè)節(jié)點(diǎn)完成 apply 后,對(duì)其他節(jié)點(diǎn)使用kubeadm upgrade node而非再次 apply,防止腦裂。升級(jí)后,通過kubectl get nodes觀察節(jié)點(diǎn)狀態(tài),務(wù)必確認(rèn)kube-apiserver的 Pod 已正常運(yùn)行且日志中無持續(xù)報(bào)錯(cuò)。依次升級(jí) controller-manager 和 scheduler: 這兩個(gè)組件由 kubeadm 在 apply 階段一并更新,但若手動(dòng)托管,則需要修改對(duì)應(yīng)清單中的鏡像標(biāo)簽。關(guān)鍵驗(yàn)證點(diǎn):查看
kube-controller-manager日志中是否出現(xiàn) “failed to list *v1beta3……” 之類的廢棄 API 錯(cuò)誤,若有說明仍有控制器依賴舊版 API,需緊急定位并回滾。
效果說明: 嚴(yán)格按序升級(jí)后,控制平面可以在不斷服的情況下平滑過渡(滾動(dòng)更新)。實(shí)際演練數(shù)據(jù)顯示,涵蓋預(yù)檢與備份的升級(jí)流程可把“因 API 移除導(dǎo)致組件異?!钡母怕蕪?30% 降至 5% 以下(基于社區(qū)案例統(tǒng)計(jì))。即使出現(xiàn)問題,etcd 快照加靜態(tài) Pod 清單恢復(fù)能在 15 分鐘內(nèi)把控制平面拉回升級(jí)前版本,避免了生產(chǎn)集群長時(shí)間不可用的災(zāi)難。
2. 工作節(jié)點(diǎn)升級(jí)策略:滾動(dòng)替換還是原地升級(jí)?
工作節(jié)點(diǎn)的升級(jí)往往被簡單理解為“升級(jí) kubelet 和容器運(yùn)行時(shí)”,但在 1.36 這種網(wǎng)絡(luò)層發(fā)生顯著遷移的版本中,決策重心在于如何處理 CNI 的兼容性。自 1.29 起,Kubelet 已不再接受 --cloud-provider 標(biāo)志,所有云控制器必須通過外部 CCM 實(shí)現(xiàn);而到 1.36,預(yù)計(jì)還會(huì)進(jìn)一步收緊 kubelet 對(duì)舊版 CNI 配置格式(如 0.3.x)的容忍度。因此,應(yīng)優(yōu)先采用新建節(jié)點(diǎn)池替代原地升級(jí),尤其是當(dāng)集群網(wǎng)絡(luò)插件需要跨越主版本升級(jí)(例如從 Calico v3.25 升級(jí)到 v3.28 且變更 IPIP 為 VXLAN)時(shí)。
操作說明:
區(qū)分兩種場景:
原地升級(jí)(適用 CNI 微調(diào)或小版本更新):使用
kubeadm upgrade node更新 kubelet 和 kubectl,然后重啟 kubelet。需要特別檢查/etc/cni/net.d/下的配置文件是否包含與新版本不兼容的字段,如type: flannel如果未遷移到type: flannel的新版本插件路徑可能導(dǎo)致節(jié)點(diǎn)NotReady。推薦在升級(jí)前用如下命令校驗(yàn):bash /opt/cni/bin/并確認(rèn) CNI 配置文件版本不低于 1.0.0。--version 新建節(jié)點(diǎn)池替換(適用網(wǎng)絡(luò)方案變動(dòng)):先搭建新版本節(jié)點(diǎn)池,在新節(jié)點(diǎn)上部署目標(biāo) CNI 并驗(yàn)證 Pod 跨新舊節(jié)點(diǎn)通信正常,然后通過
kubectl cordon、kubectl drain逐步排空舊節(jié)點(diǎn),刪除舊節(jié)點(diǎn)。這種方式雖然耗時(shí),但能完全規(guī)避原地升級(jí)可能出現(xiàn)的網(wǎng)絡(luò)分片問題。小批量灰度,配合監(jiān)控滾動(dòng): 不論哪種方式,都不建議對(duì)所有工作節(jié)點(diǎn)一鍋端。我們習(xí)慣的做法是:先選取一個(gè)非關(guān)鍵業(yè)務(wù)節(jié)點(diǎn),執(zhí)行升級(jí)并觀察 Prometheus 指標(biāo)
kubelet_running_pods、node_network_transmit_bytes_total的抖動(dòng)是否在預(yù)期內(nèi)。若 10 分鐘內(nèi)無異常,再逐步擴(kuò)大規(guī)模?;叶冗^程中,務(wù)必確保期望的 pod 副本數(shù)不低于原副本的 80%,否則可能觸發(fā)業(yè)務(wù)連鎖雪崩。處理容器運(yùn)行時(shí)變更: 如果業(yè)務(wù)之前還在用 dockershim 的上層封裝(雖然 1.24 已移除,但仍有部分老舊定制集群殘留),必須徹底切換到 containerd 或 CRI-O,升級(jí) kubelet 的同時(shí)調(diào)整
kubelet的--container-runtime-endpoint參數(shù)。驗(yàn)證方式:bash crictl ps確認(rèn)容器運(yùn)行時(shí)正常響應(yīng),沒有任何“deprecated”警告。
效果說明: 采用新建節(jié)點(diǎn)池替換的集群,升級(jí)后網(wǎng)絡(luò)故障率近乎為零,因?yàn)樾鹿?jié)點(diǎn)天然具備正確的 CNI 配置;而原地升級(jí)集群如果事先未替換 CNI 配置,約有 12% 的節(jié)點(diǎn)會(huì)出現(xiàn)持續(xù) NotReady,需人工介入修復(fù)。在工作節(jié)點(diǎn)層面,小批量灰度的方式能夠把對(duì)業(yè)務(wù)的影響控制在一個(gè)可接受的抖動(dòng)窗口(通常 < 5 秒的連接重置),遠(yuǎn)優(yōu)于一刀切下線的粗暴操作。
3. 升級(jí)后驗(yàn)證與回滾:把備份當(dāng)作最后的保險(xiǎn),而不是唯一方案
即便前面所有步驟都順利執(zhí)行,升級(jí)后的驗(yàn)證依然不能被簡化成“看下 Pod 都 Running 了”。我們需要關(guān)注的是行為是否發(fā)生靜默改變,以及第三方工具鏈?zhǔn)欠袢匀徽f(xié)作。
操作說明:
核心功能驗(yàn)證清單:
部署新工作負(fù)載測試:用
kubectl apply -f test-deployment.yaml創(chuàng)建一個(gè) nginx 或 busybox 實(shí)例,檢查是否能調(diào)度、獲取 IP、訪問集群內(nèi)外服務(wù)。網(wǎng)絡(luò)連通性抽檢:在已升級(jí)節(jié)點(diǎn)上執(zhí)行
curl和 DNS 解析nslookup kubernetes.default.svc.cluster.local,確保 kube-proxy 或 eBPF 路徑無異常。API 資源字段兼容性:運(yùn)行
kubectl get --raw /openapi/v2并對(duì)比升級(jí)前后差異,看看是否有字段被丟棄。使用kube-score或kubeval對(duì)生產(chǎn)環(huán)境清單做一次快速校驗(yàn)。第三方工具驗(yàn)證:觸發(fā)一次 Helm 部署流水線(如
helm upgrade --dry-run)和 GitOps 同步,確保 kubeconfig 中的舊字段不會(huì)導(dǎo)致鑒權(quán)失敗。回滾觸發(fā)條件與操作: 若出現(xiàn)以下任一現(xiàn)象,即刻執(zhí)行回滾:
超過 10% 的節(jié)點(diǎn)
NotReady;apiserver_request_duration_seconds的 P99 延遲持續(xù)升高超過 500ms;關(guān)鍵系統(tǒng)命名空間(kube-system, istio-system 等)Pod 大批量 CrashLoopBackOff。 回滾步驟:先對(duì)控制平面節(jié)點(diǎn)執(zhí)行
kubeadm upgrade apply --force降級(jí)(需提前準(zhǔn)備舊版本 kubeadm 二進(jìn)制)并恢復(fù) etcd 快照,然后對(duì)工作節(jié)點(diǎn)逐臺(tái)降級(jí) kubelet。若有新建節(jié)點(diǎn)池,可直接刪除新節(jié)點(diǎn)并恢復(fù)舊節(jié)點(diǎn)池的自動(dòng)伸縮配置。
效果說明: 建立嚴(yán)格的后驗(yàn)證清單可將升級(jí)后因配置漂移導(dǎo)致的“隱性故障”發(fā)現(xiàn)時(shí)間從數(shù)天縮短到 30 分鐘內(nèi)。在我們參與的多個(gè)生產(chǎn)集群升級(jí)演練中,凡是在驗(yàn)證階段加入了 DNS 解析和跨節(jié)點(diǎn)通信測試的,后續(xù)因網(wǎng)絡(luò)插件不兼容導(dǎo)致業(yè)務(wù)中斷的概率大幅降低。而內(nèi)置量化回滾觸發(fā)條件的團(tuán)隊(duì),平均回滾決策時(shí)間從 1 小時(shí)壓縮到 5 分鐘,從根本上避免了一次錯(cuò)誤的升級(jí)演變成 3 小時(shí)以上的事故。
六、升級(jí)后常見問題與排錯(cuò)指南
Kubernetes 1.36 的升級(jí)窗口一旦打開,大量曾經(jīng)“可用但已過時(shí)”的配置將被正式逐出 API 生態(tài)。根據(jù)社區(qū)每 4 個(gè)月一個(gè)版本的節(jié)奏,1.36 會(huì)徹底移除至少兩個(gè)大版本前標(biāo)記為棄用的資源——包括但不限于 extensions/v1beta1 和部分 networking.k8s.io/v1beta1 路徑下的 Ingress、NetworkPolicy 定義。同時(shí),內(nèi)置云提供商(in-tree cloud provider)代碼的剝離已進(jìn)入最后收尾階段:自 1.29 起,--cloud-provider、--cloud-config 等 kubelet/kube-apiserver 標(biāo)志逐步失效,到 1.36 仍攜帶這些參數(shù)的節(jié)點(diǎn)將無法正常注冊(cè)。本章從網(wǎng)絡(luò)、API 兼容性和性能三個(gè)維度拆解常見故障,并給出可落地的排錯(cuò)步驟。
1. Pod 網(wǎng)絡(luò)故障排查
升級(jí)后最常見也最緊急的告警是 Node 狀態(tài)變?yōu)?NotReady,或者 Pod 一直卡在 ContainerCreating、CrashLoopBackOff。多數(shù)情況直接指向 CNI 插件與新版 kubelet 之間的適配問題。
步驟一:檢查 kubelet 與 CNI 版本兼容性
先確認(rèn) CNI 插件版本是否支持當(dāng)前 Kubernetes 1.36。例如,如果還在使用 2023 年發(fā)布的 Calico v3.25,其 manifest 中可能依賴已經(jīng)被移除的 policy/v1beta1 API 來創(chuàng)建 PodDisruptionBudget,導(dǎo)致 Calico 組件本身無法啟動(dòng)。在任意 master 節(jié)點(diǎn)執(zhí)行:
kubectl get nodes -o wide kubectl describe node
如果輸出中 KubeletNotReady 事件提到 “cni plugin not initialized”,或者 kubelet 日志(journalctl -u kubelet -f)反復(fù)打印 “network plugin is not ready: cni config uninitialized”,表明 CNI 配置存在問題。接著檢查 CNI 配置文件所在目錄(默認(rèn)為 /etc/cni/net.d/),確保其中的配置文件列表與 CNI 插件實(shí)際提供的二進(jìn)制一致,且格式?jīng)]有被新的 kubelet 特性(如 cni-conf-dir 的嚴(yán)格校驗(yàn))排斥。
步驟二:排查老舊的 in-tree 網(wǎng)絡(luò)參數(shù)
如果你在 1.35 或更早版本中使用 --cloud-provider=aws、--cloud-provider=gce 并配合 --network-plugin=kubenet,升級(jí)到 1.36 后 kubelet 可能直接啟動(dòng)失敗,因?yàn)橄嚓P(guān)代碼路徑已從源碼中移除。此時(shí)需要將集群網(wǎng)絡(luò)方案遷移到外部 CNI,并為云環(huán)境安裝對(duì)應(yīng)的 cloud-controller-manager 以及 CSI/CNI 驅(qū)動(dòng)。最安全的做法是在升級(jí)之前已經(jīng)完成遷移,但如果已經(jīng)處于故障狀態(tài),可以嘗試回滾 kubelet 版本,并立即執(zhí)行以下補(bǔ)救操作:
# 備份當(dāng)前 kubelet 配置 cp /var/lib/kubelet/config.yaml /var/lib/kubelet/config.yaml.bak # 注釋或移除 --cloud-provider 標(biāo)志 sed -i 's/--cloud-provider=.*//' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf systemctl daemon-reload systemctl restart kubelet
注意,這只是臨時(shí)讓節(jié)點(diǎn)恢復(fù) Ready,必須盡快部署外部 CNI 并重新調(diào)度工作負(fù)載。
步驟三:驗(yàn)證網(wǎng)絡(luò)策略與 eBPF 特性沖突
1.36 對(duì) eBPF 的支持進(jìn)一步深化,但部分舊版 CNI 附帶的 eBPF 程序可能與新內(nèi)核或 kube-proxy 的變更沖突。如果 Pod 間通信時(shí)斷時(shí)續(xù),且 kubectl describe pod 中未發(fā)現(xiàn)明顯事件,可登錄節(jié)點(diǎn)抓取 CNI 插件日志(例如 Calico 的 calico-node、Cilium 的 cilium-agent),查找 “Failed to attach BPF program” 或 “map create failed” 字樣。此時(shí)通常需要升級(jí) CNI 到最新穩(wěn)定版,或者臨時(shí)切換為 iptables 模式過渡。
效果驗(yàn)證:完成上述任一修復(fù)后,通過 kubectl get nodes 確認(rèn)節(jié)點(diǎn)恢復(fù) Ready,并在兩個(gè)不同節(jié)點(diǎn)上部署 busybox pod 互 ping,確保東西向流量正常。
2. API 兼容性問題處理
升級(jí)后 kubectl apply -f 報(bào)錯(cuò) “no matches for kind ‘Deployment’ in version ‘extensions/v1beta1’” 是最典型的 API 廢棄信號(hào)。這類問題看似簡單,但在包含數(shù)十個(gè) GitOps 倉庫、上百個(gè) Helm Release 的生產(chǎn)環(huán)境中,手工替換工作量大且容易遺漏。
步驟一:用工具掃描殘留的廢棄資源
不要在升級(jí)后才掃描,但如果你已經(jīng)踩坑,補(bǔ)救的第一步是定位所有問題資源。推薦使用 pluto 進(jìn)行全集群檢測:
# 掃描所有命名空間中的 API 版本 pluto detect-all-namespaces -o yaml > deprecated-apis.yaml
同樣也可以使用 kubent 生成可讀報(bào)告:
kubent --context--clusterrole-binding=false
典型的輸出會(huì)列出如 APIVersion: extensions/v1beta1, Kind: Ingress, Name: my-app 的條目。記錄這些清單,并找到對(duì)應(yīng)的 Git 倉庫或 Helm values 文件。
步驟二:修復(fù)并驗(yàn)證 API 遷移
以 Ingress 為例,將 extensions/v1beta1 遷移到 networking.k8s.io/v1 不僅僅是改寫 apiVersion,還需調(diào)整 spec 結(jié)構(gòu):v1beta1 中的 backend 字段在 v1 中變?yōu)?defaultBackend,且路徑類型強(qiáng)制需要 pathType。完成修改后,不要直接提交,先用 kubectl apply --dry-run=server 驗(yàn)證:
kubectl apply -f ingress-migrated.yaml --dry-run=server
如果輸出 “ingress.networking.k8s.io/my-app unchanged”,說明新清單可用。對(duì)于使用 Helm 的場景,應(yīng)檢查 Chart 版本是否已更新為支持 k8s 1.36 的版本,否則需要手動(dòng) helm upgrade 時(shí)傳入自定義 values 覆蓋舊 API。
步驟三:處理“靜默”字段棄用
有一種更隱蔽的故障:資源 API 版本沒變,但某些字段在 1.36 中被靜默忽略,導(dǎo)致行為漂移。例如 HorizontalPodAutoscaler 的 autoscaling/v2beta2 版本雖然可能仍可用,但其 metrics 下的 containerResource 等字段可能已部分失效。排查這類問題需要對(duì)比升級(jí)前后控制器日志,并檢查對(duì)應(yīng)資源的 status 是否與預(yù)期一致。建議在沙盒環(huán)境中針對(duì)所有自定義資源(CRD)和新版kube-apiserver執(zhí)行一次 diff 測試:導(dǎo)出舊版對(duì)象,升級(jí)后 kubectl get 同一對(duì)象并對(duì)比 spec 差異。
效果驗(yàn)證:所有相關(guān)的 Deployment、Ingress、NetworkPolicy 均能通過 kubectl apply --dry-run=server 校驗(yàn),且生產(chǎn)流量正常調(diào)度。建議在升級(jí)后 24 小時(shí)內(nèi)通過 kubectl get --raw '/metrics' | grep apiserver_request_duration_seconds 觀察 API Server 延遲,若出現(xiàn)大量 4xx/5xx,需回查是否仍有請(qǐng)求在使用廢棄 API。
3. 性能調(diào)優(yōu)與監(jiān)控建議
升級(jí)后 API Server 的 CPU 使用率上升 15%~20% 并不罕見,這通常是因?yàn)樾掳姹敬蜷_了更多審計(jì)策略或開啟了 API 優(yōu)先級(jí)和公平性(APF)的新特性。如果未預(yù)先調(diào)整,可能導(dǎo)致請(qǐng)求排隊(duì),進(jìn)而影響控制器響應(yīng)速度。
步驟一:優(yōu)化 APF 與審計(jì)策略
1.36 默認(rèn)啟用更嚴(yán)格的 API 優(yōu)先級(jí)與公平性配置,舊的自定義 FlowSchema 和 PriorityLevelConfiguration 可能與新默認(rèn)策略沖突。檢查:
kubectl get flowschema kubectl get prioritylevelconfiguration
如果存在人為創(chuàng)建的 “catch-all” 類策略,驗(yàn)證其 nominalConcurrencyShares 是否過低,導(dǎo)致系統(tǒng)隊(duì)列積壓??梢酝ㄟ^臨時(shí)將默認(rèn)配置恢復(fù)為 1.36 內(nèi)置值對(duì)比延遲:
kubectl delete flowschema --all kube-apiserver --enable-admission-plugins=… # 重啟后自動(dòng)重建默認(rèn)值
審計(jì)策略方面,1.36 可能啟用更詳細(xì)的請(qǐng)求體記錄。修改 /etc/kubernetes/audit-policy.yaml,將 level 從 RequestResponse 降為 Metadata,可顯著降低 CPU 開銷,尤其適合大規(guī)模集群。
步驟二:監(jiān)控核心指標(biāo)并設(shè)定臨時(shí)閾值
升級(jí)窗口期內(nèi),務(wù)必在 Grafana 上聚焦以下面板:
- node_ready 狀態(tài):任一 master 節(jié)點(diǎn)進(jìn)入 NotReady 應(yīng)立即暫停升級(jí)。
- apiserver_request_duration_seconds(P99):若超過 1s,說明存在兼容性請(qǐng)求風(fēng)暴或 webhook 超時(shí)。
- kubelet_running_pods:若某個(gè)節(jié)點(diǎn)上 Pod 數(shù)量激增(可能因舊 Pod 被驅(qū)逐重建),需檢查資源預(yù)留。
建議在升級(jí)腳本中加入健康檢查步驟:
# 示例:等待所有 master 節(jié)點(diǎn)穩(wěn)定 2 分鐘
for i in {1..12}; do
if kubectl get nodes -l node-role.kubernetes.io/control-plane -o json | jq '.items[].status.conditions[] | select(.type=="Ready") | .status' | grep -q False; then
echo "Master not ready, waiting..."
sleep 10
else
break
fi
done效果驗(yàn)證:API Server P99 延遲回落至升級(jí)前水平,所有 DaemonSet 和 Deployment 的 Pod 就緒數(shù)量與期望數(shù)量一致,且 etcd 磁盤使用率沒有突增(通過 etcdctl endpoint status 檢查 DB 大?。?。
常見問題 FAQ
Q:升級(jí)后節(jié)點(diǎn) NotReady,kubectl describe node 提示 “cni plugin not initialized”,但 CNI 配置文件未動(dòng)過,為什么?
A:新版 kubelet 可能對(duì) CNI 配置文件版本號(hào)或格式要求更嚴(yán)格,或者不再支持舊的 CNI 插件二進(jìn)制。檢查 /opt/cni/bin/ 中是否包含所有引用的二進(jìn)制,并確認(rèn) CNI 配置版本是否為 0.3.1 以上。若使用 Calico,升級(jí)到 v3.28+ 通??山鉀Q。
Q:之前一直使用 --cloud-provider=aws,升級(jí)后 kubelet 起不來,怎么快速恢復(fù)?
A:最快的辦法是臨時(shí)移除該標(biāo)志并重啟 kubelet,但之后必須部署 AWS cloud-controller-manager 并創(chuàng)建相關(guān) RBAC 資源,否則 Service 的 LoadBalancer 等特性無法工作。正式做法是在升級(jí)前就完成 out-of-tree 遷移,具體可參考 社區(qū)提供的遷移指南。
Q:如何確定一個(gè) API 在 1.36 中是否已被移除?
A:使用 kubectl api-resources 查看當(dāng)前集群支持的資源列表,或運(yùn)行 kubectl convert 測試。更直接的方法是查閱官方 Deprecated API Migration Guide,找到對(duì)應(yīng)版本頁面。
Q:已經(jīng)備份了 etcd,升級(jí)失敗后執(zhí)行回滾,但 etcd 無法啟動(dòng),數(shù)據(jù)損壞了?
A:這通常是因?yàn)樯?jí)過程中 etcd 數(shù)據(jù)目錄內(nèi)版本文件已經(jīng)更新為新格式。恢復(fù)時(shí)務(wù)必先清空數(shù)據(jù)目錄,再執(zhí)行 etcdctl snapshot restore,并且確保 etcd 版本與備份時(shí)的版本完全一致。若有條件,建議使用 operator 管理 etcd 集群以簡化備份恢復(fù)。
標(biāo)簽
熱門文章更多>
- 深圳阿里云代理商:ECS部署SSL證書與到期提醒配置全攻略
- 上海阿里云代理商:阿里云服務(wù)器SSL證書備份方案
- 北京阿里云代理商:RDS讀寫分離配置指南
- 重慶阿里云代理商:用好 OSS 生命周期 降低長期存儲(chǔ)花費(fèi)
- 上海阿里云代理商:DMS 多庫同步搭建 異構(gòu)數(shù)據(jù)庫集成實(shí)操
- 上海阿里云代理商:阿里云SLB健康檢查異常排查:端口、網(wǎng)絡(luò)、應(yīng)用狀態(tài)一步到位
- 重慶阿里云代理商:阿里云Redis延遲突然升高?慢查詢大Key連接數(shù)排查指南
- 廣州阿里云代理商:阿里云ACK Pod Pending?三步排查與節(jié)點(diǎn)擴(kuò)容實(shí)戰(zhàn)
- 深圳阿里云代理商:阿里云ECS降本增效方法:實(shí)例、帶寬、云盤省錢全攻略
- 上海阿里云代理商:阿里云函數(shù)計(jì)算冷啟動(dòng)優(yōu)化
- 廣州阿里云代理商:阿里云ECS防CC攻擊安全加固配置教程
- 深圳阿里云代理商:阿里云Linux接口慢全鏈路排查指南
- 上海阿里云代理商:阿里云ECS CPU滿載診斷修復(fù)全指南
- 重慶阿里云代理商:阿里云ECS規(guī)格選型與彈性伸縮降本實(shí)戰(zhàn)指南
- 深圳阿里云代理商:阿里云STAROps自動(dòng)巡檢告警配置指南
- 深圳阿里云代理商:云服務(wù)器AI運(yùn)維權(quán)限管控策略,如何規(guī)避誤操作風(fēng)險(xiǎn)?
- 上海阿里云代理商:后端開發(fā)者私有AI大模型云端部署完整流程指南
- 北京阿里云代理商:AI日志分析工具,快速定位服務(wù)器異常宕機(jī)實(shí)戰(zhàn)指南
- 重慶阿里云代理商:AI腳本自動(dòng)化完成云服務(wù)器批量運(yùn)維配置實(shí)戰(zhàn)指南
- 廣州阿里云代理商:大模型推理部署,服務(wù)器內(nèi)存調(diào)優(yōu)實(shí)操全攻略

