本頁說明如何解決 Google Kubernetes Engine (GKE) 叢集的連線問題。
在 GKE 中擷取網路封包時發生的連線問題
本節說明如何排解與擷取網路封包相關的連線問題,包括連線逾時、連線遭拒錯誤或應用程式行為異常等徵兆。這些連線問題可能發生在節點層級或 Pod 層級。
叢集網路的連線問題通常屬於下列類別:
- 無法連線至 Pod:由於網路設定錯誤,可能無法從叢集內外存取 Pod。
- 服務中斷:服務可能中斷或延遲。
- Pod 間通訊問題:Pod 可能無法有效通訊。
GKE 叢集的連線問題可能源自各種原因,包括:
- 網路設定錯誤:網路政策、防火牆規則或路由表有誤。
- 應用程式錯誤:應用程式程式碼中的錯誤,會影響網路互動。
- 基礎架構問題:網路壅塞、硬體故障或資源限制。
下一節說明如何解決有問題的節點或 Pod 上的問題。
使用下列指令,找出問題 Pod 執行的節點:
kubectl get pods POD_NAME -o=wide -n NAMESPACE
更改下列內容:
- 將
POD_NAME
替換為 Pod 的名稱。 NAMESPACE
,並使用 Kubernetes 命名空間。
- 將
連線至節點:
gcloud compute ssh NODE_NAME \ --zone=ZONE
更改下列內容:
NODE_NAME
:節點名稱。ZONE
:節點執行的可用區名稱。
如要偵錯特定 Pod,請找出與該 Pod 相關聯的
veth
介面:ip route | grep POD_IP
將
POD_IP
替換為 Pod IP 位址。執行工具箱指令。
toolbox
指令
toolbox
是一項公用程式,可在 GKE 節點中提供容器化環境,用於偵錯和疑難排解。本節說明如何安裝 toolbox
公用程式,並使用該程式排解節點問題。
連線至節點後,啟動
toolbox
工具:toolbox
這會下載有助於
toolbox
公用程式的檔案。在
toolbox
根提示中,安裝tcpdump
:如果叢集有外部 IP 位址或 Cloud NAT:
apt update -y && apt install -y tcpdump
適用於沒有 Cloud NAT 的私人叢集:
如果您有不含 Cloud NAT 的私人叢集,就無法使用
apt
安裝tcpdump
。請改為從官方存放區下載libpcap
和tcpdump
版本檔案,然後使用gcloud compute scp
或gcloud storage cp
將檔案複製到 VM。然後按照下列步驟手動安裝程式庫:cp /media/root/home/USER_NAME/tcpdump-VERSION.tar.gz /usr/sbin/ cp /media/root/home/USER_NAME/libpcap-VERSION.tar.gz /usr/sbin/ cd /usr/sbin/ tar -xvzf tcpdump-VERSION.tar.gz tar -xvzf libpcap-VERSION.tar.gz cd libpcap-VERSION ./configure ; make ; make install cd ../tcpdump-VERSION ./configure ; make ; make install tcpdump --version
更改下列內容:
USER_NAME
:檔案所在系統的使用者名稱。VERSION
:tcpdump
和libpcap
套件的特定版本號碼。
開始擷取封包:
tcpdump -i eth0 -s 100 "port PORT" \ -w /media/root/mnt/stateful_partition/CAPTURE_FILE_NAME
更改下列內容:
PORT
:通訊埠編號的名稱。CAPTURE_FILE_NAME
:擷取檔案的名稱。
停止封包擷取作業,並中斷
tcpdump
。輸入
exit
即可離開工具箱。列出封包擷取檔案並檢查其大小:
ls -ltr /mnt/stateful_partition/CAPTURE_FILE_NAME
將節點中的封包擷取內容複製到電腦目前的工作目錄:
gcloud compute scp NODE_NAME:/mnt/stateful_partition/CAPTURE_FILE_NAME \ --zone=ZONE
更改下列內容:
NODE_NAME
:節點名稱。CAPTURE_FILE_NAME
:擷取檔案的名稱。ZONE
:可用區名稱。
其他指令
你也可以使用下列方法,排解有問題的 Pod 連線問題:
暫時性偵錯工作負載 附加至 Pod 容器。
使用
kubectl exec
直接在目標 Pod 上執行殼層,然後安裝並啟動tcpdump
指令。
Pod 網路連線問題
如網路總覽討論中所述,請務必瞭解 Pod 如何從網路命名空間連線至節點上的根命名空間,以便有效排除問題。除非另有說明,否則以下討論皆假設叢集使用 GKE 的原生 CNI,而非 Calico 的 CNI。也就是說,系統未套用任何聯播網政策。
所選節點上的 Pod 無法使用
如果特定節點上的 Pod 無法連上網路,請確認 Linux 橋接器已啟動:
ip address show cbr0
如果 Linux 橋接器已關閉,請開啟:
sudo ip link set cbr0 up
確認節點正在學習連結至 cbr0 的 Pod MAC 位址:
arp -an
所選節點上的 Pod 連線能力有限
如果特定節點上的 Pod 連線能力不佳,請先在工具箱容器中執行 tcpdump
,確認是否有任何封包遺失:
sudo toolbox bash
如果尚未安裝,請在工具箱中安裝 tcpdump
:
apt install -y tcpdump
針對 cbr0 執行 tcpdump
:
tcpdump -ni cbr0 host HOSTNAME and port PORT_NUMBER and [TCP|UDP|ICMP]
如果發現大型封包在橋接器下游遭到捨棄 (例如 TCP 交握完成,但未收到 SSL hello),請確認每個 Linux Pod 介面的 MTU 已正確設為叢集 VPC 網路的 MTU。
ip address show cbr0
使用疊加層 (例如 Weave 或 Flannel) 時,必須進一步縮減 MTU,以容納疊加層的封裝額外負荷。
GKE MTU
為 Pod 介面選取的 MTU 取決於叢集節點使用的容器網路介面 (CNI) 和基礎 VPC MTU 設定。詳情請參閱「Pod」。
Pod 介面 MTU 值為 1460
,或從節點的主要介面繼承。
CNI | MTU | GKE Standard |
---|---|---|
kubenet | 1460 | 預設 |
kubenet (GKE 1.26.1 以上版本) |
已繼承 | 預設 |
Calico | 1460 |
使用 詳情請參閱使用網路政策控管 Pod 和服務之間的通訊。 |
netd | 已繼承 | 使用下列任一項目啟用: |
GKE Dataplane V2 | 已繼承 |
使用 詳情請參閱「使用 GKE Dataplane V2」。 |
連線失敗次數時多時少
iptables 會轉送 Pod 的連線。系統會將流程追蹤為 conntrack 表格中的項目,如果每個節點的工作負載數量過多,conntrack 表格耗盡可能會導致失敗。這些資訊可以記錄在節點的序列控制台中,例如:
nf_conntrack: table full, dropping packet
如果判斷間歇性問題是由 conntrack 耗盡所致,您可以增加叢集大小 (藉此減少每個節點的工作負載和流程數量),或增加 nf_conntrack_max
:
new_ct_max=$(awk '$1 == "MemTotal:" { printf "%d\n", $2/32; exit; }' /proc/meminfo)
sysctl -w net.netfilter.nf_conntrack_max="${new_ct_max:?}" \
&& echo "net.netfilter.nf_conntrack_max=${new_ct_max:?}" >> /etc/sysctl.conf
您也可以使用 NodeLocal DNSCache 減少連線追蹤項目。
容器回報「bind: Address already in use」
Pod 中的容器無法啟動,因為根據容器記錄,應用程式嘗試繫結的連接埠已保留。容器發生當機迴圈。舉例來說,在 Cloud Logging 中:
resource.type="container"
textPayload:"bind: Address already in use"
resource.labels.container_name="redis"
2018-10-16 07:06:47.000 CEST 16 Oct 05:06:47.533 # Creating Server TCP listening socket *:60250: bind: Address already in use
2018-10-16 07:07:35.000 CEST 16 Oct 05:07:35.753 # Creating Server TCP listening socket *:60250: bind: Address already in use
Docker 異常終止時,有時會留下執行中的容器,且容器會過時。該程序仍在為 Pod 分配的網路命名空間中執行,並監聽其通訊埠。由於 Docker 和 kubelet 不知道過時的容器,因此會嘗試使用新程序啟動新容器,但新程序無法繫結至該連接埠,因為該連接埠已新增至與 Pod 相關聯的網路命名空間。
如要診斷這個問題,請按照下列步驟操作:
您需要
.metadata.uuid
欄位中的 Pod UUID:kubectl get pod -o custom-columns="name:.metadata.name,UUID:.metadata.uid" ubuntu-6948dd5657-4gsgg name UUID ubuntu-6948dd5657-4gsgg db9ed086-edba-11e8-bdd6-42010a800164
從節點取得下列指令的輸出內容:
docker ps -a ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]
檢查這個 Pod 中執行的程序。由於 cgroup 命名空間的 UUID 包含 Pod 的 UUID,因此您可以在
ps
輸出內容中 grep Pod UUID。同時使用 Grep 找出前一行,這樣您也會在引數中取得含有容器 ID 的docker-containerd-shim
程序。剪下其餘 cgroup 欄,以取得較簡單的輸出內容:# ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep -B 1 db9ed086-edba-11e8-bdd6-42010a800164 | sed s/'blkio:.*'/''/ 1283089 959 Sl futex_wait_queue_me 4026531993 docker-co docker-containerd-shim 276e173b0846e24b704d4 12: 1283107 1283089 Ss sys_pause 4026532393 pause /pause 12: 1283150 959 Sl futex_wait_queue_me 4026531993 docker-co docker-containerd-shim ab4c7762f5abf40951770 12: 1283169 1283150 Ss do_wait 4026532393 sh /bin/sh -c echo hello && sleep 6000000 12: 1283185 1283169 S hrtimer_nanosleep 4026532393 sleep sleep 6000000 12: 1283244 959 Sl futex_wait_queue_me 4026531993 docker-co docker-containerd-shim 44e76e50e5ef4156fd5d3 12: 1283263 1283244 Ss sigsuspend 4026532393 nginx nginx: master process nginx -g daemon off; 12: 1283282 1283263 S ep_poll 4026532393 nginx nginx: worker process
從這個清單中,您可以看到容器 ID,這些 ID 也應該會顯示在
docker ps
中。在這種情況下:
docker-containerd-shim 276e173b0846e24b704d4
暫停docker-containerd-shim ab4c7762f5abf40951770
for sh with sleep (sleep-ctr)docker-containerd-shim 44e76e50e5ef4156fd5d3
(適用於 nginx (echoserver-ctr))
請在
docker ps
輸出內容中查看這些項目:# docker ps --no-trunc | egrep '276e173b0846e24b704d4|ab4c7762f5abf40951770|44e76e50e5ef4156fd5d3' 44e76e50e5ef4156fd5d383744fa6a5f14460582d0b16855177cbed89a3cbd1f gcr.io/google_containers/echoserver@sha256:3e7b182372b398d97b747bbe6cb7595e5ffaaae9a62506c725656966d36643cc "nginx -g 'daemon off;'" 14 hours ago Up 14 hours k8s_echoserver-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0 ab4c7762f5abf40951770d3e247fa2559a2d1f8c8834e5412bdcec7df37f8475 ubuntu@sha256:acd85db6e4b18aafa7fcde5480872909bd8e6d5fbd4e5e790ecc09acc06a8b78 "/bin/sh -c 'echo hello && sleep 6000000'" 14 hours ago Up 14 hours k8s_sleep-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0 276e173b0846e24b704d41cf4fbb950bfa5d0f59c304827349f4cf5091be3327 registry.k8s.io/pause-amd64:3.1
在正常情況下,您會在
docker ps
中看到ps
的所有容器 ID。如果找不到,表示容器過時,您可能會看到docker-containerd-shim process
在 TCP 連接埠上接聽的子程序,該連接埠回報為已在使用中。如要驗證這點,請在容器的網路命名空間中執行
netstat
。取得 Pod 的任何容器程序 PID (因此「不是」docker-containerd-shim
)。從上述範例中:
- 1283107 - pause
- 1283169 - sh
- 1283185 - sleep
- 1283263 - nginx master
- 1283282 - nginx worker
# nsenter -t 1283107 --net netstat -anp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 1283263/nginx: mast Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node PID/Program name Path unix 3 [ ] STREAM CONNECTED 3097406 1283263/nginx: mast unix 3 [ ] STREAM CONNECTED 3097405 1283263/nginx: mast gke-zonal-110-default-pool-fe00befa-n2hx ~ # nsenter -t 1283169 --net netstat -anp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 1283263/nginx: mast Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node PID/Program name Path unix 3 [ ] STREAM CONNECTED 3097406 1283263/nginx: mast unix 3 [ ] STREAM CONNECTED 3097405 1283263/nginx: mast
您也可以使用
ip netns
執行netstat
,但需要手動連結程序的網路命名空間,因為 Docker 不會執行連結:# ln -s /proc/1283169/ns/net /var/run/netns/1283169 gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns list 1283169 (id: 2) gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns exec 1283169 netstat -anp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 1283263/nginx: mast Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node PID/Program name Path unix 3 [ ] STREAM CONNECTED 3097406 1283263/nginx: mast unix 3 [ ] STREAM CONNECTED 3097405 1283263/nginx: mast gke-zonal-110-default-pool-fe00befa-n2hx ~ # rm /var/run/netns/1283169
因應措施:
短期解決方法是使用上述方法找出閒置程序,然後使用 kill [PID]
指令終止程序。
長期解決方案包括找出 Docker 崩潰的原因並加以修正。可能的原因包括:
- 廢止程序堆積,導致 PID 命名空間用盡
- Docker 中的錯誤
- 資源壓力 / 記憶體不足
後續步驟
如需診斷 Kubernetes DNS 問題的一般資訊,請參閱「偵錯 DNS 解析」。
如果無法在說明文件中找到問題的解決方法,請參閱「取得支援」一文,尋求進一步的協助, 包括下列主題的建議:
- 與 Cloud 客戶服務聯絡,建立支援案件。
- 在 StackOverflow 上提問,並使用
google-kubernetes-engine
標記搜尋類似問題,向社群尋求支援。你也可以加入#kubernetes-engine
Slack 頻道,取得更多社群支援。 - 使用公開問題追蹤工具回報錯誤或提出功能要求。