解決pod健康檢查問題

解決pod健康檢查問題

引自:Solving the mystery of pods health checks failures in Kubernetes。原文中的某些描述並不清晰,本文作了調整。

很早以前,環境中的pod有時候會遇到健康檢查失敗的問題,但並沒有什麼明顯表徵,且幾乎是立馬就會恢復。由於這種情況很少發生,且不會對業務造成影響,因此起初並沒有人關注該問題。

但後來發生的頻率越來越高,導致開發人員頻繁接收到deployment的健康告警。

第1步:查看日誌

  • Kubernetes worker的系統日誌 -- 無異常
  • kubelet 日誌 -- 無異常
  • Containerd 日誌 -- 無異常
  • CNI 日誌 -- 無異常
  • 檢查最近失敗的pod日誌 -- 無異常

通過檢查相關日誌,並沒有發現什麼異常

第2步:tcpdump

在抓取的流量中發現,當kubelet給pod發送TCP SYN之後,pod會回覆SYN-ACK,但kubelet並沒有發送TCP ACK。在一段時間的重試之後,Kubelet會建立起一條TCP會話,因此該問題是隨機發生的。

爲以防萬一,我們檢查了TCP中的seq和ack序列號,並沒有發現問題。

此時懷疑worker可能存在問題:是不是Kubelet沒有處理接收到的報文?

第3步:ss

每秒調用一次"ss -natp"來查看kubelet進程連接,此時發現失敗的連接卡在了SYN-SENT階段,說明kubelet並沒有接收到pod發來的SYN-ACK報文。

第4步:conntrack

使用conntrack查看TCP網絡連接跟蹤,發現有的連接卡在SYN-SENT狀態(kubelet側),有的連接卡在SYN-RECV(pod側),但連接的源端口號看起來都類似。

在我們的環境中,設定了一個較大的源端口可選範圍:

net.ipv4.ip_local_port_range=12000 65001

出現問題的源端口爲30XXX或31XXX,非常類似。

第5步:ipvs

通過ipvsadm命令查看ipvs配置發現,所有卡住的連接都使用了Kubernetes的nodeport 保留端口

根因分析

至此,問題已經明瞭。當Kubelet初始化一條TCP連接時,會隨機選擇一個源端口號,例如31055。當TCP SYN到達pod之後,pod會向31055端口號回覆一個TCP SYN-ACK報文。當該報文到達IPVS之後,由於已經存在一個端口號爲31055的nodeport(Kubernetes loadbalance service),此時會將TCP SYN-ACK報文轉發到對應的後端(其他pod),這樣就導致Kubelet無法接收到回覆的報文,無法建立連接。

解決辦法

解決方式也很簡單,設置如下內核參數即可,這樣Kubelet在建立連接時就不會選擇30000–32768的端口作爲TCP源端口:

net.ipv4.ip_local_reserved_ports="30000–32768"

Kubernetes的nodeport保留端口爲30000-32767,因此設置的net.ipv4.ip_local_reserved_ports爲30000–32768

TIPs

  • net.ipv4.ip_local_port_range的默認值爲32768 60999,正好和Kubernetes的nodeport保留端口錯開,本文中描述的問題的源頭也是因爲修改了該內核參數,因此非必要不要修改內核參數!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章