Calico网络模型
由于两台物理机的容器网段不同,我们完全可以将两台物理机配置成为路由器,并按照容器的网段配置路由表。
在物理机A中,我们可以这样配置:要想访问网段172.17.9.0/24,下一跳是192.168.100.101,也即到物理机B上去。
这样在容器A中访问容器B,当包到达物理机A的时候,就能够匹配到这条路由规则,并将包发给下一跳的路由器,也即发给物理机B。在物理机B上也有路由规则,要访问172.17.9.0/24,从docker0的网卡进去即可。
当容器B返回结果的时候,在物理机B上,可以做类似的配置:要想访问网段172.17.8.0/24,下一跳是192.168.100.100,也即到物理机A上去。
Calico网络的大概思路,即不走Overlay网络,不引入另外的网络性能损耗,而是将转发全部用三层网络的路由转发来实现
如果全部走三层的路由规则,没必要每台机器都用一个docker0,从而浪费了一个IP地址,而是可以直接用路由转发到veth pair在物理机这一端的网卡。同样,在容器内,路由规则也可以这样设定:把容器外面的veth pair网卡算作默认网关,下一跳就是外面的物理机。
于是,整个拓扑结构就变成了这个图中的样子。
Calico网络的转发细节
容器A1的IP地址为172.17.8.2/32,不是/24,而是/32,将容器A1作为一个单点的局域网了, 容器A1里面的默认路由,Calico配置得比较有技巧
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地址不会在任何网络包头里面出现,也就是说,没有人在乎这个地址具体是什么,只要能找到对应的MAC,响应ARP就可以了
ARP本地有缓存,通过ip neigh命令可以查看。
169.254.1.1 dev eth0 lladdr ee:ee:ee:ee:ee:ee STALE
这个MAC地址是Calico硬塞进去的,但是没有关系,它能响应ARP,于是发出的包的目标MAC就是这个MAC地址。
在物理机A上查看所有网卡的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
简易架构图:
物理机化身为路由器,通过路由器上的路由规则,将包转发到目的地。在这个过程中,没有隧道封装解封装,仅仅是单纯的路由转发,性能会好很多。但是,这种模式也有很多问题。
路由配置组件Felix
如果只有两台机器,每台机器只有两个容器,而且保持不变。我手动配置一下,倒也没啥问题。但是如果容器不断地创建、删除,节点不断地加入、退出,情况就会变得非常复杂。
有三台物理机,两两之间都需要配置路由,每台物理机上对外的路由就有两条。如果有六台物理机,则每台物理机上对外的路由就有五条。新加入一个节点,需要通知每一台物理机添加一条路由。
这还是在物理机之间,一台物理机上,每创建一个容器,也需要多配置一条指向这个容器的路由。如此复杂,肯定不能手动配置,需要每台物理机上有一个agent,当创建和删除容器的时候,自动做这件事情。这个agent在Calico中称为Felix。
路由广播组件BGP Speaker
在Calico中,每个Node上运行一个软件BIRD,作为BGP的客户端,或者叫作BGP Speaker,将“如何到达我这个Node,访问我这个Node上的容器”的路由信息广播出去。所有Node上的BGPSpeaker 都互相建立连接,就形成了全互连的情况,这样每当路由有所变化的时候,所有节点就都能够收到了。
安全策略组件
Calico中还实现了灵活配置网络策略Network Policy,可以灵活配置两个容器通或者不通。
虚拟机中的安全组,是用iptables实现的。Calico中也是用iptables实现的。这个图里的内容是iptables在内核处理网络包的过程中可以嵌入的处理点。Calico也是在这些点上设置相应的规则。
当网络包进入物理机上的时候,进入PREOUTING规则,这里面有一个规则是cali-fip-dnat,这是实现浮动IP(Floating IP)的场景,主要将外网的IP地址dnat为容器内的IP地址。在虚拟机场景下,路由器的网络namespace里面有一个外网网卡上,也设置过这样一个DNAT规则。接下来可以根据路由判断,是到本地的,还是要转发出去的。
如果是本地的,走INPUT规则,里面有个规则是cali-wl-to-host,wl的意思是workload,也即容器,也即这是用来判断从容器发到物理机的网络包是否符合规则的。这里面内嵌一个规califrom-wl-dispatch,也是匹配从容器来的包。如果有两个容器,则会有两个容器网卡,这里面内嵌有详细的规则“cali-fw-cali网卡1”和“cali-fw-cali网卡2”,fw就是from workload,也就是匹配从容器1来的网络包和从容器2来的网络包。
如果是转发出去的,走FORWARD规则,里面有个规则cali-FORWARD。这里面分两种情况,一种是从容器里面发出来,转发到外面的;另一种是从外面发进来,转发到容器里面的。
第一种情况匹配的规则仍然是cali-from-wl-dispatch,也即from workload。第二种情况匹配的规则是cali-to-wl-dispatch,也即to workload。如果有两个容器,则会有两个容器网卡,在这里面内嵌有详细的规则“cali-tw-cali网卡1”和“cali-tw-cali网卡2”,tw就是to workload,也就是匹配发往容器1的网络包和发送到容器2的网络包。
接下来是匹配OUTPUT规则,里面有cali-OUTPUT。接下来是POSTROUTING规则,里面有一个规则是cali-fip-snat,也即发出去的时候,将容器网络IP转换为浮动IP地址。在虚拟机场景下,路由器的网络namespace里面有一个外网网卡上,也设置过这样一个SNAT规则。
Calico全景架构图:
全连接复杂性与规模问题
这里面还存在问题,就是BGP全连接的复杂性问题。
例子里只有六个节点,BGP的互连已经如此复杂,如果节点数据再多,这种全互连的模式肯定不行,到时候都成蜘蛛网了。于是多出了一个组件BGP Route Reflector,它也是用BIRD
实现的。有了它,BGP Speaker就不用全互连了,而是都直连它,它负责将全网的路由信息广播出去。
大规模部署架构图:
一个机架就像一个数据中心,可以把它设置为一个AS,而BGP Router Reflector有点儿像数据中心的边界路由器。在一个AS内部,也即服务器和BGP RouterReflector之间使用的是数据中心内部的路由协议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。之所以能够这样,是因为物理机A和物理机B是同一个网段的,是连接在同一个交换机上的。那如果物理机A和物理机B不是在同一个网段呢?
简化架构:
物理机A的网段是192.168.100.100/24,物理机B的网段是192.168.200.101/24,这样两台机器就不能通过二层交换机连接起来了,需要在中间放一台路由器,做一次路由转发,才能跨网段访问。
本来物理机A要告诉物理机B,你要访问172.17.8.0/24,下一跳是我192.168.100.100的,但是中间多了一台路由器,下一跳不是我了,而是中间的这台路由器了,这台路由器的再下一跳,才是我。这样之前的逻辑就不成立了
物理机B上的容器要访问物理机A上的容器,第一跳就是物理机B,IP为192.168.200.101,第二跳是中间的物理路由器右面的网口,IP为192.168.200.1,第三跳才是物理机A,IP为192.168.100.100。
解决方式是在物理机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网络模型的更多相关文章
- vxlan 简单理解 vs calico 网络模型
1.vxlan(virtual Extensible LAN)虚拟可扩展局域网,是一种overlay的网络技术,使用MAC in UDP的方法进 行封装,共50字节的封装报文头. 2.VTEP为虚拟机 ...
- k8s网络之Calico网络
k8s网络主题系列: 一.k8s网络之设计与实现 二.k8s网络之Flannel网络 三.k8s网络之Calico网络 简介 Calico 是一种容器之间互通的网络方案.在虚拟化平台中,比如 Open ...
- Calico网络方案
参考文档: Difficulties with traditional overlay networks:https://www.projectcalico.org/learn/ Get Start( ...
- Calico 网络通信原理揭秘
Calico 是一个纯三层的数据中心网络方案,而且无缝集成像 OpenStack 这种 Iaas 云架构,能够提供可控的 VM.容器.裸机之间的 IP 通信.为什么说它是纯三层呢?因为所有的数据包都是 ...
- 第 8 章 容器网络 - 072 - 一文搞懂各种 Docker 网络
Docker 起初只提供了简单的 single-host 网络,显然这不利于 Docker 构建容器集群并通过 scale-out 方式横向扩展到多个主机上. 跨主机网络方案: Docker Over ...
- 【Network】Calico, Flannel, Weave and Docker Overlay Network 各种网络模型之间的区别
From the previous posts, I have analysed 4 different Docker multi-host network solutions - Calico, F ...
- calico docker 应用实例
在上一篇文章<quay.io/coreos/etcd 基于Docker镜像的集群搭建>中,介绍了ETCD集群的搭建.在此基础上,我们进一步实践calico docker的应用. PaaS ...
- Docker网络解决方案 - Calico部署记录
简单来说,实现docker跨主机容器间通信,常用的第三方网络方案是Flannel,Weave,Calico:Flannel会为每个host分配一个subnet,容器从这个subnet中分配ip,这些i ...
- 容器网络——从CNI到Calico
从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道.我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理.虚拟环境对网络环境需求是有差别的,主要面临以下两个问题: 过去Iaa ...
随机推荐
- 使用 Python 和 Flask 设计 RESTful API
近些年来 REST (REpresentational State Transfer) 已经变成了 web services 和 web APIs 的标配. 在本文中我将向你展示如何简单地使用 Pyt ...
- ImportError: cannot import name 'BaseDataset' from 'src.dataset'
因为我进行了相互调用,我在父类中调用了子类. from src.dataset import BaseDataset class PSINSDataset(BaseDataset): from src ...
- Fluent设置充分发展湍流入口(利用profile)
计算模型: 物性参数为: 密度:100kg/m3 粘度系数:0.003333kg/(m·s) 原视频下载地址: https://pan.baidu.com/s/1W3n_K-dZCVMF7M63wV2 ...
- 如何去掉word中英文单词下的红色波浪线
文件 ->选项 ->校对 在 只隐藏此文档中的拼写错误(S) 选项前打钩,点击确定即可
- [技术博客] Android 自动化测试
[技术博客] Android 自动化测试 安卓自动化测试工具与平台的搭建 类似于网页端自动化,安卓测试的自动化也主要是针对控件的自动化.其原理就是通过python(其他语言) 的脚本来代替我们手动完成 ...
- Android Sensor 架构深入剖析【转】
本文转载自: 1.Android sensor架构 Android4.0系统内置对传感器的支持达13种,它们分别是:加速度传感器 (accelerometer).磁力传感器(magnetic fiel ...
- Struts2工作原理和核心文件
一.Struts2工作原理 如下图: 二.Struts2配置文件 1.web.xml 任何MVC框架都需要与Web应用整合,这就不得不借助于web.xml文件,只有配置了web.xml文件的Servl ...
- Git Bash 克隆project
cd 到想要的路径,然后执行下面的命令
- tp使用ajaxReturn返回二维数组格式的字符串,前台如何获取非乱码
参考: https://www.cnblogs.com/jiqing9006/p/5000849.html https://blog.csdn.net/zengxiangxuan123456/arti ...
- docker build提示error checking context:can't stat xxx
现象描述 使用docker build一个镜像的时候,提示下面的错误: ➜ docker build -t image_name -f xxx.dockerfile . error checking ...