一次“不負責任”的 K8s 網路故障排查經驗分享

爾達Erda發表於2021-06-23

作者 | 駱冰利

來源 | Erda 公眾號


某天晚上,客戶碰到了這樣的問題:K8s 叢集一直擴容失敗,所有節點都無法正常加入叢集。在經過多番折騰無解後,客戶將問題反饋到我們這裡,希望得到技術支援。該問題的整個排查過程比較有意思,本文對其中的排查思路及所用的方法進行了歸納整理並分享給大家,希望能夠對大家在排查此類問題時有些幫助和參考。


問題現象

運維同學在對客戶的 K8s 叢集進行節點擴容時,發現新增的節點一直新增失敗。初步排查結果如下:

- 在新增節點上,訪問 K8s master service vip 網路不通。

- 在新增節點上,直接訪問 K8s master hostIP + 6443 網路正常。

- 在新增節點上,訪問其他節點的容器 IP 可以正常 ping 通。

- 在新增節點上,訪問 coredns service vip 網路正常。


該客戶使用的 Kubernetes 版本是 1.13.10,宿主機的核心版本是 4.18(centos 8.2)。


問題排查過程

收到該一線同事的反饋,我們已經初步懷疑是 ipvs 的問題。根據以往網路問題排查的經驗,我們先對現場做了些常規排查:

- 確認核心模組 ip_tables 是否載入(正常)

- 確認 iptable forward 是否預設 accpet (正常)

- 確認宿主機網路是否正常(正常)

- 確認容器網路是否正常(正常)

- ...


排除了常規問題後,基本可以縮小範圍,下面我們再繼續基於 ipvs 相關層面進行排查。

1. 透過 ipvsadm 命令排查

> 10.96.0.1 是客戶叢集 K8s master service vip。

如上圖所示,我們可以發現存在異常連線,處於 SYN_RECV 的狀態,並且可以觀察到,啟動時 kubelet + kube-proxy 是有正常建連的,說明是在啟動之後,K8s service 網路出現了異常。

2. tcpdump 抓包分析

兩端進行抓包,並透過 telnet 10.96.0.1 443 命令進行確認。

結論:發現 SYN 包在本機沒有傳送出去。


3. 初步總結

透過上面的排查,我們可以再次縮小範圍:問題基本就在 kube-proxy 身上。我們採用了 ipvs 模式,也依賴了 iptables 配置實現一些網路的轉發、snat、drop 等。


根據上面的排查過程,我們又一次縮小了範圍,開始分析懷疑物件 kube-proxy。


4. 檢視 kube-proxy 日誌

如上圖所示:發現異常日誌,iptables-restore 命令執行異常。透過 Google、社群檢視,確認問題。

相關 issue 連結可參考:

- [](%3A//github.com/kubernetes/kubernetes/issues/73360)

- [](%3A//github.com/kubernetes/kubernetes/pull/84422/files)

- [](%3A//github.com/kubernetes/kubernetes/pull/82214/files)


5. 繼續深入

透過程式碼檢視(1.13.10 版本 pkg/proxy/ipvs/proxier.go:1427),可以發現該版本確實沒有判斷 KUBE-MARK-DROP 是否存在並建立的邏輯。當出現該鏈不存在時,會出現邏輯缺陷,導致 iptable 命令執行失敗。

K8s master service vip 不通,實際容器相關的 ip 是通的,這種情況出現的原因,與下面的 iptable 規則有關:

```

iptable -t nat -A KUBE-SERVICES ! -s 9.0.0.0/8 -m comment --comment "Kubernetes service cluster ip + port for masquerade purpose" -m set --match-set KUBE-CLUSTER-IP dst,dst -j KUBE-MARK-MASQ

```


6. 根因探究

前面我們已經知道了 kube-proxy 1.13.10 版本存在缺陷,在沒有建立 KUBE-MARK-DROP 鏈的情況下,執行 iptables-restore 命令配置規則。但是為什麼 K8s 1.13.10 版本跑在 centos8.2 4.18 核心的作業系統上會報錯,跑在 centos7.6 3.10 核心的作業系統上卻正常呢?


我們檢視下 kube-proxy 的原始碼,可以發現 kube-proxy 其實也就是執行 iptables 命令進行規則配置。那既然 kube-proxy 報錯 iptables-restore 命令失敗,我們就找一臺 4.18 核心的機器,進入 kube-proxy 容器看下情況。

到容器內執行下 iptables-save 命令,可以發現 kube-proxy 容器內確實沒有建立 KUBE-MARK-DROP 鏈(符合程式碼預期)。繼續在宿主機上執行下 iptables-save 命令,卻發現存在 KUBE-MARK-DROP 鏈。


這裡有兩個疑問:

- 為什麼 4.18 核心宿主機的 iptables 有 KUBE-MARK-DROP 鏈?

- 為什麼 4.18 核心宿主機的 iptables 規則和 kube-proxy 容器內的規則不一致?


第一個疑惑,憑感覺懷疑除了 kube-proxy,還會有別的程式在操作 iptables,繼續擼下 K8s 程式碼。

結論:發現確實除了 kube-proxy,還有 kubelet 也會修改 iptables 規則。具體程式碼可以檢視:pkg/kubelet/kubelet_network_linux.go

第二個疑惑,繼續憑感覺······Google 一發撈一下為何 kube-proxy 容器掛載了宿主機 /run/xtables.lock 檔案的情況下,宿主機和容器 iptables 檢視的規則不一致。

結論:CentOS 8 在網路方面摒棄 iptables,採用 nftables 框架作為預設的網路包過濾工具。


至此,所有的謎團都解開了。



團隊完成過大量的客戶專案交付,這裡有些問題可以再解答下:


- 問題一:為什麼這麼多客戶環境第一次碰到該情況?


因為需要 K8s 1.13.10 + centos 8.2 的作業系統,這個組合罕見,且問題必現。升級 K8s 1.16.0+ 就不出現該問題。



- 問題二:為什麼使用 K8s 1.13.10 + 5.5 核心卻沒有該問題?


因為與 centos 8 作業系統有關,我們手動升級 5.5 版本後,預設還是使用的 iptables 框架。


可以透過 iptables -v 命令,來確認是否使用 nftables。

> 題外話:nftables 是何方神聖?比 iptables 好麼?這是另一個值得進一步學習的點,這裡就不再深入了。


總結與感悟

針對以上的排查問題,我們總結下解決方法:


- 調整核心版本到 3.10(centos 7.6+),或者手動升級核心版本到 5.0 +;

- 升級 Kubernetes 版本,當前確認 1.16.10+ 版本沒有該問題。


以上是我們在進行 Kubernetes 網路故障排查中的一點經驗,希望能夠對大家高效排查,定位原因有所幫助。


如果對於 Erda 專案你有其它想要了解的內容,歡迎**新增小助手微信(Erda202106)**加入交流群!


歡迎參與開源

Erda 作為開源的一站式雲原生 PaaS 平臺,具備 DevOps、微服務觀測治理、多雲管理以及快資料治理等平臺級能力。 點選下方連結即可參與開源**,和眾多開發者一起探討、交流,共建開源社群。 歡迎大家關注、貢獻程式碼和 Star!


- Erda Github 地址:](

- Erda Cloud 官網:](


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70002215/viewspace-2777982/,如需轉載,請註明出處,否則將追究法律責任。

相關文章