跟唐老师学习云网络 - CloudFoundry网络实现

举报
tsjsdbd 发表于 2020/04/24 16:13:06 2020/04/24
【摘要】 在K8s独霸天下之前,CloudFoundry才是那时的PaaS平台一哥呢。虽然你之前可能没了解过CloudFoundry是什么,不过今天,我们可以来回顾一下当年老PaaS是如何实现容器集群中网络分发的,也许还能顺道看下这家伙是如何被后浪拍死在沙滩上的。

K8s独霸天下之前,CloudFoundry才是那时的PaaS平台一哥呢。虽然你之前可能没了解过CloudFoundry是什么,不过今天,我们可以来回顾一下当年老PaaS是如何实现容器集群中网络分发的,也许还能顺道看下这家伙是如何被后浪拍死在沙滩上的。

 

1      简单介绍下CloudFoundry

image.png

Docker解决了单机上面的容器管理,当在大规模集群上面管理容器集群时,则需要依赖PaaS平台。CloudFoundry就是业界首个开源的PaaS平台,那在当年(大概2013~2015)可是叱咤风云,一时风光无限。

后来的故事大家基本也看到了,几个比较有名的PaaS平台起来,然后就是K8s一家独大,然后就没有然后了。(可参考唐老师的《K8S前世今生》文章)

image.png

这里提一下,当年的CF用的容器技术,还不是Docker,而是自创的一个叫做Warden的容器技术(原理和Docker差不多,但是没有镜像管理这个功能,所以后面被Docker碾压了)。后来Docker实在太火,CF把底层的容器换成了Docker,不过也来不及了。

 

2      集群中容器网络怎么打通

要访问容器,有2种场景: 1)容器间互相访问。(2PaaS平台外部访问容器。

CF基本没怎么考虑第(1)种场景,只是对第(2)种场景做了较好的处理。所以我们详细介绍下第(2)种场景:PaaS外部怎么访问容器。

 

为了从外部可以访问容器,CF新增了一个叫做GoRouter的组件,你就理解成一个自己实现的定制版Nginx

image.png

PaaS集群外部,访问集群里面的容器,都需要一个这样的LB的。定制也好,取第三方也罢。 比如作为后来者,K8s为了偷懒,实现弯道超车CF,直接只做控制逻辑(还取个好听的名字叫Ingress),具体转发动作交给Nginx这种第三方工具去实现了。

 

回到CF,那我们就详细看下报文是怎么经过GoRouter,到达容器的。

 image.png

(1)       首先,GoRouter 容器所在的节点(DEA),是局域网的VM,互相连通。

(2)       GoRouter记录URL和容器endpoint的映射关系。

(3)       收到请求,将报文转给对应的容器Host节点。这个和K8s是一样的。

 

2.1      Host节点的容器网络

Warden容器出现的比Docker容器早,所以网络模型,也更简单。具体来讲,就是没Bridge网桥,报文直接靠Host路由导入容器。

l  DEA上运行ifconfig看到的结果:

image.png

w-开头的 就是 Veth-pair 网线,没有Bridge网桥。

l  在容器内运行ifconfig看到的结果:

image.png

可以看到,warden容器内只有一个接口,就是Veth的另一头。在warden容器中运行的app也只能看到这一个接口。

所以CF为每个容器,创建了一根Veth网线,一头在Host主机(DEA)中,一头在Warden容器中,如下图:

image.png

l  DEA如何把app请求交给Warden容器内

前面提到GoRouter转发过来的请求,目的IP都是DEA的,那么DEA是怎么区分请求是给哪个warden容器的呢? 答案是端口映射(目的IP都一样,不是还有端口不同么)。是的,DEA通过端口来区分不同的warden容器,从而交给不同的app

DEA做的端口转warden容器IP工作是交给Hostiptables规则来完成的(跟Docker一样):

image.png

所以,之前提到的路由组件(GoRouter)不关心容器(Warden)里面的实际IP,只记录容器所在主机(DEA)的IP就够了。Warden容器之间网络彼此隔离,所以这个Warden容器内部的IP其实并不重要,随机都可以,只要保证所有虚拟Veth网线的IP不重复就能区分不同的Warden容器。

2.2      容器内部网络

从容器角度来看,它自己肯定认为自己是完整的世界,所以我们只需要把容器当作普通的主机就行。(容器还是为了模拟出一个“真实”的运行环境)。

image.png    

对于warden容器内部来说,与外界通信的唯一途径就那根Veth网线,网线的对端就是它的网关(即容器所在的主机),再外部的网络它就一点都不知道了。在这个虚拟世界中(warden容器中)运行的app所看到的网络也是这么的简单:我的世界只有一个网卡,路由也只有一条:

image.png

 

2.3      报文从客户端到达容器

这一章节,是上述章节的细化版,有兴趣的看看就行了。

2.3.1        客户端到CFGoRouter

image.png

 

1. 首先客户端知道appURL网址。so会先去查询DNSDNS返回的IPGoRouter的外部IP(即EIP啦)。

2. 接着客户端访问刚查到的GoRouter的外部EIP(实际就是Openstack的网络节点,IaaS报文都是通过网络节点,转给内部的VM的。)。

3. Openstack网络节点将外部IP通过NAT转换成内部的IP,交给对应的VM。这里也就是GoRouter所在的节点了。

Ps:因为NAT对客户端用户来说是不感知的,客户端会认为用EIP就是接与GoRouter通信了。

 

2.3.2        RouterDEAApp所在的VM

image.png

4. 路由组件GoRouter执行L7层终结模式。即先和客户端正常TCP建链,这时还不跟任何后端容器连接通信。等到客户端发起GET的时候,会根据客户端请求的URL,找到“url-app”的关联映射记录,找出是访问哪个app,然后才向目标app发起syn建链。注意这里向容器中的app发起请求时的目的端口已经换了,不再是http默认端口80

5. url-app”记录中app的地址是容器所在的节点(即:目的IPDEA)。所以GoRouter把报文丢给DEA,其实也是一个VM

 

2.3.3        DEA收到的报文

image.png

6. 可以看到GoRouter发其建链报文到达容器所在的Host节点。

2.3.4        DEA转发进入容器(App所在的运行环境)

image.png

dea执行nat,把报文转入到容器里面。

7.  DEA根据报文的目的端口,注意是端口,执行NAT动作,将目的IP改成内部容器的IP,交给APP

 

2.3.5        最终App看的请求

image.png

app看到的抓包

8 还是一样,NAT行为对客户端来说是不感知的,于是GoRouter路由组件以为自己直接跟容器App通信了。它继续开心的认为“url-app”的映射关系是正确的:

image.png

2.3.6        整体图

image.png

3      总结

CF的容器网络实现,和K8s主要3个地方稍有区别。

(1)       K8sService概念搞定容器间如何互访问题,CF未考虑容器如何互访。

(2)       外部路由转发的实现,K8s借助第三方组件,CF自己上阵

(3)       容器所在Host组网,DockerBridgeCF不带Bridge

 

第一点:K8s精明的地方,也是一把直接站在了CF的肩膀上。

第二点:App网络主要考虑了集群外部,如何访问容器,即K8s中的Ingress部分。跟K8s-Ingress中只定义“URL->容器”映射规则,转发则交给Nginx不一样的是。CF搞了个GoRouter路由组件,除了定义映射关系,自己上手做了转发动作。

第三点:容器有没有接入Bridge网桥,其实没太大区别,这个本身还是DockerWarden的差异。DockerWarden更通用一些,场景考虑的更周到,所以和K8s时代盖住了CF一样,Warden这种容器,也被Docker盖的死死的。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。