建立一个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相关技术![]()