絡(luò)模型到故障排查)
1. 先弄清楚Kubernetes網(wǎng)絡(luò)模型的底層邏輯聊Pod間通信之前得先明白Kubernetes定的那條鐵律每個Pod都擁有獨(dú)立的IP地址Pod內(nèi)的所有容器共享這個IP。這個設(shè)計是整個Pod通信體系的基石沒有這個前提后面所有通信方式都無從談起。為什么這個設(shè)計如此重要因為Kubernetes假設(shè)所有Pod之間都能直接通信不需要NAT轉(zhuǎn)換不需要額外配置端口映射。這個扁平化網(wǎng)絡(luò)的設(shè)想把Pod當(dāng)成了一臺臺獨(dú)立的主機(jī)Pod的IP就像是主機(jī)IP一樣可以直接訪問。實(shí)踐中你會感受到這個模型讓網(wǎng)絡(luò)問題變得非常清晰——Pod連不上要么是本機(jī)網(wǎng)絡(luò)棧問題要么是跨節(jié)點(diǎn)網(wǎng)絡(luò)問題歸因路徑非常直接。這就像一棟大樓里的各個房間每個房間都有自己獨(dú)立的門牌號房間之間通過走廊就能互相串門不需要經(jīng)過前臺轉(zhuǎn)接。Kubernetes要做的就是保證這棟大樓里的走廊永遠(yuǎn)暢通不管房間分布在同一層還是不同樓層。理解了這層邏輯再去看各種Pod間通信方式就會豁然開朗Kubernetes解決的是走廊怎么修而通信方式本質(zhì)上就是在不同的網(wǎng)絡(luò)層次上使用這條走廊。2. 同一個Pod內(nèi)的容器通信最不起眼但最容易被忽視2.1 共享網(wǎng)絡(luò)命名空間localHost直接訪問同一個Pod內(nèi)的多個容器最核心的特征是共享同一個網(wǎng)絡(luò)命名空間。這意味著它們的網(wǎng)絡(luò)棧完全一樣——同一個IP地址、同一個端口空間、同一套路由規(guī)則。所以容器之間通信直接通過localhost訪問即可。實(shí)際項目中這個模式最典型的應(yīng)用就是Sidecar架構(gòu)。舉個真實(shí)的例子一個Web應(yīng)用容器監(jiān)聽8080端口旁邊掛一個日志采集容器日志采集容器直接通過localhost:8080去抓取Web應(yīng)用的訪問日志。這種模式的優(yōu)點(diǎn)在于網(wǎng)絡(luò)開銷幾乎為零走的是內(nèi)核回環(huán)接口性能損耗可以忽略不計。需要注意的坑是端口沖突。因為共享端口空間同一個Pod內(nèi)的不同容器監(jiān)聽同一個端口會直接報錯。我踩過這個坑一次項目中Web容器監(jiān)聽8080監(jiān)控容器想用8080跑一個健康檢查接口結(jié)果第二個容器怎么都起不來查了半天才發(fā)現(xiàn)是端口沖突。所以設(shè)計Pod內(nèi)多容器時一定要提前規(guī)劃好端口分配。2.2 進(jìn)程間通信的幾種手段除了網(wǎng)絡(luò)通信同一個Pod內(nèi)還支持進(jìn)程間通信方式包括共享內(nèi)存和信號量。因為容器共享同一個PID命名空間部分配置下進(jìn)程可以通過標(biāo)準(zhǔn)IPC機(jī)制交互。但在生產(chǎn)環(huán)境我見得最多的還是通過網(wǎng)絡(luò)端口通信進(jìn)程間通信在容器化場景下用得比較少主要原因是容器技術(shù)本來就是想做進(jìn)程隔離再去突破隔離反而違背了初衷。一個容易被忽略的細(xì)節(jié)是Pod內(nèi)容器之間的文件交換。容器共享Volume所以可以通過共享文件目錄來傳遞數(shù)據(jù)。這個方式在配置同步、證書輪換等場景下非常好用——生成證書的容器把證書寫到共享目錄主容器監(jiān)聽目錄變化后自動加載不需要任何網(wǎng)絡(luò)通信。3. Pod到Pod的直連通信同節(jié)點(diǎn)與跨節(jié)點(diǎn)3.1 同節(jié)點(diǎn)通信veth對和Linux Bridge的配合當(dāng)兩個Pod落在同一個節(jié)點(diǎn)上通信路徑相對簡單。每個Pod里有一個虛擬網(wǎng)卡veth這個虛擬網(wǎng)卡的一端在Pod的網(wǎng)絡(luò)命名空間里另一端掛在節(jié)點(diǎn)的Linux Bridge如cni0上。數(shù)據(jù)從Pod的eth0發(fā)出去實(shí)際上就是從一個veth口進(jìn)從另一個veth口出然后由Bridge轉(zhuǎn)發(fā)到目標(biāo)Pod的veth口。這個過程對性能的影響很小因為數(shù)據(jù)包只在節(jié)點(diǎn)內(nèi)部走了一遍二層交換不涉及封包解包。跑I/O密集型的分布式存儲應(yīng)用時把相關(guān)工作負(fù)載盡量調(diào)度到同一節(jié)點(diǎn)網(wǎng)絡(luò)延遲能明顯降下來。但同節(jié)點(diǎn)通信也有個隱藏問題ARP表項。每個Pod啟動時都要在Bridge上做ARP學(xué)習(xí)當(dāng)節(jié)點(diǎn)上Pod數(shù)量很多比如超過100個Bridge的MAC地址表可能會比較大極端情況下會影響轉(zhuǎn)發(fā)性能。大規(guī)模集群里顯示節(jié)點(diǎn)Pod密度規(guī)劃要有數(shù)別為省機(jī)器瘋狂壓榨單節(jié)點(diǎn)。3.2 跨節(jié)點(diǎn)通信Overlay網(wǎng)絡(luò)的封包與解包Pod分布在不同節(jié)點(diǎn)時問題就復(fù)雜了。節(jié)點(diǎn)A上的Pod IP是10.244.1.5節(jié)點(diǎn)B上的Pod IP是10.244.2.8這兩個IP在節(jié)點(diǎn)外是不可路由的。要讓它們通信必須通過Overlay網(wǎng)絡(luò)把Pod的IP包封裝在宿主機(jī)的網(wǎng)絡(luò)包里傳輸。以Flannel的VXLAN模式為例數(shù)據(jù)包的流轉(zhuǎn)過程是這樣的源Pod發(fā)出IP包通過節(jié)點(diǎn)A的cni0進(jìn)入FlannelFlannel將原始IP包封裝成UDP包VXLAN封裝外層IP是宿主機(jī)IP然后從節(jié)點(diǎn)的物理網(wǎng)卡發(fā)出去經(jīng)過Underlay網(wǎng)絡(luò)到達(dá)節(jié)點(diǎn)B節(jié)點(diǎn)B收到后解封裝還原原始IP包再通過本地的cni0送給目標(biāo)Pod。這套機(jī)制本質(zhì)上是硬生生多包了一層頭帶來的代價就是跨節(jié)點(diǎn)通信的延遲比同節(jié)點(diǎn)高。實(shí)測下來在常見的物理機(jī)上同節(jié)點(diǎn)Pod間通信延遲在0.05ms左右跨節(jié)點(diǎn)走VXLAN通常要到0.2~0.5ms網(wǎng)絡(luò)吞吐也有10%~20%的損耗。所以對延遲敏感的應(yīng)用比如實(shí)時推薦系統(tǒng)、交易系統(tǒng)最好讓Pod和它的依賴盡量落在同一節(jié)點(diǎn)。3.3 CNI插件怎么選Flannel、Calico還是Cilium跨節(jié)點(diǎn)通信這么重要底層的CNI插件選型就成了一件繞不開的事。當(dāng)前主流選項實(shí)際是Flannel、Calico和Cilium三家。Flannel最簡單部署快VXLAN模式和host-gw模式兩種選擇。如果節(jié)點(diǎn)在同一個二層網(wǎng)絡(luò)用host-gw模式可以繞開封裝開銷性能基本接近原生網(wǎng)絡(luò)。但host-gw模式下Pod網(wǎng)段要跟物理網(wǎng)絡(luò)規(guī)劃好避免路由沖突這點(diǎn)很多初學(xué)者會忽略。Calico功能最全它用的是BGP路由協(xié)議替代Overlay封裝Pod數(shù)據(jù)包直接走Underlay網(wǎng)絡(luò)路由性能更好。它還支持NetworkPolicy可以精細(xì)控制Pod間誰能訪問誰。代價是需要BGP環(huán)境的配合網(wǎng)絡(luò)拓?fù)鋸?fù)雜時配置會比較燒腦。Cilium是后起之秀基于eBPF技術(shù)性能和可觀測性都做得非常出色還內(nèi)置了L3/L4/L7層的網(wǎng)絡(luò)策略。但它對內(nèi)核版本有要求至少4.9以上推薦5.8老舊的節(jié)點(diǎn)系統(tǒng)跑不了。我的建議是小規(guī)模測試環(huán)境用Flannel省事生產(chǎn)環(huán)境沒有強(qiáng)合規(guī)要求選Calico有大規(guī)模微服務(wù)和高性能要求同時內(nèi)核版本滿足條件的Cilium值得一試。4. 通過Service通信讓Pod訪問不再依賴具體IP4.1 為什么需要Service直連通信雖然可行但有個致命問題Pod會重建、會漂移每次重建IP都會變。如果A服務(wù)要訪問B服務(wù)而B的Pod從10.244.1.5重建后變成了10.244.3.9A服務(wù)難道要跟著改配置Service就是為解決這個問題出現(xiàn)的。它為一組Pod通常用Label Selector圈定提供一個穩(wěn)定的虛擬IP也就是ClusterIP??蛻舳酥恍枰L問這個固定的ClusterIP剩下的事Service管了。這個模式跟生活中的總機(jī)臺很像你不用記住每個員工的直線電話只需要打總機(jī)總機(jī)會幫你轉(zhuǎn)接到具體的人。就算這個人換了工位總機(jī)照樣能幫他接到電話。4.2 ClusterIP背后的轉(zhuǎn)發(fā)機(jī)制ClusterIP本身是Kubernetes集群內(nèi)部的一個虛擬IP沒有對應(yīng)的物理網(wǎng)卡。流量到達(dá)ClusterIP后如何分發(fā)到后端的Pod這就要靠kube-proxy了。kube-proxy在節(jié)點(diǎn)上維護(hù)轉(zhuǎn)發(fā)規(guī)則主要有iptables模式和IPVS模式兩種實(shí)現(xiàn)。iptables模式邏輯簡單Kubernetes為每個Service創(chuàng)建一組iptables規(guī)則數(shù)據(jù)包進(jìn)入節(jié)點(diǎn)后根據(jù)規(guī)則隨機(jī)選擇一個后端Pod做DNAT。但iptables規(guī)則是鏈?zhǔn)狡ヅ涞漠?dāng)集群規(guī)模變大Service總數(shù)上千時規(guī)則匹配的耗時明顯增加還可能遇到規(guī)則更新不及時的問題。IPVS模式把規(guī)則從iptables遷移到了內(nèi)核的IPVS表里查找效率是哈希匹配性能遠(yuǎn)超iptables線性匹配。生產(chǎn)集群強(qiáng)烈建議把kube-proxy切到IPVS模式。怎么切直接在kube-proxy的啟動參數(shù)里加--proxy-modeipvs或者在部署時配置ConfigMap。切完之后可以看到IPVS的轉(zhuǎn)發(fā)表ipvsadm -Ln這個命令會列出所有Service對應(yīng)的后端Pod IP列表和權(quán)重信息排查負(fù)載均衡不均勻的時候很有用。4.3 Service類型怎么選Service一共有四種類型按需選擇即可。ClusterIP是默認(rèn)類型只能集群內(nèi)部訪問適合服務(wù)間調(diào)用。NodePort在每個節(jié)點(diǎn)上開一個端口外部流量可以通過任意節(jié)點(diǎn)的IP加端口訪問適合臨時調(diào)試或小規(guī)模對外服務(wù)。LoadBalancer依賴于云廠商的負(fù)載均衡器把請求轉(zhuǎn)發(fā)到NodePort適合云上生產(chǎn)環(huán)境。ExternalName不創(chuàng)建轉(zhuǎn)發(fā)規(guī)則只是DNS層面的CNAME別名適合把集群外的老服務(wù)包裝成內(nèi)部Service訪問。實(shí)際項目中Service間互相調(diào)用時還有個細(xì)節(jié)要留意跨Service調(diào)用時數(shù)據(jù)包源IP會被DNAT干擾。默認(rèn)情況下后端Pod看到的是NodeIP或kube-proxy所在節(jié)點(diǎn)的IP不是發(fā)起請求的Pod IP。如果業(yè)務(wù)需要拿到真實(shí)客戶端IP比如審計需求需要配置externalTrafficPolicy: Local代價是流量可能分布不均需要根據(jù)業(yè)務(wù)需求權(quán)衡。5. Headless Service把負(fù)載均衡拋到一邊的特殊通信方式有些場景不需要負(fù)載均衡反而需要直接拿到每個Pod的真實(shí)IP。最典型的就是有狀態(tài)應(yīng)用——比如Elasticsearch集群、Kafka、Cassandra這些。它們需要知道集群里每個Peer節(jié)點(diǎn)的真實(shí)地址來組成集群如果通過ClusterIP負(fù)載均衡過去節(jié)點(diǎn)間互相通信時根本不知道自己在跟哪個節(jié)點(diǎn)說話。Headless Service就是為此設(shè)計的。創(chuàng)建Service時把clusterIP指定為None這個Service就不分配ClusterIP了DNS會直接把后端Pod的IP列表返回給調(diào)用方。舉個例子創(chuàng)建一個headless服務(wù)apiVersion: v1 kind: Service metadata: name: es-cluster spec: clusterIP: None selector: app: elasticsearch ports: - port: 9300 targetPort: 9300之后通過DNS查詢es-cluster.default.svc.cluster.local會得到所有匹配Pod的IP列表。配合StatefulSetPod的DNS名格式固定為podname.servicename.namespace.svc.cluster.local也就是穩(wěn)定網(wǎng)絡(luò)標(biāo)識。比如es-0.es-cluster.default.svc.cluster.local即使Pod重建這個域名也保持不變因為StatefulSet保證Pod的名字和序號不變。利用這個機(jī)制一個Pod根本不需要知道其他Pod的IP只需要按照約定好的域名規(guī)則去拼接就可以了。這也是StatefulSet應(yīng)用的標(biāo)準(zhǔn)做法Elasticsearch的elasticsearch.yml里配置discovery.seed_hosts為主機(jī)列表就是通過headless service解析出來的。Kafka則利用這個機(jī)制維護(hù)節(jié)點(diǎn)間的broker列表。這里有個容易犯的錯headless service雖然能拿到Pod IP但這些IP列表是DNS返回的如果Pod數(shù)量很大DNS響應(yīng)包會非常大可能觸發(fā)UDP截斷問題。遇到這種情況建議開啟DNS的TCP查詢支持或者通過StatefulSet的方式直接用域名而不是IP列表減輕DNS壓力。6. 實(shí)操搭建一套Pod通信驗證環(huán)境前面講了很多理論這部分我通過一個完整的示例把所有通信方式串起來實(shí)際驗證一遍。6.1 準(zhǔn)備測試環(huán)境假設(shè)你已經(jīng)有一個Kubernetes集群Minikube或kind都能用先創(chuàng)建一個命名空間kubectl create ns net-test然后部署兩個Deployment分別跑一個簡單的HTTP服務(wù)和一個客戶端工具。為了方便調(diào)試直接用nginx和busybox的組合apiVersion: apps/v1 kind: Deployment metadata: name: web-server namespace: net-test spec: replicas: 2 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: debug-client namespace: net-test spec: replicas: 1 selector: matchLabels: app: client template: metadata: labels: app: client spec: containers: - name: busybox image: busybox:1.36 command: [sleep, 3600]部署完成后分別驗證幾種通信方式是否正常。6.2 逐一驗證不同通信方式先找到客戶端Pod的名字kubectl get pod -n net-test -l appclient拿到名字后進(jìn)入Pod內(nèi)部直接訪問nginx服務(wù)kubectl exec -it client-pod -n net-test -- wget -qO- http://web-server.default.svc.cluster.local這次請求走的是Service的ClusterIP轉(zhuǎn)發(fā)驗證了通過Service通信的鏈路正常。如果返回了nginx的默認(rèn)頁面說明ClusterIP、kube-proxy、后端Pod轉(zhuǎn)發(fā)整個鏈路都是通的。接著驗證直連Pod IP的通信方式。先查詢某個web Pod的IPkubectl get pod -n net-test -l appweb -o wide然后在客戶端Pod里用wget加--no-check-certificate直接訪問這個IPkubectl exec -it client-pod -n net-test -- wget -qO- http://pod-ip如果兩個Pod在同一節(jié)點(diǎn)走的是前面說的Bridge路徑如果在不同節(jié)點(diǎn)則走Overlay封裝。不管哪種都返回nginx默認(rèn)頁面就說明Pod直連通信正常。再驗證同一個Pod內(nèi)多容器的通信改一下web-server的Deployment加一個sidecar容器spec: containers: - name: nginx image: nginx:1.25 - name: sidecar image: busybox:1.36 command: [sleep, 3600]然后進(jìn)入sidecar容器訪問nginxkubectl exec -it web-pod -c sidecar -n net-test -- wget -qO- http://localhostlocalhost訪問成功說明同Pod內(nèi)容器共享網(wǎng)絡(luò)棧的機(jī)制正常。6.3 順手做一些網(wǎng)絡(luò)觀察通信驗證通了之后可以進(jìn)一步觀察網(wǎng)絡(luò)細(xì)節(jié)。在web Pod里看一眼路由表kubectl exec -it web-pod -n net-test -- ip route會看到類似這樣的輸出default via 10.244.0.1 dev eth0 10.244.0.0/24 dev eth0 scope link src 10.244.0.20這個default網(wǎng)關(guān)就是節(jié)點(diǎn)上的cni0網(wǎng)橋的IP。每個Pod的數(shù)據(jù)包只要是出Pod的都會先到這個網(wǎng)關(guān)由節(jié)點(diǎn)決定是橋接給同節(jié)點(diǎn)Pod還是封裝后發(fā)往其他節(jié)點(diǎn)。把這個路由表記住排查網(wǎng)絡(luò)異常的時候非常有用——如果Pod的默認(rèn)路由丟了這個Pod就徹底失聯(lián)了。7. 排查Pod間通信問題的實(shí)戰(zhàn)經(jīng)驗7.1 常見問題速查表Pod間通信的故障教科書上看病難但實(shí)際總結(jié)下來高發(fā)的其實(shí)只有幾類。我直接列一個速查表照著排查效率會高很多?,F(xiàn)象可能原因排查命令同一節(jié)點(diǎn)Pod互通跨節(jié)點(diǎn)Pod不通Overlay網(wǎng)絡(luò)問題比如VXLAN端口被封、Flannel路由表丟失檢查節(jié)點(diǎn)上ip route和ethtool隧道接口狀態(tài)同節(jié)點(diǎn)Pod也不通CNI網(wǎng)橋異常cni0接口或iptables規(guī)則被手動改動ip link show cni0查看接口是否存在iptables -t nat -L CNI-*查看規(guī)則Service訪問不通Pod直連正常kube-proxy規(guī)則異常或Service selector沒匹配到Podkubectl get endpoints service確認(rèn)Endpoints存在ipvsadm -Ln檢查轉(zhuǎn)發(fā)規(guī)則集群內(nèi)DNS解析不到Service名CoreDNS故障或Pod的DNS配置不正確kubectl get pod -n kube-system -l k8s-appkube-dnsnslookup service名.namespace.svc.cluster.local跨命名空間訪問不通沒寫完整域名或NetworkPolicy阻擋檢查yaml里Service名格式是否正確kubectl get networkpolicy -n namespace從節(jié)點(diǎn)訪問ClusterIP通但Pod內(nèi)不通節(jié)點(diǎn)iptables對轉(zhuǎn)發(fā)鏈設(shè)置了DROP或Pod的所屬節(jié)點(diǎn)被排除在外檢查每臺節(jié)點(diǎn)的iptables -L FORWARD的默認(rèn)策略這個表看著簡單是我排查了無數(shù)真實(shí)線上故障后沉淀下來的。每個問題背后基本都有對應(yīng)的坑下面挑兩個高頻的細(xì)說一下。7.2 高發(fā)問題一Service沒匹配到PodService建了Pod也跑了但訪問ClusterIP就是超時。別急著重啟kube-proxy先查一下這個命令kubectl get endpoints service-name -n namespace如果Endpoints列表是空的說明Service的selector和Pod的label對不上或者后端Pod還沒就緒。我遇到過最典型的場景Pod加了版本號label如appweb-v1但Service的selector還停留在舊label appweb結(jié)果半天查不出原因。這種就是純手誤label和selector一對就立刻現(xiàn)形。還有就緒探針的問題。Pod雖然Running但沒通過readinessProbe檢查不會進(jìn)Endpoints列表。這時候看到的現(xiàn)象是Pod明明是Running狀態(tài)但Service就是選不到它。7.3 高發(fā)問題二開通網(wǎng)絡(luò)策略后服務(wù)全斷大團(tuán)隊合作時有人引入NetworkPolicy做安全加固后網(wǎng)絡(luò)反而全斷了。這個問題的根源通常是對NetworkPolicy的默認(rèn)行為不夠理解沒有NetworkPolicy時默認(rèn)允許所有流量但只要有NetworkPolicy匹配到某個Pod就只有顯式允許的流量能進(jìn)來。要排查網(wǎng)絡(luò)策略問題我是先反推的從客戶端Pod去訪問目標(biāo)Pod看中間的路徑上有沒有哪道策略被攔了。首先看目標(biāo)Pod所在namespace有沒有NetworkPolicy限制了入站流量kubectl get networkpolicy -n namespace然后看具體的策略規(guī)則里allow的來源標(biāo)簽和端口能不能對上天比如只允許appfrontend的Pod訪問TCP 80端口但客戶端Pod的label寫錯了自然就撞墻了。這種時候把podSelector對準(zhǔn)或者臨時加一條允許規(guī)則放通測試流量等確認(rèn)了再做精細(xì)化收斂。繞來繞去排查Pod通信問題的最終奧義就一個字分段。把鏈路拆成Pod到節(jié)點(diǎn)網(wǎng)關(guān)、節(jié)點(diǎn)到節(jié)點(diǎn)、節(jié)點(diǎn)到目標(biāo)Pod、Service轉(zhuǎn)發(fā)這幾段每一段單獨(dú)驗證問題定位就快了。8. 選型建議和幾個踩坑教訓(xùn)說到選型網(wǎng)絡(luò)上默認(rèn)就是Flannel但生產(chǎn)環(huán)境我會優(yōu)先用Calico。核心原因是Calico在性能、NetworkPolicy支持和可觀測性上都有明顯優(yōu)勢。Flannel能做的Calico都能做而Calico的策略能力Flannel沒有。如果團(tuán)隊維護(hù)成本敏感Calico的部署也就多幾條配置而已不值得省這個事。Cilium適合有明確的可觀測性和能力擴(kuò)展需求團(tuán)隊eBPF的魔力邊用邊體會。但它對內(nèi)核版本的要求確實(shí)是個硬門檻老機(jī)器裝不上就別硬上別為趕時髦給自己埋坑。網(wǎng)絡(luò)插件選好之后還要做好網(wǎng)絡(luò)運(yùn)維的基本功。節(jié)點(diǎn)上常用的網(wǎng)絡(luò)排查命令比如ip、route、iptables、ipvsadm、tcpdump一定要熟練到肌肉記憶。我處理過的一次線上故障就是靠tcpdump定位的一個跨節(jié)點(diǎn)的PostgreSQL集群連接大量超時懷疑網(wǎng)絡(luò)問題在源節(jié)點(diǎn)和目標(biāo)節(jié)點(diǎn)同時抓包很快就發(fā)現(xiàn)VXLAN的UDP 8472端口被安全組規(guī)則過濾了。如果不會抓包對比分析這個故障排查可能要拖好幾個小時。另外建議大家給節(jié)點(diǎn)上的關(guān)鍵網(wǎng)絡(luò)組件做監(jiān)控告警重點(diǎn)盯cni0接口的狀態(tài)、Overlay隧道的收發(fā)丟包率、kube-proxy的規(guī)則同步延遲。這幾個指標(biāo)異常往往比業(yè)務(wù)側(cè)報警來得更早。最后說一個很多人都忽略的實(shí)踐升級或者變更網(wǎng)絡(luò)相關(guān)配置前先備份iptables和路由表。尤其是你手動調(diào)整過宿主機(jī)網(wǎng)絡(luò)策略的集群升級CNI插件時很容易出現(xiàn)規(guī)則互相覆蓋的情況。有一次我們升級Calico版本升級過程中節(jié)點(diǎn)上舊的BGP session沒有正常關(guān)閉新版本啟動后又建立了一個新的路由表瞬間多了很多重復(fù)路由導(dǎo)致部分Pod間通信時有時無。當(dāng)時就是因為有備份路由表快速回滾才止損。Pod間通信整體上不是多玄妙的機(jī)制核心就是網(wǎng)絡(luò)模型加幾種轉(zhuǎn)發(fā)鏈路。把原理吃透再把常用的驗證手段練熟Kubernetes網(wǎng)絡(luò)這塊基本就穩(wěn)了。