最新实践 | 将Docker网络方案进行到底

本文是数人云研发工程师向阳在DockOne微信群分享的直播实录,与大家一起探究Docker的网络方案。

随着容器的火热发展,数人云越来越多的客户对容器网络特性要求也开始越来越高,比如:

  • 一容器一IP;
  • 多主机容器互联;
  • 网络隔离;
  • ACL;
  • 对接SDN等等。

这次主要跟大家聊聊Docker的网络方案,首先是现有容器网络方案介绍, 接下来重点讲解Calico的特性及技术点,作为引申和对比再介绍下Contiv的特性,最后给出对比测试结果。

现有的主要Docker网络方案

首先简单介绍下现有的容器网络方案,网上也看了好多对比,大家之前都是基于实现方式来分,以下两个方案引自作者彭哲夫在DockOne的分享

隧道方案

通过隧道,或者说Overlay Networking的方式:

  • Weave,UDP广播,本机建立新的BR,通过PCAP互通。
  • Open vSwitch(OVS),基于VxLAN和GRE协议,但是性能方面损失比较严重。
  • Flannel,UDP广播,VxLan。

隧道方案在IaaS层的网络中应用也比较多,大家共识是随着节点规模的增长复杂度会提升,而且出了网络问题跟踪起来比较麻烦,大规模集群情况下这是需要考虑的一个点。

路由方案

还有另外一类方式是通过路由来实现,比较典型的代表有:

  • Calico,基于BGP协议的路由方案,支持很细致的ACL控制,对混合云亲和度比较高。
  • Macvlan,从逻辑和Kernel层来看隔离性和性能最优的方案,基于二层隔离,所以需要二层路由器支持,大多数云服务商不支持,所以混合云上比较难以实现。

路由方案一般是从3层或者2层实现隔离和跨主机容器互通的,出了问题也很容易排查。

我觉得Docker 1.9以后再讨论容器网络方案,不仅要看实现方式,而且还要看网络模型的“站队”,比如说你到底是要用Docker原生的 “CNM”,还是CoreOS,谷歌主推的“CNI”。

Docker Libnetwork Container Network Model(CNM)阵营

  • Docker Swarm overlay
  • Macvlan & IP network drivers
  • Calico
  • Contiv(from Cisco)

Docker Libnetwork的优势就是原生,而且和Docker容器生命周期结合紧密;缺点也可以理解为是原生,被Docker“绑架”。

Container Network Interface(CNI)阵营

  • Kubernetes
  • Weave
  • Macvlan
  • Flannel
  • Calico
  • Contiv
  • Mesos CNI

CNI的优势是兼容其他容器技术(e.g. rkt)及上层编排系统(Kuberneres & Mesos),而且社区活跃势头迅猛,Kubernetes加上CoreOS主推;缺点是非Docker原生。

而且从上的也可以看出,有一些第三方的网络方案是“脚踏两只船”的, 我个人认为目前这个状态下也是合情理的事儿,但是长期来看是存在风险的,或者被淘汰,或者被收购。

Calico

接下来重点介绍Calico,原因是它在CNM和CNI两大阵营都扮演着比较重要的角色。即有着不俗的性能表现,提供了很好的隔离性,而且还有不错的ACL控制能力。

Calico是一个纯3层的数据中心网络方案,而且无缝集成像OpenStack这种IaaS云架构,能够提供可控的VM、容器、裸机之间的IP通信。

通过将整个互联网的可扩展IP网络原则压缩到数据中心级别,Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息像整个Calico网络内传播——小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。

这样保证最终所有的workload之间的数据流量都是通过IP路由的方式完成互联的。

Calico节点组网可以直接利用数据中心的网络结构(无论是L2或者L3),不需要额外的NAT,隧道或者Overlay Network。

如上图所示,这样保证这个方案的简单可控,而且没有封包解包,节约CPU计算资源的同时,提高了整个网络的性能。

此外,Calico基于iptables还提供了丰富而灵活的网络Policy,保证通过各个节点上的ACLs来提供Workload的多租户隔离、安全组以及其他可达性限制等功能。

Calico架构

结合上面这张图,我们来过一遍Calico的核心组件:

  • Felix,Calico Agent,跑在每台需要运行Workload的节点上,主要负责配置路由及ACLs等信息来确保Endpoint的连通状态;
  • etcd,分布式键值存储,主要负责网络元数据一致性,确保Calico网络状态的准确性;
  • BGP Client(BIRD), 主要负责把Felix写入Kernel的路由信息分发到当前Calico网络,确保Workload间的通信的有效性;
  • BGP Route Reflector(BIRD),大规模部署时使用,摒弃所有节点互联的 mesh 模式,通过一个或者多个BGP Route Reflector来完成集中式的路由分发。

Calico Docker Network 核心概念

从这里开始我们将“站队” CNM,通过Calico Docker libnetwork plugin的方式来体验和讨论Calico容器网络方案。

先来看一下CNM模型:

从上图可以知道,CNM基于3个主要概念:

  • Sandbox,包含容器网络栈的配置,包括Interface,路由表及DNS配置,对应的实现如:Linux Network Namespace;一个Sandbox可以包含多个Network;
  • Endpoint,做为Sandbox接入Network的介质,对应的实现如:veth pair、TAP;一个Endpoint只能属于一个Network,也只能属于一个Sandbox;
  • Network,一组可以相互通信的Endpoints;对应的实现如:Linux bridge、VLAN;Network有大量Endpoint资源组成。

除此之外,CNM还需要依赖另外两个关键的对象来完成Docker的网络管理功能,他们分别是:

  • NetworkController,对外提供分配及管理网络的APIs,Docker Libnetwork支持多个活动的网络driver,NetworkController允许绑定特定的driver到指定的网络;
  • Driver,网络驱动对用户而言是不直接交互的,它通过插件式的接入来提供最终网络功能的实现;Driver(包括IPAM)负责一个Network的管理,包括资源分配和回收。

有了这些关键的概念和对象,配合Docker的生命周期,通过APIs就能完成管理容器网络的功能,具体的步骤和实现细节这里不展开讨论了, 有兴趣的可以移步 Github:https://github.com/docker/libnetwork/blob/master/docs/design.md。

接下来再介绍两个Calico的概念:

  • Pool,定义可用于Docker Network的IP资源范围,比如:10.0.0.0/8或者192.168.0.0/16;
  • Profile,定义Docker Network Policy的集合,由tags和rules组成;每个 Profile默认拥有一个和Profile名字相同的Tag,每个Profile可以有多个Tag,以List形式保存。 Profile样例:

Inbound rules: 1 allow from tag WEB
2 allow tcp to ports 80,443
Outbound rules:
1 allow
Demo

基于上面的架构及核心概念,我们通过一个简单的例子,直观的感受下Calico的网络管理。

Calico以测试为目的集群搭建,步骤很简单,这里不展示了, 大家可以直接参考Github:https://github.com/projectcalico/calico-containers/blob/master/docs/calico-with-docker/docker-network-plugin/README.md。

这里默认已经有了Calico网络的集群,IP分别是:192.168.99.102和192.168.99.103。

calicoctl status截图:

同时,已经有两个IP Pool创建好,分别是:10.0.0.0/26和192.168.0.0/16。

calicoctl pool show截图:

当前集群也已经通过使用calico driver和IPAM创建了不同的Docker Network,本次Demo只需要使用DataMan。

Docker Network ls 截图:

calicoctl profile show截图:

下面我们使用DataMan这个网络,在两台slave机器上各启动一个容器:

数人云下发容器的Marathon json file:

code { "id": "/nginx-calico", "cmd": null, "cpus": 0.1, "mem": 64, "disk": 0, "instances": 2, "container": { "type": "DOCKER", "volumes": [], "docker": { "image": "nginx", "network": "HOST", "privileged": false, "parameters": [ { "key": "net", "value": "dataman" } ], "forcePullImage": false } }, "portDefinitions": [ { "port": 10000, "protocol": "tcp", "labels": {} } ] }

两台slave容器IP截图:

从上图可以看出,两个slave上的容器IP分别是:slave 10.0.0.48、slave2 192.168.115.193。

Slave容器连通性测试截图:

IP路由实现

根据上面这个Calico数据平面概念图,结合我们的例子,我们来看看Calico是如何实现跨主机互通的:

两台slave route截图:

对照两台slave的路由表,我们就知道,如果slave 1上的容器(10.0.0.48)想要发送数据到slave 2 上的容器(192.168.115.193), 那它就会match到最后一条路由规则,将数据包转发给slave 2(192.168.99.103),那整个数据流就是:

container -> kernel -> (cali2f0e)slave 1 -> one or more hops -> (192.168.99.103)slave 2 -> kernel -> (cali7d73)container

这样,跨主机的容期间通信就建立起来了,而且整个数据流中没有NAT、隧道,不涉及封包。

安全策略ACL

Calico的ACLs Profile主要依靠iptables和ipset来完成,提供的是可针对每个容器级别的规则定义。

具体的实现我们可以通过iptables命令查看对应的chain和filter规则, 这里我们就不展开讨论了。

Contiv

http://contiv.github.io

Contiv是Cisco开源出来的针对容器的基础架构,主要功能是提供基于Policy的网络和存储管理,是面向微服务的一种新基架。

Contiv能够和主流的容器编排系统整合,包括:Docker Swarm、Kubernetes、Mesos and Nomad。

如上图所示,Contiv比较“诱人”的一点就是,它的网络管理能力,既有L2(VLAN)、L3(BGP),又有 Overlay(VxLAN),而且还能对接Cisco自家的 SDN 产品 ACI。可以说有了它就可以无视底层的网络基础架构,向上层容器提供一致的虚拟网络了。

Contiv Netplugin特性

  • 多租户网络混部在同一台主机上;
  • 集成现有SDN方案;
  • 能够和非容器环境兼容协作,不依赖物理网络具体细节;
  • 即时生效的容器网络Policy/ACL/QoS规则。

网络方案性能对比测试

最后附上我们使用qperf做的简单性能测试结果,我们选取了vm-to-vm、host、calico-bgp、calico-ipip以及Swarm Overlay进行了对比。

其实Contiv也测试了,但是因为Contiv的测试环境和其他方案使用的不同,不具有直接可比性,所以没有放入对比图里。 直观感受就是基于OVS的方案确实不理想,后面有时间会统一环境继续进行测试对比,包括Contiv的L3/L2方案以及引入MacVLAN、Flannel等。

测试环境:VirtualBox VMs,OS:Centos 7.2,kernel 3.10,2 vCPU,2G Mem。

带宽对比结果如下:

时延对比结果如下:

qperf 命令:

总结

随着容器的落地,网络方案必将成为“兵家”必争之地,我们 数人云 是轻量级 PaaS 容器集群管理云平台,在网络方案选择上的考虑是:

  • 性能,Calico和MacVLAN都有着不错的表现;Contiv L3(BGP)理论上性能也不会差;

  • 普适性,Calico对底层的基本要求就是IP层可达;MacVLAN不适应于公有云;Contiv对底层的兼容性可能更好;

  • 可编程性,保证整个网络管理过程能够程序化、API化,这样方便集成到产品里,不需要手动运维;Calico和Contiv都有相应的模块;

  • 未来发展,这个就是我说的“站队”,Docker的CNM和CoreOS、Kubernetes的CNI,现在还看不清,Calico和Contiv都是支持的。

综上,个人推荐关注和尝试下Calico或者Contiv做为容器的网络方案,有问题或者收获,欢迎随时交流分享。

Q&A

Q:从你发的Marathon json文件来看,你们是对Mesos底层的网络做了扩展吗?容器网络通过”parameters”传递下去的吗?

A:就是利用Marathon支持的Docker parameters下发,等同于docker run —net dataman xxx。

Q:Felix根据配置的pool地址段配置路由,BGP Client通告路由?请问bgp的邻居关系是怎么建立的?是依靠etcd里的信息?

A:是的,Felix配置本地Kernel路由,BGP Client负责分发路由信息;BGP小规模部署采取mesh方式建立,所有节点互联n^2的联系,大规模部署推荐 部署一个或多个BGP route reflector,专门负责路由信息分发。

Q:请问在DataMan这个网络中路由信息是如何更新的?我们知道BGP是可以自己发现收敛网络的,那么在网络控制层面是如何设计的?

A:随着使用DatMan这个网络的容器的添加或者删除,Felix负责更新本地路由,BGP client 负责向外分发;Calico的BGP和广域网的BGP还是有不同,它只是使用private AS num,相对自治,网络控制层面都是可以程序控制的。

Q:请问Calico如何解决多租户里地址冲突的问题?

A:多租户容器混部在同一主机上时,所使用的Network最好不要用同一个Pool里的就好,这样就不可能有冲突了。

Q:如果集群的容器很多,那么相应的路由表的规则也会增多,这样会不会对网络性能造成影响?

A:网络性能不会有太大影响,因为容器多流量多网络压力本来就大,倒是会增加系统负载,毕竟要配置路由规则,同步网络信息;这部分我们也很关心,但还没有具体的测试结果。

Q:还有就是路由信息是存放在etcd中吗?如何保证路由表的读取性能和维护路由表的信息更新?

A:生效的路由肯定是本地的,Endpoint等信息是在etcd的;这两个问题都是Calico自身要解决的问题,这部分我们也很关心,但还没有具体的测试结果。

Q:Calico下跨多个路由hop的情况,中间路由不需要学习这么多的容器路由表吗?

A:不需要,中间过程是依赖节点之间原有的网络建设的,只要两个节点互通,所有的hop都不需要知道Calico内部的容器路由信息。

Q:还有一个问题,就是网络管理问题。目前从设备厂商网站看有几个支持VXLAN控制器的。这些控制器能不能与容器OVS协同? 目前来看我们这里买国外产品还是比较困难的。

A:这个肯定是问题,我觉得作为平台方,我们能做的很少,如果要改变,肯定是要SDN设备厂商发力,就像是各家都会去为OpenStack适配设备提供driver一样,但是也需要Docker或者说容器编排系统能做到如同OpenStack那样的行业标准级。

Q:Calico能和Flannel整合么,CoreOS上Kubelet里同时出现了Calico和Flannel?

A:Calico在DockerCon 2016应该是高调拥抱了Flannel,两个整合出了一个叫canal的项目,有兴趣可以去找找看。

Q:我想问一下老师,你这VXLAN的标签是Calico打的对吧?

A:Calico没有VXLAN,Calico的tag会对应到 ipset,iptables 用来 match filter规则。