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


在這里插入圖片描述

作者 | 駱冰利
來源 | 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 鏈接可參考:

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!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM