当前位置: 首页 > 科技观察

容器网络方案Bridge-Vlan模式的演进

时间:2023-03-14 19:12:37 科技观察

容器网络背景如果你只在一台机器上使用Docker,也许你根本不需要关心网络配置,因为DockerDaemon默认的模式是比较友好,它会直接帮你生成一个Bridge名称Bridge0,这样你就可以通过端口映射方式或者host方式让容器与外界进行通信,而不需要使用任何网络工具(brctl,iptables)手动创建。但是如果容器放在集群环境下(比如使用Mesos或者K8S编排工具),这个网络问题就比较蛋疼了。因为要保证如何在不增加过多额外性能开销的情况下将容器暴露给外部访问,网络方案相对可控和稳定,成为基于容器的PaaS平台成功的关键因素。我们的需求:独立IP除了需要考虑的网络性能和网络稳定性问题外,我们内部还有一个很重要的需求,就是要保证每个容器都获得独立的IP,并且每个容器之间可以互相访问。因为我们有自己的基于RPC的服务体系,所以需要一个扁平化的通信网络,相关的系统比如APM系统都依赖这个独立的IP进行解析。网络方案选择第一次做容器化架构(半年前),选择网络方案的要点是简单成熟的方案。网络选择主要有两个方向。一种是物理机方案,即通过交换机的方案,如VLAN方式、VxLan方式等;另一种是软件方案SDN,如Overlay网络。因为这是我们第一个容器方案,为了保险起见,我们更信任物理设备的方式,所以我们选择了VLAN方式作为首选,而VxLan对物理设备有要求,所以暂时放弃。但是,如果有硬件基础,可以有限考虑VxLan方式。最新版本的VLAN组网方案,一开始没有找到适合的VLAN使用方式的资料,都是自己摸索出来的。后来新版docker支持dockernetwork命令后,这些就简单多了。而且我们不需要使用dockercreatenetwork。主要解决方案如下:最新版“vlan模式”的缺陷从最新版的解决方案来看,虽然简单,也比较稳定,但我们已经在生产环境中运行了4个多月没有出现任何问题。但是从管理和监控的角度来看,这个方案还是有明显的缺陷,但是这个缺陷在容器规模没有达到一定数量的情况下是可以容忍的。但是对于这些缺陷,我们需要在下一个版本的平台上工作时找到合适的解决方案。这些缺陷主要是:一台主机上使用的IP数量是固定的,因为我们已经把IP段分配给了dockerdaemon,所以有风险,如果有剩余的机器资源,mesos+marathon会在主机上启动容器,但是此时可能没有ip,所以marathon会不停的启动容器,销毁容器。当容器数量较多时,在二级扁平化网络的容器部署中,每个容器新建时都会广播ARP包,这样整个网络的风暴比较大。当然这个在容器数量还没有增加的情况下可以暂时忽略。尤其是动态伸缩容器的场景比较小的时候,这个问题不大。不过和京东的永城大师聊过之后,有一个绕过这个问题的workaround方法,后面会讲到。主要问题出在核心交换机的mac-ip表的容量上,因为容器打破了原有的物理机系统,让核心交换机处理容器的mac-ip关系,传统交换机不适合.但是,我对网络设备只了解一二,所以这个问题也只是听说而已。如果有什么不对的地方,请指出。第二版VLAN网络方案第二版网络要求在保证容器可以拥有独立IP的同时,不再限制单个主机的IP数量,支持以小资源部署更多业务应用要求。可以限制单个容器使用网卡,避免突然过度使用一个容器的网络,影响同一主机上其他容器的使用。减轻容器动态扩展引起的网络ARP风暴的影响。动态IP管理解决方案。容器要有独立的IP,要让每个主机的IP动态管理,就需要把IP分配放在dockerdaemon/中,通过插件集成mesos+marathon的外部管理。目前可选的方式是dockerdaemon的IPAM接口,或者mesosslave的IPAM接口。虽然两者都称为IPAM,但它们基于不同的机制。Docker的IPAM(IPaddressmanagement)是Dockerdaemon的CNM(ContainerNetworkModel)机制下的IP管理驱动。CNM的设计模型请参考CNMDesign。DockerIPAM可以参考DockerIPAM,对于Mesos来说,它遵循CNI规范。CNI规范可参考CNISpec。但是,如果您只需要动态管理IP地址,那么任何基于IPAM的接口都可以。于是我们经老肖(@熟人云)介绍,参考了TalkingData的Shrike做动态IP管理。Shrike是基于Dockerdeamon的IPAM解决方案,因此只能用于基于Docker容器的解决方案。如果使用mesos统一容器,则需要将其转化为连接CNI的IPAM接口。Shrike虽然比较简单,但是目前Shrike存在一些局限性,所以我们需要对其进行一些改造以支持后续的扩展。主要包括:如果Shrike进程意外退出,未处理IP释放报文(Releaseaddress),则IP会被***占用。目前我们的想法是在shrike启动的时候主动扫描本地的docker容器,然后和etcd上的数据进行对比。如果有IP还没有释放,它会主动清理。针对以上约束,我们需要修改Etcd中的数据结构,支持将主机IP存储在etcd中,以供后续主动清理。同时,etcd数据结构的改造也用于限流。网络限流方案对于网络限流,最初的想法是使用mesos+marathon方案的自定义资源管理方式,但是由于marathon已经很久不支持自定义资源调度了,所以暂时搁置了这种方式。之所以想这样管理,是想把网卡变成类似cpu/mem的资源,一视同仁。只要分配给容器的带宽超过一定数量,主机就不会再启动容器。Mesos的自定义资源参考mesosattrresource这里还是要吐槽一下Marathon,开发进度和Mesos太不一致了,希望Mesosphere的同学好好推一下。这条路暂时不通,所以在使用Shrike动态分配IP的时候,请问是否可以在动态分配IP的同时限制这个容器的带宽?于是就有了下面的解决方案“shrike”主要流程如下:给Shrike添加一个Throttling模块,Shrike动态分配一个IP,并向Throttlilng模块发送消息,包括容器ip信息(可惜没有容器编号)。Throttling模块收到消息后,调用dockerdaemon接口查询ip主机上对应容器的网络名称(这里可以使用unixsocket接口或者http接口,因为是机器调用的)查询本容器的net_in、net_out等环境变量的值(这个目前是在启动容器的时候配置的)通过调用linux下的wondershape工具来限制容器的带宽。后续还有几个问题没有处理:Shrike怎么发布,目前的思路是在安装物理机的时候一起安装(rpm形式,由systemd维护)或许你可以尝试发布它在一个容器中,但我不知道它是否可行。我们还在考虑提供一个如图所示的Console管理控制台,实时显示容器的网络配置和使用情况。因为net_id和net_out会写入Etcd,这两个值可以直接在界面上调整,然后Throttling的modulewatchchanges直接执行wondershape改变容器。减少ARP广播包的解决方案ARP广播的目的是确定IP所在主机的MAC地址,用于二层网络的寻址。但是在创建容器的时候,MAC地址通常是通过一定的规则生成的,所以每次启动一个容器的时候,都会广播MAC地址和它的IP的对应关系。但是,如果MAC-IP对应关系已经建立且保持不变,则不需要再次广播ARP。这是一句俗话。详情请参考RFC826规范。既然如此,那我们能不能想办法控制ARP包的数量呢?是的,IP-MAC的关系是预先设定好的,即只要IP相同,其MAC地址也相同。因此,对于容器方案,可以预先初始化规划容量的所有IP和MAC的对应关系。然后各个容器在启动时主动拉取这张表,通过arp命令设置到容器中。(这里有一个细节没有测试过,就是如果有几万个容器,arp命令执行这个表需要多长时间,是否影响容器启动时间?)这样,容器启动后,会有所有容器的IP-MAC对应关系。不需要发送太多的ARP包。不过这里还有一个问题,就是不能使用IPAM接口,因为IPAM接口没有提供指定对应容器MAC的手段。(看CNI的源码历史,MAC设置本来可以在IPAM里面设置的,后来移到了外层)所以如果需要在容器启动后直接更新一个大的固定IP-MAC列表,只能通过CNM/CNI的接口方式设置IP和MAC地址,核心交换机MAC地址的承载能力解决只能由硬件厂商解决。据称,京东的下一代方案是直接定制核心交换机,支持容器方案。具体情况不太清楚。如果有更好的方案,记得告诉我总结到此为止,基本涵盖了我们第二版网络改进方案的大致思路。也许你会问,为什么不考虑使用几种流行的三层网络方案呢?其实道理很简单,只是还没有完全掌握,尤其是定位到了问题,如何调试就比较困难了。但是依靠硬件交换机和Linux的特性,这个还是比较有把握的。因此,建议如果您对技术没有足够的把握,不要轻易尝试SDN方案,除非您购买专业的技术服务。【本文为专栏作者“VIPDOCKER-Leoge”原创文章,如需转载请通过联系作者】点击此处查看该作者更多好文