為什么 Pod 無(wú)法通過(guò) Service 訪問(wèn)自己?

問(wèn)題現(xiàn)象
創(chuàng)建一個(gè)nginx pod,并配置了service訪問(wèn),service后端指向pod。
進(jìn)入pod中使用service ip 或者service 域名,無(wú)法訪問(wèn)。
一開(kāi)始以為是環(huán)境配置或者k8s版本(1.9)的問(wèn)題,在其他1.13的kubernetes環(huán)境下也試了,還是同樣的問(wèn)題。
環(huán)境配置
使用的cni插件是flannel,但不是容器化安裝,也不是標(biāo)準(zhǔn)化的通過(guò)kubelet指定cni plugin(--cni-bin-dir,--cni-conf-dir參數(shù)),而是通過(guò)dockerd 提供的-bip參數(shù)指定容器的子網(wǎng),而這個(gè)值是從/run/flannel/subnet.env(flannel會(huì)將獲取到的子網(wǎng)寫(xiě)入到該文件)
排查過(guò)程
「1、首先嘗試通過(guò)pod ip嘗試是否可訪問(wèn),已驗(yàn)證是可通的。」
「2、嘗試對(duì)docker0網(wǎng)橋進(jìn)行抓包」
tcpdump -i docker0
神奇的在這里,再次嘗試通過(guò)service 訪問(wèn)是居然可以通,發(fā)現(xiàn)只要tcpdump斷開(kāi)就不行了。
?到這里的時(shí)候有點(diǎn)覺(jué)得詭異了
?
在pod內(nèi)通過(guò)service訪問(wèn)的時(shí)候網(wǎng)絡(luò)的流向應(yīng)該是
pod內(nèi)部訪問(wèn)service->docker0網(wǎng)橋->宿主機(jī)的iptables規(guī)則->docker0網(wǎng)橋->pod內(nèi)部
查閱了相關(guān)資料后,看到kubelet有個(gè)--hairpin-mod參數(shù):
文檔說(shuō)明:
?如果網(wǎng)絡(luò)沒(méi)有為“發(fā)夾模式”流量生成正確配置,通常當(dāng) kube-proxy 以 iptables 模式運(yùn)行,并且 Pod 與橋接網(wǎng)絡(luò)連接時(shí),就會(huì)發(fā)生這種情況。Kubelet 公開(kāi)了一個(gè) hairpin-mode 標(biāo)志,如果 pod 試圖訪問(wèn)它們自己的 Service VIP,就可以讓 Service 的端點(diǎn)重新負(fù)載到他們自己身上。hairpin-mode 標(biāo)志必須設(shè)置為 hairpin-veth 或者 promiscuous-bridge。
?
可是我設(shè)置之后還是沒(méi)有還是不行,翻了一下kubelet里面的代碼,發(fā)現(xiàn)cni組件并沒(méi)有取這個(gè)值做任何才做(在kubnet中有)
查看這個(gè)討論:https://github.com/kubernetes/kubernetes/issues/45790
「大致結(jié)論是,應(yīng)該由cni插件來(lái)根據(jù)這個(gè)值來(lái)做對(duì)應(yīng)的操作。」
還是沒(méi)解決我的問(wèn)題?
不過(guò)我看到hairpin開(kāi)啟的標(biāo)志位是通過(guò)/sys/devices/virtual/net/docker0/brif/veth-xxx/hairpin_mod 內(nèi)容設(shè)置為1開(kāi)啟的。
所以我將所有veth該文件內(nèi)容設(shè)置1
for intf in /sys/devices/virtual/net/docker0/brif/*; do echo 1> $intf/hairpin_mod; done
可以訪問(wèn)了。?
解疑:promiscuous-bridge 與 hairpin-veth
「為什么我無(wú)法訪問(wèn)」
bridge不允許包從收到包的端口發(fā)出,比如這種情況,在pod內(nèi)通過(guò)docker0訪問(wèn)service,后續(xù)又通過(guò)docker0網(wǎng)橋進(jìn)來(lái),所以需要開(kāi)啟hairpin_mod
「為什么使用tcpdump 可以讓訪問(wèn)可通?」
因?yàn)閠cpdump要抓取所有經(jīng)過(guò)該網(wǎng)卡,所以需要開(kāi)啟混雜模式。可以在/var/log/message看到device docker0 entered promiscuous mode的log。
?混雜模式(英語(yǔ):promiscuous mode)是電腦網(wǎng)絡(luò)中的術(shù)語(yǔ)。是指一臺(tái)機(jī)器的網(wǎng)卡能夠接收所有經(jīng)過(guò)它的數(shù)據(jù)流,而不論其目的地址是否是它。一般計(jì)算機(jī)網(wǎng)卡都工作在非混雜模式下,此時(shí)網(wǎng)卡只接受來(lái)自網(wǎng)絡(luò)端口的目的地址指向自己的數(shù)據(jù)。當(dāng)網(wǎng)卡工作在混雜模式下時(shí),網(wǎng)卡將來(lái)自接口的所有數(shù)據(jù)都捕獲并交給相應(yīng)的驅(qū)動(dòng)程序。
?
手動(dòng)開(kāi)關(guān)命令:ifconfig docker0 promisc on/off
總結(jié)
其實(shí)我們集群通過(guò)這種比較另類的方式來(lái)分配POD IP也用了了很久了,之所以沒(méi)出問(wèn)題,應(yīng)該是業(yè)務(wù)基本沒(méi)遇到這種pod內(nèi)通過(guò)service訪問(wèn)自己的情況。
所以還是要跟著標(biāo)準(zhǔn)的k8s方式來(lái)安裝cni,避免入坑,比如flannel就已經(jīng)提供給了hairpinMode參數(shù)來(lái)進(jìn)行配置開(kāi)啟。
?點(diǎn)擊屏末?|?閱讀原文?|?即刻學(xué)習(xí)