在剛剛過去的北美KubeCon 18中,有一位來自Redhat的老哥分享了k8s網絡的診斷的方法,阿裡雲容器服務在客戶問題中有挺多是網絡的問題,這個分享可以幫助在使用k8s網絡遇到問題時的診斷流程。
為啥k8s網絡那麼複雜
首先介紹了k8s網絡為啥這麼複雜,都有哪些考慮到的地方,這部分介紹的很多内容也是我們團隊在做網絡時遇到的一些坑。
k8s網絡方案設計需要考慮很多方面:

- 主控端間的網絡:是采用純硬體的網絡還是虛拟的網絡(例如openstack)的vxlan,關系到主控端的性能以及容器網絡可以選擇的方案,比如主控端是虛拟網絡的話容器網絡一般隻能采用overlay的方案。
- 容器間網絡:采用Overlay(封包成主控端的包)的網絡還是 Non-overlay的網絡以及各自的性能和限制,容器的IP位址管理,容器的網絡通路控制(Network Policy), 網絡帶寬管理(Qos/Traffic sharping)
- K8S本身的網絡結構适配:負載均衡(kube-proxy...), K8S的Network Policy, Ingress服務等等。
需要協調很多層次的網絡元件:
- 容器網絡的包會被各個層次去修改,在容器中會有istio等service mesh元件, 在主控端上也會有kube-proxy/kubelet會修改包的源/目的位址等等
- 需要考慮到底層網絡的一些限制,比如帶寬限制,比如arp劫持/防欺騙等等
k8s網絡配置過程以及診斷:
上面講了很多網絡的複雜度,下面講師以kubeadm為例介紹了網絡的配置過程,針對配置的過程以及每一步做的事情和完成的原因可以了解網絡初始化的過程,友善出現問題時排查:
大體上的k8s網絡從叢集初始化到ready是這樣的流程:
- 先是叢集建立出來,節點加入到叢集中,這個時候每個節點(kubelet)都通過主控端網絡連通到master節點的管控的元件(apiserver等)上。這個時候在叢集中能看到節點清單(kubectl get node),但是每個節點都是NotReady的狀态,這個時候非Host網絡的Pod都會在Pending狀态,因為沒有節點網絡是Ready的,如下圖Coredns就是Pending的,說明主控端的網絡已經聯通了,但是容器網絡還沒有好:
- 然後每個節點再配置CNI的plugin和配置,比如最常見的我們通過flannel的模闆部署flannel的插件,節點在監聽到插件和配置存在時會上報狀态,這個時候整個節點的網絡才ready,這時候k8s會将需要容器網絡的容器排程到ready的節點上,Pending狀态就會變成Creating狀态,然後由節點上的kubelet再調用CNI插件去配置容器的網絡,容器就能變成Running狀态,這個時候容器的網絡也就Ready了:
容器網絡配置這一步會有哪些問題呢?
在CNI插件和配置檔案安裝到節點上後,節點就會變成ready了,就會有容器排程到節點上,但不一定容器能正确運作:
- CNI插件執行失敗了,容器一直在Creating,通過kubelet日志或者容器事件可以看到cni的報錯
- CNI插件執行沒問題,容器也能變成Running,但是容器網絡通信不行(容器間,容器和主控端(健康檢查等)
對于第一種情況:
我們能看到的現象是這樣的:容器一直在Creating,通過kubelet日志或者容器事件可以看到cni的報錯
對于第二種情況:
通常可以通過健康檢查日志或者容器本身的網絡請求的日志看到容器網絡是不連通的:
如何排查這些問題:
對于容器網絡不通的情況,我們要如何排查呢,這裡講師介紹了一些簡單的容器虛拟化網絡和排查的知識,可以從中入手:
如何區分容器的網卡
ip -d -d link show dev {網卡名} 這個指令可以看到網卡的類型以及詳細的一些資訊,比如
cni0是一個bridge裝置,可以比作實體網絡中的交換機
這個截圖是在容器内部執行的,容器的eth0網卡,是一個veth類型的裝置,veth是用來聯通不同的namespace的,通常用來聯通容器和主控端的網橋,後面的if33代表它聯通的另外一端的網卡的編号,到主控端的namespace中執行ip -d link show我們就能看到這個網卡編号對應的網卡
如果有的容器沒有ip 指令,那我們要怎麼進到容器中排查呢?可以通過nsenter的指令進入到容器的網絡命名空間操作,例如:
其中的pid就是容器程序的ID,PID可以通過ps -ef | grep <容器程序>,也可以通過kubectl get pod -o yaml | grep containerID , 然後docker inspect 來找到對應的pid。
排查Iptables:
很多時候遇到網絡配置成功,但是容器網絡不通的問題都是iptables在從中作梗,比如增加了什麼防火牆規則,Chain的Policy被改掉啦之類的。
iptables工作的地方:
容器程序通路網絡時,會首先經過容器内部的iptables,然後到主控端上面,在主控端上面會通過主控端的iptables和routing最終決定包的取舍和去向。
那麼誰會添加iptables規則呢?
答案是誰都會。。。
iptables添加為了幾個功能: 負載均衡(在PREROUTING中去做DNAT+RAMDOM), 通路控制(在FORWARD/INPUT/OUTPUT)中去做限制, 源位址裝換(POSTROUTING中轉換成主控端的IP位址)等等
最後介紹抓包大法:
上面的介紹可見網絡的過程和複雜度,但是通常排查時沒辦法一條一條規則的順着去排查,何況規則還是由那麼多元件操控随時會變化,這時候可以使用抓包工具排查在哪一層包被丢掉了來一一排除的解決問題:
我們可以在不同層次的網卡上抓包來看到底包丢在什麼地方,或者被改成了啥熊樣。
在容器服務這邊,通常情況下,我們采用tcpdump的方式通過容器IP等過濾條件抓包排查,如果需要詳細的包的解析,可以tcpdump -w寫到檔案中,然後通過wireshark去解析,這裡講師展示了另外一個工具:
kokotap
可以建立一個拷貝的接口,将容器的流量也導入到這個接口上友善wireshark直接在主控端上也能抓到容器的包。
總結
整個分享就是這些,這個分享中前面介紹了很多k8s網絡的複雜度,這塊介紹的比較全面,我們在做網絡插件時在那些點上也都會遇到一些坑,在後面的介紹中主要是網絡排查的入門以及工具,通過這些工具可以上手排查問題了,但排查到現象後具體的原因沒有詳細介紹,可能因為遇到的問題場景就太多了,大家可以在排查的過程中多多增加經驗。
容器服務在k8s網絡上有深入的實踐,另外有開源的網絡插件Terway,覆寫了k8s網絡的方方面面,項目連結
https://github.com/AliyunContainerService/terway