docker网络方案简介

注:本篇仅仅是对各个网络方案的简介和思考。需要深入学习如何部署和使用的同学请自行度娘~

中小docker用户的苦恼

docker的使用者十分广泛,不止有网易蜂巢,daocloud,时速云这类的已经成熟化的公有云服务,许多中小型企业内部也在试图将docker容器应用到内部的运维工作中。

在成熟的容器服务架构中,往往会依赖IaaS层去实现更好的隔离效果,一个很明显的例子就是网络的连通性和隔离性。许多企业使用neutron作为这方面的支持并且能获得不错的效果。

而中小型企业内部,甚至一些个人用户的docker环境就很少考虑租户隔离了,连通性和性能是这类用户的至高需求。
比如下面这段对话:
“我们部门这套业务是基于dubbo的架构来开发的,现在其中的服务A要放你们容器环境里面跑。”
“可以啊,来来来,我帮你打镜像,我帮你跑,要几个实例?OK没问题。”
“你们容器集群里的服务,我们的dubbo注册中心都访问不到啊!搞什么鬼?”
“不好意思不好意思,我们的容器IP是虚拟的IP,你没法主动访问我们的。不过我们用了k8s,可以把整个服务以一个IP:port的形式提供给注册中心,你看我们还帮你们做了负载均衡。”
“我们不需要你们帮我们做负载均衡,我们就想把容器当虚拟机一样用嘛~”
“这…”

实际上,对于每一个初步接触docker的人来说,网络是绝对的痛点,要搭建一套能让容器跨机器的集群,是玩转容器,建设CaaS的第一步。这里简单介绍一下几种使用较为普遍的容器网络方案,并详细讲述笔者在“远古时期”的网络方案解决思路。

host模式

容器直接使用宿主机的网络配置,包括网卡,路由等,这种方案下,从网络层面来看,容器就不是容器了,只是一个宿主机上的进程(端口)而已。
使用这种模式的性能损耗最少(直接用宿主机的网卡,能有什么损耗)。但是除非在容器中我们做好端口的自动化配置,否则端口被占用了,容器就启动不了。

flannel

flannel已经日趋成熟,从原本的udp,vxlan支持,到后来的aws,host-gw,gce网络。这里主要说udp,vxlan,host-gw。
udp和vxlan在flannel中其实只是封装协议的不同而已。笔者了解不多,不敢多做解释,不过这两种方式的性能其实是差不多的(很多人会觉得vxlan性能更好)。flannel实现的是一个三层网络。但是udp,vxlan协议是通过隧道方式进行跨机互联,简单地说就是:
容器a的数据包pkg->宿主机A的docker0->路由到宿主机A的flannel0网卡->被封装->宿主机A的物理网卡->宿主机B的物理网卡->路由到宿主机B的flannel0网卡->被解封->通过暴露出来的目的容器IP找到docker0->docker0转给容器的虚拟网卡

封装解封的过程导致flannel会有20-30%的损耗。

host-gw是一个比较新鲜的方式,在slaver节点属于同一个二层网络,且可以自由配置slaver节点网络的前提下,我们使用host-gw,会使得slaver节点上创建出一系列路由规则,通过这套路由规则,将容器发出的数据包转发给相应的机器。这种模式性能会更好
flannel的主要缺点在于,既没有租户隔离(即:一套环境里,每一个容器都可以访问到其他任何容器),也没有对外开放(集群外没有搭建flannel的机器ping不通容器)。

calico

calico是一种容器级路由和防火墙工具,它能够在容器级别上为每个容器实例或k8s的Pod实例指定访问规则,达到服务间可控的访问。
Calico的原理是通过修改每个主机节点上的iptables和路由表规则,实现容器间数据路由和访问控制,并通过Etcd协调节点配置信息的。因此Calico服务本身和许多分布式服务一样,需要运行在集群的每一个节点上。
calico已经并入了k8s的CNI插件。在每一个slaver节点上启动一个calico容器,去劫持docker的创建命令,接管容器网络的配置。
calico吸引人的地方在于:他有一套自己的管理体系,给不同的子网络增加了标签,可以通过这种方式实现容器网络的隔离;同时业内认为他的性能也是很好的,基本接近裸机的网络性能,然而笔者在自己的环境中测试了几次,效果并不尽如人意,。

桥接+IPAM

接下来说下桥接+IPAM模式。这个方案针对的是一种比较特殊的使用场景:

docker有许多用法,微服务是其中一种,通过docker技术圈内爱好者的交流,我们了解到确实有一些企业试图,或者已经将容器当做虚拟机在用。上文中的对话就是这个使用场景之一,这种场景下的网络问题总结为:同一个网络环境中的机器里,非docker机器主动连接docker机器上的容器是连不通的

解决方法:
1.给这个网络环境中非docker的机器也部署虚拟网络,将flannel,calico这类组件在全网络范围内做分布式的部署。(考虑到机器数量,可能存在的VM,VM会有起停操作,这个方案基本不可行)
2.给容器一个和宿主机器同一层网络的IP,即二层网络IP,路由到宿主机的物理网卡,进行转发。

我们知道docker1.9以后增加了network特性,docker daemon可以自己创建一个network,通过选择network给容器配置网络。
在二层网络的基础上,我们在宿主机建立一个网桥,桥接了物理网卡和docker network(当然了type必须是bridge)。设置好路由规则和gateway,docker容器创建时桥接到相应的network上,就可以正常地访问二层网络内的任何机器/容器。
同样的,因为这种方式下容器创建后IP是一个二层网络内的IP,所以外部机器可以很方便地访问容器。这是一种全暴露的网络模式。做到了完全的连通,但没办法做到网络的隔离。

那IPAM又是什么鬼?

假设这种情况:桥接模式下,容器和宿主机是同一个网段,比如172.16.1.0/24,假设该网段中的.1~.10都是宿主机,我们在.1的宿主机上创建的容器,其IP必定是172.16.1.2,172.16.1.3,…会发现容器的IP和宿主机重复了。这就麻烦了,要么我们就连不上容器,要么我们就连不上IP为172.16.1.2的宿主机。(简单地说下原因:每个宿主机彼此并不知悉对方的IP和MAC信息,我们创建的那个网桥也没有这方面的记录,容器启动时,网桥上已经记录了本机的IP:172.16.1.1,但没有记录172.16.1.2,所以就会给容器分配172.16.1.2这个IP)

那就开发一个服务用于管理IP吧,docker原生支持network plugin,其中一个插件就是IPAM,即ip分配管理服务。docker network创建/销毁容器时会使用IPAM去申请/释放一个合法的IP。如果没有指定IPAM插件,docker daemon会自动配置的网段中选一个IP,其逻辑是按数字从小到大进行分配。

我们开发一个IPAM,通过IPAM来进行IP的申请和释放,并在整个集群中建立一个IP的管理中心,维护整个容器集群的IP资源。保证一个IP只能同时被最多一个容器使用。

这种方案的性能看起来应该是和flannel host-gw,calico差不多的,因为其本质还是路由转发,不同之处是给容器分配了二层网络IP,所有容器都暴露了,因此这种模式下网络就难以做租户隔离(容器更像一个瘦VM了~),而这种情况下,dubbo的服务可以直接在容器上部署,k8s的service特性,kube-proxy组件基本可以酌情弃用。

总结

综上所述:

  1. host 损耗小 灵活度低,IP资源不足 没有隔离
  2. flannel udp/vxlan 损耗较大 灵活,IP资源充足 有内外网隔离,没有租户隔离
  3. flannel host-gw 损耗较小 灵活,ip资源充足 有内外网隔离,没有租户隔离
  4. calico 损耗较小 灵活,ip资源充足 有内外网隔离,有租户隔离
  5. 桥接+ipam 损耗很小 开发成本大,二层网络IP资源有限 无任何隔离

    展望:calico可能会是最适合容器云的网络方案,因为租户的网络隔离是生产化过程中绝对不可缺少的。如果仅在内部小规模使用,追求简单配置,可以使用flannel,如果将容器vm化,可以考虑使用桥接+ipam。

    原文作者:fzu_huang
    原文地址: https://segmentfault.com/a/1190000006594822
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞