滴普技术荟-云原生基座OpenKube开放容器实践(三):理解linux虚拟网络设备bridge

295 阅读3分钟

前言

上一节我们介绍了Linux veth设备,了解了如何把多个独立网络命名空间(下面开始简称NS)与主机互通,并且多个NS间也能相互通信,在这一节我们将介绍另一种方式,用linux bridge。

linux bridge

Linux bridge即linux虚拟网桥,工作方式类似于物理的网络交换机,工作在二层时,能够转发以太网报文,能够学习MAC地址与端口的映射关系,下面通过一些示例来了解一下。我们将通过linux bridge连接两个NS,通过下面的命令可以创建一个linux bridge并启动:

接下来我们创建两个新的NS和两对linux veth网卡:

接下来就是把主机这边的两个端都插到bridge上:

就这样两个NS就可以相互PING通了,因为是相同网段,所以暂不需要默认网关,又因为linux bridge会广播ARP请求,NS1的协议栈能通过ARP广播拿到NS2中网卡的MAC地址。 但是此时在主机上ping两个ns反而是ping不通的,因为主机不知道怎么去192.168.10.0/24网段,所以先给主机加条路由:

注意主机的这条路由针对的是整个网段192.168.10.0/24,就是说后面如果继续加新的NS,只要IP还在这个段内,就不用再增加主机路由了。 来看一下现状:

主机加了路由后,从主机ping ns1还是不行,应该是ns1缺默认网关,所以不知道怎么回这个包,看一下当前NS1中的路由信息:

这条路由是我们在给veth0设置ip的时候由系统自动生成的。

我们给ns1和ns2都加个默认路由,然后打开br0的arp代答:

这时候应该就ping得通了。

为什么给ns1和ns2设置的默认网关是169.2.2.2?这个在上一章有解释过了,想了解的话请看回上一章的内容

区别

到目前为止我们介绍了两种在同个主机连接多个ns的方法,现在来介绍一下两种方法异同点:如果只是用veth连接,就是单纯地把主机当成路由器,两个ns之间的通信数据包都是要走主机协议栈的三层转发流程的,如图1所示:

而用bridge的方式,则在二层直接把数据包就从ns1转到了ns2,没有再走主机协议栈的三层,如图2所示:

这个我们可以用如下方式求证,用bridge的情况下,关掉主机的路由转发功能:

然后你会发现ns1中ping ns2其实还是可以ping通的。

那这样一来,主机的防火墙策略岂不是没用了?k8s的网络策略就是在主机的iptables规则中来控制的,为了让这个规则生效,还是有办法的,可以让经过linux bridge的数据包也过一遍iptabls规则:

开启了这个参数,数据包还是没有经过主机的协议栈的三层处理,只是linux bridge的__br_forward方法中显式地调用了NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD,net, NULL, skb, indev, skb->dev,br_forward_finish) 代码在:/net/bridge/br_forward.c 这时候在主机的iptables防火墙里增加一个过滤规则,把数据包全拦截掉:

然后ns1就ping不通ns2了。

总结 前面介绍的linux veth和linux bridge主要是用于完成同主机容器的相互通信,下一章我们来介绍一下如何配置跨主机的容器通信。

linux bridge 不能跨网络命名空间,所以不要尝试把br0转到ns1中,下面的命令会报错 ip link set br0 netns ns1 RTNETLINK answers: Invalid argument 凡是netns-local为on的设备都不能跨网络命名空间,像loopback/vxlan/bridge,用下面的命名可以查看eth0的netns-local的值 ethtool -k eth0|grep netns-local

更多信息欢迎关注滴普科技官网 datasink-sensors.deepexi.top/t/za

作者:刘海峰,IT行业资深码农,从事.net/java/go语言开发十余年,长期关注springcloud/k8s/linux网络相关的技术,