Flannel利用了给不同的物理机设置不同的网段,来做到的网络互通设置
但是使用了Overlay网络,还是引入了另外的网络性能损耗
于是发明了Calico
Calico网络模型的设计思路
下面的两个物理机
我们是在同一个二层网络里面的,由于两台物理机的容器网段不同,可以将两台
物理机配置层路由器,并且按照容器的网段配置路由表
在物理机A上,我们可以配置,想要访问172.17.9.0/24就要从docker0网卡发出去,下一跳是192.168.100.101,到物理机B上去
这样从容器A访问容器B,当包通过docker0发送到物理机A的网卡的时候,就可以通过这个路由规则,发往下一跳的路由器到B,
在容器B返回结果的时候,在物理机B上,做类似的配置,访问网段172.17.8.0/24,下一跳是192.168.100.100,到物理机A上去
这样,处理完成,包到达了物理机B,能够匹配得上这条路由规则,并且发给下一跳的路由,就是路由器A,那么路由器A,可以配置一个路由规则,访问172.17.8.0/24,从docker0网卡进去
这就是Calico的大概思路,不走Overlay网络,不引入另外的网络性能损耗,将转发全部用三层网络的路由转发来实现
如果全部走三层的路由规则,没必要每个机器都用一个docker0作为网桥,直接通过路由规则转发到veth pair在物理机这一端的网卡,在容器内,路由规则可以设置为,在容器外的veth pair是默认网关,下一跳就是外面的物理机
那么整体的拓扑结构如上
看容器A1,IP地址为172.17.8.2/32,将容器A作为一个单点的局域网了
容器A1里面的默认路由,配置如下
default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link |
IP地址169.254.1.1是默认的网关,但是整个拓补图中没有一张网卡是这个地址的,如何到达的呢?
我们说网关的原理时候说过,一台机器要访问网关的时候,首先通过ARP获得MAC地址,然后将目标MAC变为网关MAC,但是IP和这个没关系,也就是说,Ip随便配,只要MAC能获取到就行
于是Calico硬塞进去一个MAC地址,能够响应ARP,发出的包目标MAC就是这个MAC地址
于是物理机查看所有网卡的MAC的时候,就会发现veth1就是这个MAC地址,所以容器A1发出的包,第一跳就是这个veth1这个网卡,就到了物理机A这个路由器
在物理机A上有三条路由规则,分别由去两个本机容器的路由,以及去172.17.9.0/24
下一条为物理机B
172.17.8.2 dev veth1 scope link
172.17.8.3 dev veth2 scope link
172.17.9.0/24 via 192.168.100.101 dev eth0 proto bird onlink
物理机B上也有三条路由,分别是去两个本机的容器的路由,以及172.17.8.0/24
下一跳就到了物理机A上
172.17.9.2 dev veth1 scope link
172.17.9.3 dev veth2 scope link
172.17.8.0/24 via 192.168.100.100 dev eth0 proto bird onlink
配置完成后,形成了如下的拓补图
这里,物理机化身了路由器,通过路由器上的路由规则,将包转发给了目的地,这一个过程中,纯粹的靠路由转发,性能好很多
Calico
因为,在一个容器网络中,很难保证容器的数量本身不变,容器经常进行创建,删除,节点不断的加入,退出,情况很复杂
就好比如图,有三台物理机,彼此之间要配置路由,对外的路由就有两条,如果有6台,,每台物理机上对外的路由就有5条,这样,每加入一个新的节点,就需要通知每一台物理机添加一条路由
这还是在物理机上,如果一个物理机上每次创建一个容器,就需要多配置一条指向这个容器的路由,这样,太过于麻烦了,就需要每个物理机上有一个agent,当删除或者创建容器的时候,自动做这件事,这个agent在Calico中叫做Felix
那么Felix,如何将路由信息保存并广播出去的呢?
其实,这就是路由协议,在公网的路由协议中,使用了BGP协议,将,如何到我,我是谁 广播了出去,Calico使用的BGP协议
在Calico中,每个节点Node上运行了一个软件BIRD,作为BGP的客户端,或者说BGP Speaker,也就是到达我这个Node,如何访问我这个Node上的容器的路由信息广播了出去,让所有的BGP Speaker都能建立起连接,形成了全互联的情况,每当有路由变化的时候,所有节点都能收到了
安全策略组件
因为容器之间仍然存在的不同用户不能通信的情况,所以如何做到的呢
还是基于了iptables,这个图里面的内容是iptables在内核处理网络包的过程中可以嵌入的处理点,Calico也是在这些点上设置了相应的规则
网络包进入物理机的时候,进入了PREOUTING的规则,这里面的一个规则是cali-fip-dnat,这是实现了浮动IP的场景,主要将外网的IP地址dnat作为容器内的IP地址
然后根据路由判断,是到本地的还是,转发出去的
本地的,走INPUT规则,里面有规则cali-wl-to-host,wl就是workload,就是容器,然后里面内嵌一个规则cali-from-wl-dispatch,匹配从容器来的包,如果有两个容器,就会有两个容器网卡,然后有两个网卡规则 cali-fw-cali网卡1,这里面的fw表示from workload,匹配从容器1来的网络包
如果是转发出去的,走FORWARD规则,里面有个规则cali-FORWARD,里面分为两种情况,从容器内部走出来,发到外面,从外面进来,发往容器里面的
第一种匹配的规则仍然是cali-from-wl-dispatch,也就是from workload,第二种匹配的是cali-to-wl-dispatch,to workload,在这里,就是匹配 to workload,匹配发往容器1的网络包和容器2的网络包
接下来是匹配OUTPUT的规则,里面有cali-OUTPUT,接下来是POSTROUTING规则,里面有一个规则cali-fip-snat,也就是发出去的时候,将容器的网络转换成浮动IP地址,在虚拟机的场景下,路由器的网络namespace里面有一个外网网卡,设置的这个SNAT
那么Calico的所有组件基本完成了,架构如下
那么,还有着问题,就是BGP全连接的复杂性问题
在上面之中,BGP的互连已经很复杂了,如果节点数据更多,这种全互联的模式,会更加的臃肿
于是推出了一个组件BGP Route Reflector,可以用BIRD实现,BGP不会全互联,而是直接连他,其负责将全网的路由信息广播出
但是,这个BGP Router Reflector会不会成为瓶颈呢?
所以,肯定不能让一个BGP Router Reflector 管理所以路由分发,而有BGP Router Reflector
每个BGP Router Reflector管理一部分
所以,一般来说,一个机架上会有一个TOR交换机,将机架上的机器连接在一起,这样,一个机架是不是一个单元.让一个BGP Router Reflector来管理,如果要跨机架,就需要BGP Router Reflector进行路由交换
一个机架就好比一个数据中心,可以设置为一个AS,而BGP Router Reflector有点像是数据中心的边界路由器,也就是BGP Router Reflector之间使用的是数据中心内部的路由协议iBGP,BGP Router Reflector之间使用的是数据中心之间的路由协议,eBGP
就好比,一个机架上有多台机器,每台机器上启动多个容器,每台机器上都有可以到达这些容器的路由,每台机器上都启动一个BGP Speaker,然后,然后这些路由规则上报到这个RACK上接入交换机的BGP Route Reflector,将这些路由通过iBGP协议告知到接入交换机的三层路由功能
然后在接入交换机之间建立BGP连接,彼此告知路由,因此一个Rack中的路由可以告知另一个Rack,有多个核心或者汇聚交换机将接入交换机连接起来,如果核心和汇聚起到了二层互通的作用,则接入和接入之间交换路由即可,如果核心和汇聚之间使用了三层路由,就需要通过核心或者汇聚交换机进行告知
跨网段访问问题
上面的Calico模式中,跨网段的问题是怎么办呢?
前面我们说的那些逻辑成立的条件,就是物理机作为路由器使用的,例如物理机A告诉物理机B,要访问172.17.8.0/24,下一跳就是192.168.100.100,同理,物理机B告诉物理机A,访问 172.17.9.0/24,下一跳是 192.168.100.101
如果不是一个网段,怎么办?
看上面,我们将原本的物理路由器的直接互联,在一个网段内,变成了玄奘西行
原本,两者在一个网段内,下一跳直接到即可,但是中间多了一台路由器,下一跳就不是我了,导致无法走一个网段的直接转发
物理机B上的容器要访问物理机A上的容器,第一跳就是物理机B,IP是192.168.200.101,第二条就是中间路由器的网口,IP为192.168.200.1,第三跳才是物理机A,IP为192.168.100.100
通过拓补图看到,物理机A和物理机B之间有隔阂,物理机A根本不可能知道从物理机B之后的下一跳是谁,中间搁着多个路由器情况,让路径无从而知
第一种解决方案,中间的所有的路由都来适配Calicao,可以互相告知路由,比起之前告知物理机的,现在还要告知容器的网段
第二种方式,物理机A和物理机B之间打通一个隧道,在这个隧道上有两个端点,在端点上封装,将容器的IP作为乘客的协议放在隧道里面,而物理主机的IP放在外面作为承载协议,不管外层的IP通过传统的物理网络,走多少跳到达目标物理机,从隧道两端看起来,物理机A的下一跳就是物理机B,这样前面的逻辑才能成立
这就是Calico的IPIP模式,使用了IPIP模式,在物理机A上,可以看到如下的路由表
172.17.8.2 dev veth1 scope link
172.17.8.3 dev veth2 scope link 172.17.9.0/24 via 192.168.200.101 dev tun0 proto bird onlink |
这就和原来的模式区别在于,下一跳就不再是同一个网段的物理机B了,IP为192.168.200.101,并且不是eth0跳,而是建立一个隧道的端点tun0,这样才是下一跳
如果我们在容器A1里面的172.17.8.2,去ping 容器B1里面的172.17.9.2首先会到物理机A,在物理机A上根据上面的规则,转发给tun0,并在对包进行封装
内层的源IP是 172.17.8.2
内层的目标IP是 172.17.9.2
外层的源IP是 192.168.100.100
外层的目标IP是 192.168.200.101
这样,这个包从eth0发出去,在物理机网络上会外用外层的IP来进行路由,最后到达了物理机B,在物理机B上,tun0会解封装,将内层的源IP和目标IP拿出来,转发到了相应的容器
本章重点
Calico推荐使用物理机作为路由器的模式,这种模式没有虚拟化的开销,性能相当的高
Calico内部包含的组件有 iptables的配置组件Felix,路由广播组件BGP Speaker,大规模使用的BGP Route Reflector
为了跨网段,Calico有一种IPIP的模式,也为打通隧道的方式,让两边不是邻居的机器,变成相邻的机器
课后思考:
1.Calico部署在公有云上,经常使用IPIP模式,为何?
2.容器这种部署微服务的,微服务之间的通信,网络要互通,还要高效地传输信息,怎么办呢?
在云中网络的虚拟机,并不是直接通过交换机互通,而是中间有路由,使用VPC实现
微服务交换可以使用RPC
在IPIP模式下,隧道中是点到点的,服务都部署在多个局域网中,每个局域网都有n台机器,为了保证互相跨网互联,是否需要全部点对点打通隧道?
使用路由,汇聚到物理路由器,物理路由器之间打通
另外的原因是,如果VPC网络是平的,但是公有云往往有一个限制,就是容器的IP端是用户自己定义的,如果出了虚拟机,云平台发现不是自己分配的IP,很多情况就直接丢弃了,如果是IPIP,出了虚拟机之后,IP还是虚拟机的IP,没有问题