建立一個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
能夠訪問了。😺
爲何我沒法訪問
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相關技術