天天看點

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

作者:拾光映季

本文将引入一個思路:“在 Kubernetes 叢集發生網絡異常時如何排查”。文章将引入 Kubernetes 叢集中網絡排查的思路,包含網絡異常模型,常用工具,并且提出一些案例以供學習。

  • Pod 常見網絡異常分類
  • 網絡排查工具
  • Pod 網絡異常排查思路及流程模型
  • CNI 網絡異常排查步驟
  • 案例學習

Pod 網絡異常

網絡異常大概分為如下幾類:

  • 網絡不可達,主要現象為 ping 不通,其可能原因為:
    • 源端和目的端防火牆(iptables, selinux)限制
    • 網絡路由配置不正确
    • 源端和目的端的系統負載過高,網絡連接配接數滿,網卡隊列滿
    • 網絡鍊路故障
  • 端口不可達:主要現象為可以 ping 通,但 telnet 端口不通,其可能原因為:
    • 源端和目的端防火牆限制
    • 源端和目的端的系統負載過高,網絡連接配接數滿,網卡隊列滿,端口耗盡
    • 目的端應用未正常監聽導緻(應用未啟動,或監聽為 127.0.0.1 等)
  • DNS 解析異常:主要現象為基礎網絡可以連通,通路域名報錯無法解析,通路 IP 可以正常連通。其可能原因為
    • Pod 的 DNS 配置不正确
    • DNS 服務異常
    • pod 與 DNS 服務通訊異常
  • 大資料包丢包:主要現象為基礎網絡和端口均可以連通,小資料包收發無異常,大資料包丢包。可能原因為:
    • 可使用 ping -s 指定資料包大小進行測試
    • 資料包的大小超過了 docker、CNI 插件、或者主控端網卡的 MTU 值。
  • CNI 異常:主要現象為 Node 可以通,但 Pod 無法通路叢集位址,可能原因有:
    • kube-proxy 服務異常,沒有生成 iptables 政策或者 ipvs 規則導緻無法通路
    • CIDR 耗盡,無法為 Node 注入 PodCIDR 導緻 CNI 插件異常
    • 其他 CNI 插件問題

那麼整個 Pod 網絡異常分類可以如下圖所示:

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

Pod network trouble hirarchy

總結一下,Pod 最常見的網絡故障有,網絡不可達(ping 不通);端口不可達(telnet 不通);DNS 解析異常(域名不通)與大資料包丢失(大包不通)。

常用網絡排查工具

在了解到常見的網絡異常後,在排查時就需要使用到一些網絡工具才可以很有效的定位到網絡故障原因,下面會介紹一些網絡排查工具。

tcpdump

tcpdump 網絡嗅探器,将強大和簡單結合到一個單一的指令行界面中,能夠将網絡中的封包抓取,輸出到螢幕或者記錄到檔案中。

各系統下的安裝

Ubuntu/Debian: tcpdump ;apt-get install -y tcpdump

Centos/Fedora: tcpdump ;yum install -y tcpdump

Apline:tcpdump ;apk add tcpdump --no-cache

檢視指定接口上的所有通訊

文法

參數說明-i [interface]

-w [flle]第一個 n 表示将位址解析為數字格式而不是主機名,第二個 N 表示将端口解析為數字格式而不是服務名-n不顯示 IP 位址-Xhex and ASCII-AASCII(實際上是以人類可讀懂的包進行顯示)-XX

-v詳細資訊-r讀取檔案而不是實時抓包

關鍵字typehost(主機名,域名,IP 位址), net, port, portrangedirectionsrc, dst, src or dst , src and dsprotocolether, ip,arp, tcp, udp, wlan

捕獲所有網絡接口

tcpdump -D           

按 IP 查找流量

最常見的查詢之一 host,可以看到來往于 1.1.1.1 的流量。

tcpdump host 1.1.1.1           

按源 / 目的 位址過濾

如果隻想檢視來自 / 向某方向流量,可以使用 src 和 dst。

tcpdump src|dst 1.1.1.1           

通過網絡查找資料包

使用 net 選項,來要查找出 / 入某個網絡或子網的資料包。

tcpdump net 1.2.3.0/24           

使用十六進制輸出資料包内容

hex 可以以 16 進制輸出包的内容

tcpdump -c 1 -X icmp           

檢視特定端口的流量

使用 port 選項來查找特定的端口流量。

tcpdump port 3389
tcpdump src port 1025           

查找端口範圍的流量

tcpdump portrange 21-23           

過濾包的大小

如果需要查找特定大小的資料包,可以使用以下選項。你可以使用 less,greater。

tcpdump less 32
tcpdump greater 64
tcpdump <= 128           

捕獲流量輸出為檔案

-w 可以将資料包捕獲儲存到一個檔案中以便将來進行分析。這些檔案稱為 PCAP(PEE-cap)檔案,它們可以由不同的工具處理,包括 Wireshark 。

tcpdump port 80 -w capture_file           

組合條件

tcpdump 也可以結合邏輯運算符進行組合條件查詢

  • ANDand or &&
  • ORor or ||
  • EXCEPTnot or !
tcpdump -i eth0 -nn host 220.181.57.216 and 10.0.0.1  # 主機之間的通訊
tcpdump -i eth0 -nn host 220.181.57.216 or 10.0.0.1
# 擷取10.0.0.1與 10.0.0.9或 10.0.0.1 與10.0.0.3之間的通訊
tcpdump -i eth0 -nn host 10.0.0.1 and \(10.0.0.9 or 10.0.0.3\)           

原始輸出

并顯示人類可讀的内容進行輸出包(不包含内容)。

tcpdump -ttnnvvS -i eth0
tcpdump -ttnnvvS -i eth0           

IP 到端口

讓我們查找從某個 IP 到端口任何主機的某個端口所有流量。

tcpdump -nnvvS src 10.5.2.3 and dst port 3389           

去除特定流量

可以将指定的流量排除,如這顯示所有到 192.168.0.2 的 非 ICMP 的流量。

tcpdump dst 192.168.0.2 and src net and not icmp           

來自非指定端口的流量,如,顯示來自不是 SSH 流量的主機的所有流量。

tcpdump -vv src mars and not dst port 22           

選項分組

在建構複雜查詢時,必須使用單引号 '。單引号用于忽略特殊符号 () ,以便于使用其他表達式(如 host, port, net 等)進行分組。

tcpdump 'src 10.0.2.4 and (dst port 3389 or 22)'           

過濾 TCP 标記位

TCP RST

The filters below find these various packets because tcp[13] looks at offset 13 in the TCP header, the number represents the location within the byte, and the !=0 means that the flag in question is set to 1, i.e. it’s on.

tcpdump 'tcp[13] & 4!=0'
tcpdump 'tcp[tcpflags] == tcp-rst'           

TCP SYN

tcpdump 'tcp[13] & 2!=0'
tcpdump 'tcp[tcpflags] == tcp-syn'           

同時忽略 SYN 和 ACK 标志的資料包

tcpdump 'tcp[13]=18'           

TCP URG

tcpdump 'tcp[13] & 32!=0'
tcpdump 'tcp[tcpflags] == tcp-urg'           

TCP ACK

tcpdump 'tcp[13] & 16!=0'
tcpdump 'tcp[tcpflags] == tcp-ack'           

TCP PSH

tcpdump 'tcp[13] & 8!=0'
tcpdump 'tcp[tcpflags] == tcp-push'           

TCP FIN

tcpdump 'tcp[13] & 1!=0'
tcpdump 'tcp[tcpflags] == tcp-fin'           

查找 http 包

查找 user-agent 資訊

tcpdump -vvAls0 | grep 'User-Agent:'           

查找隻是 GET 請求的流量

tcpdump -vvAls0 | grep 'GET'           

查找 http 用戶端 IP

tcpdump -vvAls0 | grep 'Host:'           

查詢用戶端 cookie

tcpdump -vvAls0 | grep 'Set-Cookie|Host:|Cookie:'           

查找 DNS 流量

tcpdump -vvAs0 port 53           

查找對應流量的明文密碼

tcpdump port http or port ftp or port smtp or port imap or port pop3 or port telnet -lA | egrep -i -B5 'pass=|pwd=|log=|login=|user=|username=|pw=|passw=|passwd= |password=|pass:|user:|username:|password:|login:|pass |user '           

wireshark 追蹤流

wireshare 追蹤流可以很好的了解出在一次互動過程中都發生了那些問題。

wireshare 選中包,右鍵選擇 “追蹤流“ 如果該包是允許的協定是可以打開該選項的

關于抓包節點和抓包裝置

如何抓取有用的包,以及如何找到對應的接口,有以下建議

抓包節點:

通常情況下會在源端和目的端兩端同時抓包,觀察資料包是否從源端正常發出,目的端是否接收到資料包并給源端回包,以及源端是否正常接收到回包。如果有丢包現象,則沿網絡鍊路上各節點抓包排查。例如,A 節點經過 c 節點到 B 節點,先在 AB 兩端同時抓包,如果 B 節點未收到 A 節點的包,則在 c 節點同時抓包。

抓包裝置:

對于 Kubernetes 叢集中的 Pod,由于容器内不便于抓包,通常視情況在 Pod 資料包經過的 veth 裝置,docker0 網橋,CNI 插件裝置(如 cni0,flannel.1 etc..)及 Pod 所在節點的網卡裝置上指定 Pod IP 進行抓包。選取的裝置根據懷疑導緻網絡問題的原因而定,比如範圍由大縮小,從源端逐漸靠近目的端,比如懷疑是 CNI 插件導緻,則在 CNI 插件裝置上抓包。從 pod 發出的包逐一經過 veth 裝置,cni0 裝置,flannel0,主控端網卡,到達對端,抓包時可按順序逐一抓包,定位問題節點。

需要注意在不同裝置上抓包時指定的源目 IP 位址需要轉換,如抓取某 Pod 時,ping {host} 的包,在 veth 和 cni0 上可以指定 Pod IP 抓包,而在主控端網卡上如果仍然指定 Pod IP 會發現抓不到包,因為此時 Pod IP 已被轉換為主控端網卡 IP。

下圖是一個使用 VxLAN 模式的 flannel 的跨界點通訊的網絡模型,在抓包時需要注意對應的網絡接口

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

VxLAN in kubernetes

nsenter

nsenter 是一款可以進入程序的名稱空間中。例如,如果一個容器以非 root 使用者身份運作,而使用 docker exec 進入其中後,但該容器沒有安裝 sudo 或未 netstat ,并且您想檢視其目前的網絡屬性,如開放端口,這種場景下将如何做到這一點?nsenter 就是用來解決這個問題的。

nsenter (namespace enter) 可以在容器的主控端上使用 nsenter 指令進入容器的命名空間,以容器視角使用主控端上的相應網絡指令進行操作。當然需要擁有 root 權限

各系統下的安裝 [2\][1]

Ubuntu/Debian: util-linux ;apt-get install -y util-linux

Centos/Fedora: util-linux ;yum install -y util-linux

Apline:util-linux ;apk add util-linux --no-cache

nsenter 的 c 使用文法為,nsenter -t pid -n <commond>,-t 接 程序 ID 号,-n 表示進入名稱空間内,<commond> 為執行的指令。

執行個體:如我們有一個 Pod 程序 ID 為 30858,進入該 Pod 名稱空間内執行 ifconfig ,如下列所示

$ ps -ef|grep tail
root      17636  62887  0 20:19 pts/2    00:00:00 grep --color=auto tail
root      30858  30838  0 15:55 ?        00:00:01 tail -f

$ nsenter -t 30858 -n ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1480
        inet 192.168.1.213  netmask 255.255.255.0  broadcast 192.168.1.255
        ether 5e:d5:98:af:dc:6b  txqueuelen 0  (Ethernet)
        RX packets 92  bytes 9100 (8.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 92  bytes 8422 (8.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 5  bytes 448 (448.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 5  bytes 448 (448.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

net1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.1.0.201  netmask 255.255.255.0  broadcast 10.1.0.255
        ether b2:79:f9:dd:2a:10  txqueuelen 0  (Ethernet)
        RX packets 228  bytes 21272 (20.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 216  bytes 20272 (19.7 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0           

如何定位 Pod 名稱空間

首先需要确定 Pod 所在的節點名稱

$ kubectl get pods -owide |awk '{print $1,$7}'
NAME NODE
netbox-85865d5556-hfg6v master-machine
netbox-85865d5556-vlgr4 node01           

如果 Pod 不在目前節點還需要用 IP 登入則還需要檢視 IP(可選)

$ kubectl get pods -owide |awk '{print $1,$6,$7}'
NAME IP NODE
netbox-85865d5556-hfg6v 192.168.1.213 master-machine
netbox-85865d5556-vlgr4 192.168.0.4 node01           

接下來,登入節點,擷取容器 lD,如下列所示,每個 pod 預設有一個 pause 容器,其他為使用者 yaml 檔案中定義的容器,理論上所有容器共享相同的網絡命名空間,排查時可任選一個容器。

$ docker ps |grep netbox-85865d5556-hfg6v
6f8c58377aae   f78dd05f11ff                                                    "tail -f"                45 hours ago   Up 45 hours             k8s_netbox_netbox-85865d5556-hfg6v_default_4a8e2da8-05d1-4c81-97a7-3d76343a323a_0
b9c732ee457e   registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.1   "/pause"                 45 hours ago   Up 45 hours             k8s_POD_netbox-85865d5556-hfg6v_default_4a8e2da8-05d1-4c81-97a7-3d76343a323a_0           

接下來獲得擷取容器在節點系統中對應的程序号,如下所示

$ docker inspect --format "{{ .State.Pid }}" 6f8c58377aae
30858           

最後就可以通過 nsenter 進入容器網絡空間執行指令了

paping

paping 指令可對目标位址指定端口以 TCP 協定進行連續 ping,通過這種特性可以彌補 ping ICMP 協定,以及 nmap , telnet 隻能進行一次操作的的不足;通常情況下會用于測試端口連通性和丢包率

paping download:paping[2]

paping 還需要安裝以下依賴,這取決于你安裝的 paping 版本

  • RedHat/CentOS:yum install -y libstdc++.i686 glibc.i686
  • Ubuntu/Debian:最小化安裝無需依賴
$ paping -h
paping v1.5.5 - Copyright (c) 2011 Mike Lovell

Syntax: paping [options] destination

Options:
 -?, --help     display usage
 -p, --port N   set TCP port N (required)
     --nocolor  Disable color output
 -t, --timeout  timeout in milliseconds (default 1000)
 -c, --count N  set number of checks to N           

mtr

mtr 是一個跨平台的網絡診斷工具,将 traceroute 和 ping 的功能結合到一個工具。與 traceroute 不同的是 mtr 顯示的資訊比起 traceroute 更加豐富:通過 mtr 可以确定網絡的條數,并且可以同時列印響應百分比以及網絡中各跳躍點的響應時間。

各系統下的安裝 [2\][3]

Ubuntu/Debian: mtr ;apt-get install -y mtr

Centos/Fedora: mtr ;yum install -y mtr

Apline:mtr ;apk add mtr --no-cache

簡單的使用示例

最簡單的示例,就是後接域名或 IP,這将跟蹤整個路由

$ mtr google.com

Start: Thu Jun 28 12:10:13 2018
HOST: TecMint                     Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 192.168.0.1                0.0%     5    0.3   0.3   0.3   0.4   0.0
  2.|-- 5.5.5.211                  0.0%     5    0.7   0.9   0.7   1.3   0.0
  3.|-- 209.snat-111-91-120.hns.n 80.0%     5    7.1   7.1   7.1   7.1   0.0
  4.|-- 72.14.194.226              0.0%     5    1.9   2.9   1.9   4.4   1.1
  5.|-- 108.170.248.161            0.0%     5    2.9   3.5   2.0   4.3   0.7
  6.|-- 216.239.62.237             0.0%     5    3.0   6.2   2.9  18.3   6.7
  7.|-- bom05s12-in-f14.1e100.net  0.0%     5    2.1   2.4   2.0   3.8   0.5           

-n 強制 mtr 列印 IP 位址而不是主機名

$ mtr -n google.com

Start: Thu Jun 28 12:12:58 2018
HOST: TecMint                     Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 192.168.0.1                0.0%     5    0.3   0.3   0.3   0.4   0.0
  2.|-- 5.5.5.211                  0.0%     5    0.9   0.9   0.8   1.1   0.0
  3.|-- ???                       100.0     5    0.0   0.0   0.0   0.0   0.0
  4.|-- 72.14.194.226              0.0%     5    2.0   2.0   1.9   2.0   0.0
  5.|-- 108.170.248.161            0.0%     5    2.3   2.3   2.2   2.4   0.0
  6.|-- 216.239.62.237             0.0%     5    3.0   3.2   3.0   3.3   0.0
  7.|-- 172.217.160.174            0.0%     5    3.7   3.6   2.0   5.3   1.4           

-b 同時顯示 IP 位址與主機名

$ mtr -b google.com

Start: Thu Jun 28 12:14:36 2018
HOST: TecMint                     Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 192.168.0.1                0.0%     5    0.3   0.3   0.3   0.4   0.0
  2.|-- 5.5.5.211                  0.0%     5    0.7   0.8   0.6   1.0   0.0
  3.|-- 209.snat-111-91-120.hns.n  0.0%     5    1.4   1.6   1.3   2.1   0.0
  4.|-- 72.14.194.226              0.0%     5    1.8   2.1   1.8   2.6   0.0
  5.|-- 108.170.248.209            0.0%     5    2.0   1.9   1.8   2.0   0.0
  6.|-- 216.239.56.115             0.0%     5    2.4   2.7   2.4   2.9   0.0
  7.|-- bom07s15-in-f14.1e100.net  0.0%     5    3.7   2.2   1.7   3.7   0.9           

-c 跟一個具體的值,這将限制 mtr ping 的次數,到達次數後會退出

$ mtr -c5 google.com           

如果需要指定次數,并且在退出後儲存這些資料,使用 -r flag

$ mtr -r -c 5 google.com >  1
$ cat 1
Start: Sun Aug 21 22:06:49 2022
HOST: xxxxx.xxxxx.xxxx.xxxx Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- gateway                    0.0%     5    0.6 146.8   0.6 420.2 191.4
  2.|-- 212.xx.21.241              0.0%     5    0.4   1.0   0.4   2.3   0.5
  3.|-- 188.xxx.106.124            0.0%     5    0.7   1.1   0.7   2.1   0.5
  4.|-- ???                       100.0     5    0.0   0.0   0.0   0.0   0.0
  5.|-- 72.14.209.89               0.0%     5   43.2  43.3  43.1  43.3   0.0
  6.|-- 108.xxx.250.33             0.0%     5   43.2  43.1  43.1  43.2   0.0
  7.|-- 108.xxx.250.34             0.0%     5   43.7  43.6  43.5  43.7   0.0
  8.|-- 142.xxx.238.82             0.0%     5   60.6  60.9  60.6  61.2   0.0
  9.|-- 142.xxx.238.64             0.0%     5   59.7  67.5  59.3  89.8  13.2
 10.|-- 142.xxx.37.81              0.0%     5   62.7  62.9  62.6  63.5   0.0
 11.|-- 142.xxx.229.85             0.0%     5   61.0  60.9  60.7  61.3   0.0
 12.|-- xx-in-f14.1e100.net  0.0%     5   59.0  58.9  58.9  59.0   0.0           

預設使用的是 ICMP 協定 -i ,可以指定 -u, -t 使用其他協定

mtr --tcp google.com           

-m 指定最大的跳數

mtr -m 35 216.58.223.78
           

-s 指定包的大小

mtr 輸出的資料

columdescribelast最近一次的探測延遲值avg探測延遲的平均值best探測延遲的最小值wrst探測延遲的最大值stdev标準偏差。越大說明相應節點越不穩定

丢包判斷

任一節點的 Loss%(丢包率)如果不為零,則說明這一跳網絡可能存在問題。導緻相應節點丢包的原因通常有兩種。

  • 營運商基于安全或性能需求,人為限制了節點的 ICMP 發送速率,導緻丢包。
  • 節點确實存在異常,導緻丢包。可以結合異常節點及其後續節點的丢包情況,來判定丢包原因。

Notes:

如果随後節點均沒有丢包,則通常說明異常節點丢包是由于營運商政策限制所緻。可以忽略相關丢包。

如果随後節點也出現丢包,則通常說明節點确實存在網絡異常,導緻丢包。對于這種情況,如果異常節點及其後續節點連續出現丢包,而且各節點的丢包率不同,則通常以最後幾跳的丢包率為準。如鍊路測試在第 5、6、7 跳均出現了丢包。最終丢包情況以第 7 跳作為參考。

延遲判斷

由于鍊路抖動或其它因素的影響,節點的 Best 和 Worst 值可能相差很大。而 Avg(平均值)統計了自鍊路測試以來所有探測的平均值,是以能更好的反應出相應節點的網絡品質。而 StDev(标準偏內插補點)越高,則說明資料包在相應節點的延時值越不相同(越離散)。是以标準偏內插補點可用于協助判斷 Avg 是否真實反應了相應節點的網絡品質。例如,如果标準偏差很大,說明資料包的延遲是不确定的。可能某些資料包延遲很小(例如:25ms),而另一些延遲卻很大(例如:350ms),但最終得到的平均延遲反而可能是正常的。是以此時 Avg 并不能很好的反應出實際的網絡品質情況。

這就需要結合如下情況進行判斷:

  • 如果 StDev 很高,則同步觀察相應節點的 Best 和 wrst,來判斷相應節點是否存在異常。
  • 如果 StDev 不高,則通過 Avg 來判斷相應節點是否存在異常。

Pod 網絡排查流程

Pod 網絡異常時排查思路,可以按照下圖所示

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

Pod network troubleshooting idea

案例學習

擴容節點通路 service 位址不通

測試環境 k8s 節點擴容後無法通路叢集 clusterlP 類型的 registry 服務

環境資訊:

IPHostnamerole10.153.204.15yq01-aip-aikefu12worknode 節點(本次擴容的問題節點)10.153.203.14yq01-aip-aikefu31master 節點10.61.187.42yq01-aip-aikefu2746f8e9master 節點10.61.187.48yq01-aip-aikefu30b61e25master 節點(本次 registry 服務 pod 所在 節點)

  • cni 插件:flannel vxlan
  • kube-proxy 工作模式為 iptables
  • registry 服務
    • 單執行個體部署在 10.61.187.48:5000
    • Pod IP:10.233.65.46,
    • Cluster IP:10.233.0.100

現象:

  • 所有節點之間的 pod 通信正常
  • 任意節點和 Pod curl registry 的 Pod 的 IP:5000 均可以連通
  • 新擴容節點 10.153.204.15 curl registry 服務的 Cluster lP 10.233.0.100:5000 不通,其他節點 curl 均可以連通

分析思路:

  • 根據現象 1 可以初步判斷 CNI 插件無異常
  • 根據現象 2 可以判斷 registry 的 Pod 無異常
  • 根據現象 3 可以判斷 registry 的 service 異常的可能性不大,可能是新擴容節點通路 registry 的 service 存在異常

懷疑方向:

  • 問題節點的 kube-proxy 存在異常
  • 問題節點的 iptables 規則存在異常
  • 問題節點到 service 的網絡層面存在異常

排查過程:

  • 排查問題節點的 kube-proxy
  • 執行 kubectl get pod -owide -nkube-system l grep kube-proxy 檢視 kube-proxy Pod 的狀态,問題節點上的 kube-proxy Pod 為 running 狀态
  • 執行 kubecti logs <nodename> <kube-proxy pod name> -nkube-system 檢視問題節點 kube-proxy 的 Pod 日志,沒有異常報錯
  • 在問題節點作業系統上執行 iptables -S -t nat 檢視 iptables 規則

排查過程:

确認存在到 registry 服務的 Cluster lP 10.233.0.100 的 KUBE-SERVICES 鍊,跳轉至 KUBE-SVC-* 鍊做負載均衡,再跳轉至 KUBE-SEP-* 鍊通過 DNAT 替換為服務後端 Pod 的 IP 10.233.65.46。是以判斷 iptables 規則無異常執行 route-n 檢視問題節點存在通路 10.233.65.46 所在網段的路由,如圖所示

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

10.233.65.46 路由

檢視對端的回程路由

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

回程路由

以上排查證明問題原因不是 cni 插件或者 kube-proxy 異常導緻,是以需要在通路鍊路上抓包,判斷問題原因、問題節點執行 curl 10.233.0.100:5000,在問題節點和後端 pod 所在節點的 flannel.1 上同時抓包發包節點一直在重傳,Cluster lP 已 DNAT 轉換為後端 Pod IP,如圖所示

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

抓包過程,發送端

後端 Pod( registry 服務)所在節點的 flannel.1 上未抓到任何資料包,如圖所示

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

抓包過程,服務端

請求 service 的 ClusterlP 時,在兩端實體機網卡抓包,發包端如圖所示,封裝的源端節點 IP 是 10.153.204.15,但一直在重傳

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

包傳送過程,發送端

收包端收到了包,但未回包,如圖所示

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

包傳送過程,服務端

由此可以知道,NAT 的動作已經完成,而隻是後端 Pod( registry 服務)沒有回包,接下來在問題節點執行 curl10.233.65.46:5000,在問題節點和後端( registry 服務)Pod 所在節點的 flannel.1 上同時抓包,兩節點收發正常,發包如圖所示

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

正常包發送端

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

正常包接收端

接下來在兩端實體機網卡接口抓包,因為資料包通過實體機網卡會進行 vxlan 封裝,需要抓 vxlan 裝置的 8472 端口,發包端如圖所示

發現網絡鍊路連通,但封裝的 IP 不對,封裝的源端節點 IP 是 10.153.204.228,但是存在問題節點的 IP 是 10.153.204.15

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

問題節點實體機網卡接口抓包

後端 Pod 所在節點的實體網卡上抓包,注意需要過濾其他正常節點的請求包,如圖所示;發現收到的資料包,源位址是 10.153.204.228,但是問題節點的 IP 是 10.153.204.15。

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

對端節點實體機網卡接口抓包

此時問題以及清楚了,是一個 Pod 存在兩個 IP,導緻發包和回包時無法通過隧道裝置找到對端的接口,是以發可以收到,但不能回。

問題節點執行 ip addr,發現網卡 enp26s0f0 上配置了兩個 IP,如圖所示

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

問題節點 IP

進一步檢視網卡配置檔案,發現網卡既配置了靜态 IP,又配置了 dhcp 動态擷取 IP。如圖所示

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

問題節點網卡配置

最終定位原因為問題節點既配置了 dhcp 擷取 IP,又配置了靜态 IP,導緻 IP 沖突,引發網絡異常

解決方法:修改網卡配置檔案 /etc/sysconfig/network-scripts/ifcfg-enp26s0f0 裡 BOOTPROTO="dhcp"為 BOOTPROTO="none";重新開機 docker 和 kubelet 問題解決。

叢集外雲主機調用叢集内應用逾時

問題現象:Kubernetes 叢集外雲主機以 http post 方式通路 Kubernetes 叢集應用接口逾時

環境資訊:Kubernetes 叢集:calicoIP-IP 模式,應用接口以 nodeport 方式對外提供服務

用戶端:Kubernetes 叢集之外的雲主機

排查過程:

  • 在雲主機 telnet 應用接口位址和端口,可以連通,證明網絡連通正常,如圖所示
  • 雲主機上調用接口不通,在雲主機和 Pod 所在 Kubernetes 節點同時抓包,使用 wireshark 分析資料包
用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

通過抓包結果分析結果為 TCP 連結建立沒有問題,但是在傳輸大資料的時候會一直重傳 1514 大小的第一個資料包直至逾時。懷疑是鍊路兩端 MTU 大小不一緻導緻(現象:某一個固定大小的包一直逾時的情況)。如圖所示,1514 大小的包一直在重傳。

封包 1-3 TCP 三次握手正常

封包 1 info 中 MSS 字段可以看到 MSS 協商為 1460,MTU=1460+20bytes(IP 標頭)+20bytes(TCP 標頭)=1500

封包 7 k8s 主機确認了包 4 的資料包,但是後續再沒有對資料的 ACK

封包 21-29 可以看到雲主機一直在發送後面的資料,但是沒有收到 k8s 節點的 ACK,結合 pod 未收到任何封包,表明是 k8s 節點和 POD 通信出現了問題。

用Kubernetes 網絡排錯,在 Kubernetes 叢集發生網絡異常時如何排查

wireshark 分析

在雲主機上使用 ping -s 指定資料包大小,發現超過 1400 大小的資料包無法正常發送。結合以上情況,定位是雲主機網卡配置的 MTU 是 1500,tunl0 配置的 MTU 是 1440,導緻大資料包無法發送至 tunl0 ,是以 Pod 沒有收到封包,接口調用失敗。

解決方法:修改雲主機網卡 MTU 值為 1440,或者修改 calico 的 MTU 值為 1500,保持鍊路兩端 MTU 值一緻。

叢集 pod 通路對象存儲逾時

環境資訊:公有雲環境,Kubernetes 叢集節點和對象存儲在同一私有網絡下,網絡鍊路無防火牆限制 k8s 叢集開啟了節點自動彈縮(CA)和 Pod 自動彈縮(HPA),通過域名通路對象存儲,Pod 使用叢集 DNS 服務,叢集 DNS 服務配置了使用者自建上遊 DNS 伺服器

排查過程:

  • 使用 nsenter 工具進入 pod 容器網絡命名空間測試,ping 對象存儲域名不通,報錯 unknown server name,ping 對象存儲 lP 可以連通。
  • telnet 對象存儲 80/443 端口可以連通。
  • paping 對象存儲 80/443 端口無丢包。
  • 為了驗證 Pod 建立好以後的初始階段網絡連通性,将以上測試動作寫入 dockerfile,重新生成容器鏡像并創 pod,測試結果一緻。

通過上述步驟,判斷 Pod 網絡連通性無異常,逾時原因為域名解析失敗,懷疑問題如下:

  • 叢集 DNS 服務存在異常
  • 上遊 DNS 服務存在異常
  • 叢集 DNS 服務與上遊 DNS 通訊異常
  • pod 通路叢集 DNS 服務異常

根據上述方向排查,叢集 DNS 服務狀态正常,無報錯。測試 Pod 分别使用叢集 DNS 服務和上遊 DNS 服務解析域名,前者解析失敗,後者解析成功。至此,證明上遊 DNS 服務正常,并且叢集 DNS 服務日志中沒有與上遊 DNS 通訊逾時的報錯。定位到的問題:Pod 通路叢集 DNS 服務逾時

此時發現,出現問題的 Pod 集中在新彈出的 Kubernetes 節點上。這些節點的 kube-proxy Pod 狀态全部為 pending,沒有正常排程到節點上。是以導緻該節點上其他 Pod 無法通路包括 dns 在内的所有 Kubernetes service。

再進一步排查發現 kube-proxy Pod 沒有配置 priorityclass 為最高優先級,導緻節點資源緊張時為了将高優先級的應用 Pod 排程到該節點,将原本已運作在該節點的 kube-proxy 驅逐。

解決方法:将 kube-proxy 設定 priorityclass 值為 system-node-critical 最高優先級,同時建議應用 Pod 配置就緒探針,測試可以正常連通對象存儲域名後再配置設定任務。

引用連結

[1] [2]: https://www.cnblogs.com/Cylon/p/16611503.html#2

[2] paping: https://code.google.com/archive/p/paping/

[3] [2]: https://www.cnblogs.com/Cylon/p/16611503.html#2

[4] 文章: https://www.cnblogs.com/Cylon/p/14946935.htm

繼續閱讀