自从docker容器出现以来,容器的网络通讯就一直是你们关注的焦点,也是生产环境的迫切需求。而容器的网络通讯又能够分为两大方面:单主机容器上的相互通讯和跨主机的容器相互通讯。而本文将分别针对这两方面,对容器的通讯原理进行简单的分析,帮助你们更好地使用docker。html
基于对net namespace的控制,docker能够为在容器建立隔离的网络环境,在隔离的网络环境下,容器具备彻底独立的网络栈,与宿主机隔离,也可使容器共享主机或者其余容器的网络命名空间,基本能够知足开发者在各类场景下的须要。按docker官方的说法,docker容器的网络有五种模式:node
这些网络模式在相互网络通讯方面的对好比下所示:linux
模式docker |
是否支持多主机 | 南北向通讯机制 | 东西向通讯机制安全 |
bridge | 否 | 宿主机端口绑定 | 经过Linux bridge |
host | 是 | 按宿主机网络通讯 | 按宿主机网络通讯 |
none | 否 | 没法通讯 | 只能用link通讯 |
其余容器 | 否 | 宿主机端口绑定 | 经过link通讯 |
用户自定义 | 按网络实现而定 | 按网络实现而定 | 按网络实现而定 |
南北向通讯指容器与宿主机外界的访问机制,东西向流量指同一宿主机上与其余容器相互访问的机制。服务器
因为容器和宿主机共享同一个网络命名空间,换言之,容器的IP地址即为宿主机的IP地址。因此容器能够和宿主机同样,使用宿主机的任意网卡,实现和外界的通讯。其网络模型能够参照下图:网络
采用host模式的容器,能够直接使用宿主机的IP地址与外界进行通讯,若宿主机具备公有IP,那么容器也拥有这个公有IP。同时容器内服务的端口也可使用宿主机的端口,无需额外进行NAT转换,并且因为容器通讯时,再也不须要经过linuxbridge等方式转发或者数据包的拆封,性能上有很大优点。固然,这种模式有优点,也就有劣势,主要包括如下几个方面:tcp
bridge模式是docker默认的,也是开发者最常使用的网络模式。在这种模式下,docker为容器建立独立的网络栈,保证容器内的进程使用独立的网络环境,实现容器之间、容器与宿主机之间的网络栈隔离。同时,经过宿主机上的docker0网桥,容器能够与宿主机乃至外界进行网络通讯。其网络模型能够参考下图:工具
从该网络模型能够看出,容器从原理上是能够与宿主机乃至外界的其余机器通讯的。同一宿主机上,容器之间都是链接到docker0这个网桥上的,它能够做为虚拟交换机使容器能够相互通讯。然而,因为宿主机的IP地址与容器veth pair的 IP地址均不在同一个网段,故仅仅依靠veth pair和namespace的技术,还不足以使宿主机之外的网络主动发现容器的存在。为了使外界能够方位容器中的进程,docker采用了端口绑定的方式,也就是经过iptables的NAT,将宿主机上的端口端口流量转发到容器内的端口上。oop
举一个简单的例子,使用下面的命令建立容器,并将宿主机的3306端口绑定到容器的3306端口:
docker run -tid –name db -p 3306:3306 MySQL
在宿主机上,能够经过iptables -t nat -L -n,查到一条DNAT规则:
DNAT tcp — 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 to:172.17.0.5:3306
上面的172.17.0.5即为bridge模式下,建立的容器IP。
很明显,bridge模式的容器与外界通讯时,一定会占用宿主机上的端口,从而与宿主机竞争端口资源,对宿主机端口的管理会是一个比较大的问题。同时,因为容器与外界通讯是基于三层上iptables NAT,性能和效率上的损耗是能够预见的。
在这种模式下,容器有独立的网络栈,但不包含任何网络配置,只具备lo这个loopback网卡用于进程通讯。也就是说,none模式为容器作了最少的网络设置,可是俗话说得好“少便是多”,在没有网络配置的状况下,经过第三方工具或者手工的方式,开发这任意定制容器的网络,提供了最高的灵活性。
其余网络模式是docker中一种较为特别的网络的模式。在这个模式下的容器,会使用其余容器的网络命名空间,其网络隔离性会处于bridge桥接模式与host模式之间。当容器共享其余容器的网络命名空间,则在这两个容器之间不存在网络隔离,而她们又与宿主机以及除此以外其余的容器存在网络隔离。其网络模型能够参考下图:
在这种模式下的容器能够经过localhost来同一网络命名空间下的其余容器,传输效率较高。并且这种模式还节约了必定数量的网络资源,但它并无改变容器与外界通讯的方式。在一些特殊的场景中很是有用,例如,kubernetes的pod,kubernetes为pod建立一个基础设施容器,同一pod下的其余容器都以其余容器模式共享这个基础设施容器的网络命名空间,相互之间以localhost访问,构成一个统一的总体。
在用户定义网络模式下,开发者可使用任何docker支持的第三方网络driver来定制容器的网络。而且,docker 1.9以上的版本默认自带了bridge和overlay两种类型的自定义网络driver。能够用于集成calico、weave、openvswitch等第三方厂商的网络实现。
除了docker自带的bridge driver,其余的几种driver均可以实现容器的跨主机通讯。而基于bdrige driver的网络,docker会自动为其建立iptables规则,保证与其余网络之间、与docker0之间的网络隔离。例如,使用下面的命令建立一个基于bridge driver的自定义网络:
docker network create bri1
则docker会自动生成以下的iptables规则,保证不一样网络上的容器没法互相通讯。
-A DOCKER-ISOLATION -i br-8dba6df70456 -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-8dba6df70456 -j DROP
除此以外,bridge driver的全部行为都和默认的bridge模式彻底一致。而overlay及其余driver,则能够实现容器的跨主机通讯。
早期你们的跨主机通讯方案主要有如下几种:
上面这些方案有各类各样的缺陷,同时也由于跨主机通讯的迫切需求,docker 1.9版本时,官方提出了基于vxlan的overlay网络实现,原生支持容器的跨主机通讯。同时,还支持经过libnetwork的plugin机制扩展各类第三方实现,从而以不一样的方式实现跨主机通讯。就目前社区比较流行的方案来讲,跨主机通讯的基本实现方案有如下几种:
下面,本从网络通讯模型的角度,对这些方案的通讯原理作一个简单的比较,从中能够窥见各类方案在性能上的本质差异。
首先,科普下docker容器的CNM网络模型,calico、weave等第三方实现都是基于CNM模型与docker集成的。CNM网络模型的结构以下图所示:
在上面的图中:
docker官方文档的示例中,overlay网络是在swarm集群中配置的,但实际上,overlay网络能够独立于swarm集群实现,只须要知足如下前提条件便可。
协议
端口 说明
udp 4789 容器之间流量的vxlan端口 tcp/udp 7946 docker守护进程的控制端口
宿主机内核版本10以上(1.9版本时,要求3.16以上)
知足以上条件后,就能够经过docker network命令来建立跨主机的overlay网络了,例如: docker network create -d overlay overlaynet 在集群的不一样主机上,使用overlaynet这个网络建立容器,造成以下图所示的网络拓扑:
因为容器和overlay的网络的网络命名空间文件再也不操做系统默认的/var/run/netns下,只能手动经过软链接的方式查看。
ln -s /var/run/docker/netns /var/run/netns
这样就能够经过ip netns查看到容器和网络的网络命名空间了。
容器的网络命名空间名称能够经过docker inspect -f ‘{{.NetworkSettings.SandboxKey}}’ <容器ID>方式查看到。网络的网络命名空间则是经过docker network ls查看到的网络短ID。
有时候网络的网络命名空间名称前面会带上1-、2-等序号,有时候不带。但不影响网络的通讯和操做。
从这个通讯过程当中来看,跨主机通讯过程当中的步骤以下:
虽然上面的网络通讯模型能够实现容器的跨主机通讯,但仍是有一些缺陷,形成实际使用上的不便,例如:
weave经过在docker集群的每一个主机上启动虚拟的路由器,将主机做为路由器,造成互联互通的网络拓扑,在此基础上,实现容器的跨主机通讯。其主机网络拓扑参见下图:
如上图所示,在每个部署Docker的主机(多是物理机也多是虚拟机)上都部署有一个W(即weave router,它自己也能够以一个容器的形式部署)。weave网络是由这些weave routers组成的对等端点(peer)构成,而且能够经过weave命令行定制网络拓扑。
每一个部署了weave router的主机之间都会创建TCP和UDP两个链接,保证weave router之间控制面流量和数据面流量的经过。控制面由weave routers之间创建的TCP链接构成,经过它进行握手和拓扑关系信息的交换通讯。控制面的通讯能够被配置为加密通讯。而数据面由weave routers之间创建的UDP链接构成,这些链接大部分都会加密。这些链接都是全双工的,而且能够穿越防火墙。
当容器经过weave进行跨主机通讯时,其网络通讯模型能够参考下图:
从上面的网络模型图中能够看出,对每个weave网络中的容器,weave都会建立一个网桥,而且在网桥和每一个容器之间建立一个veth pair,一端做为容器网卡加入到容器的网络命名空间中,并为容器网卡配置ip和相应的掩码,一端链接在网桥上,最终经过宿主机上weave router将流量转发到对端主机上。其基本过程以下:
weave默认基于UDP承载容器之间的数据包,而且能够彻底自定义整个集群的网络拓扑,但从性能和使用角度来看,仍是有比较大的缺陷的:
calico是纯三层的SDN 实现,它基于BPG 协议和Linux自身的路由转发机制,不依赖特殊硬件,容器通讯也不依赖iptables NAT或Tunnel 等技术。可以方便的部署在物理服务器、虚拟机(如 OpenStack)或者容器环境下。同时calico自带的基于iptables的ACL管理组件很是灵活,可以知足比较复杂的安全隔离需求。
在主机网络拓扑的组织上,calico的理念与weave相似,都是在主机上启动虚拟机路由器,将每一个主机做为路由器使用,组成互联互通的网络拓扑。当安装了calico的主机组成集群后,其拓扑以下图所示:
每一个主机上都部署了calico/node做为虚拟路由器,而且能够经过calico将宿主机组织成任意的拓扑集群。当集群中的容器须要与外界通讯时,就能够经过BGP协议将网关物理路由器加入到集群中,使外界能够直接访问容器IP,而不须要作任何NAT之类的复杂操做。
当容器经过calico进行跨主机通讯时,其网络通讯模型以下图所示:
从上图能够看出,当容器建立时,calico为容器生成veth pair,一端做为容器网卡加入到容器的网络命名空间,并设置IP和掩码,一端直接暴露在宿主机上,并经过设置路由规则,将容器IP暴露到宿主机的通讯路由上。于此同时,calico为每一个主机分配了一段子网做为容器可分配的IP范围,这样就能够根据子网的CIDR为每一个主机生成比较固定的路由规则。
当容器须要跨主机通讯时,主要通过下面的简单步骤:
从上面的通讯过程来看,跨主机通讯时,整个通讯路径彻底没有使用NAT或者UDP封装,性能上的损耗确实比较低。但正式因为calico的通讯机制是彻底基于三层的,这种机制也带来了一些缺陷,例如:
转自:https://www.cnblogs.com/ilinuxer/p/6680205.html
docker容器网络参见:https://blog.csdn.net/zjysource/article/details/52055820