記一次問題排查:爲何在POD沒法經過Service訪問本身?

問題現象

建立一個nginx pod,並配置了service訪問,service後端指向pod。nginx

進入pod中使用service ip 或者service 域名,沒法訪問。git

一開始覺得是環境配置或者k8s版本(1.9)的問題,在其餘1.13的kubernetes環境下也試了,仍是一樣的問題。github

環境配置

使用的cni插件是flannel,但不是容器化安裝,也不是標準化的經過kubelet指定cni plugin(--cni-bin-dir,--cni-conf-dir參數),而是經過dockerd 提供的-bip參數指定容器的子網,而這個值是從/run/flannel/subnet.env(flannel會將獲取到的子網寫入到該文件)docker

排查過程

一、首先嚐試經過pod ip嘗試是否可訪問,已驗證是可通的。segmentfault

二、嘗試對docker0網橋進行抓包後端

tcpdump -i docker0

神奇的在這裏,再次嘗試經過service 訪問是竟然能夠通,發現只要tcpdump斷開就不行了。網絡

到這裏的時候有點以爲詭異了

在pod內經過service訪問的時候網絡的流向應該是tcp

pod內部訪問service->docker0網橋->宿主機的iptables規則->docker0網橋->pod內部

查閱了相關資料後,看到kubelet有個--hairpin-mod參數:url

文檔說明:spa

若是網絡沒有爲「髮夾模式」流量生成正確配置,一般當 kube-proxy 以 iptables 模式運行,而且 Pod 與橋接網絡鏈接時,就會發生這種狀況。Kubelet 公開了一個 hairpin-mode 標誌,若是 pod 試圖訪問它們本身的 Service VIP,就可讓 Service 的端點從新負載到他們本身身上。hairpin-mode 標誌必須設置爲 hairpin-veth 或者 promiscuous-bridge。

但是我設置以後仍是沒有仍是不行,翻了一下kubelet裏面的代碼,發現cni組件並無取這個值作任何才作(在kubnet中有)

查看這個討論:
https://github.com/kubernetes/kubernetes/issues/45790

大體結論是,應該由cni插件來根據這個值來作對應的操做。

仍是沒解決個人問題?

不過我看到hairpin開啓的標誌位是經過/sys/devices/virtual/net/docker0/brif/veth-xxx/hairpin_mod 內容設置爲1開啓的。

因此我將全部veth該文件內容設置1

for intf in /sys/devices/virtual/net/docker0/brif/*; do echo 1> $intf/hairpin_mod; done

能夠訪問了。😺

解疑:promiscuous-bridge 與 hairpin-veth

爲何我沒法訪問

bridge不容許包從收到包的端口發出,好比這種狀況,在pod內經過docker0訪問service,後續又經過docker0網橋進來,因此須要開啓hairpin_mod

爲何使用tcpdump 可讓訪問可通?

由於tcpdump要抓取全部通過該網卡,因此須要開啓混雜模式。能夠在/var/log/message看到device docker0 entered promiscuous mode的log。

混雜模式(英語:promiscuous mode)是電腦網絡中的術語。 是指一臺機器的網卡可以接收全部通過它的數據流,而不論其目的地址是不是它。 通常計算機網卡都工做在非混雜模式下,此時網卡只接受來自網絡端口的目的地址指向本身的數據。 當網卡工做在混雜模式下時,網卡未來自接口的全部數據都捕獲並交給相應的驅動程序。

手動開關命令:
ifconfig docker0 promisc on/off

總結

其實咱們集羣經過這種比較另類的方式來分配POD IP也用了了好久了,之因此沒出問題,應該是業務基本沒遇到這種pod內經過service訪問本身的狀況。

因此仍是要跟着標準的k8s方式來安裝cni,避免入坑,好比flannel就已經提供給了hairpinMode 參數來進行配置開啓。

原文地址:https://silenceper.com/blog/202004/bridge-hairpin-mod/

關注《學點程序》公衆號,瞭解更多Go相關技術 學點程序
相關文章
相關標籤/搜索