Docker网络现状
为了解决容器网络性能低下、功能不足的问题,Docker启动了子项目“Libnetwork”。Libnetwork提出了新的容器网络模型(Container Network Model,简称CNM),定义了标准的API用于为容器配置网络,其底层可以适配各种网络驱动(如图Docker-network01所示)。CNM有三个:
- 沙盒
沙盒是一个隔离的网络运行环境,保存了容器网络栈的配置,包括了对网络接口、路由表和DNS配置的管理。在Linux平台上,沙盒是用Linux Network Namespace实现的,在其他平台上可能是不同的概念,如FreeBSD Jail。一个沙盒可以包括来自多个网络的多个Endpoint(端点)。 - Endpoint
Endpoint将沙盒加入一个网络,Endpoint的实现可以是一对veth pair或者OVS内部端口,当前的Libnetwork使用的是veth pair。一个Endpoint只能隶属于一个沙盒及一个网络。通过给沙盒增加多个Endpoint可以将一个沙盒加入多个网络。 - 网络
网络包括一组能互相通信的Endpoint。网络的实现可以是Linux bridge、vlan等。
从CNM的概念角度讲,Libnetwork的出现使得Docker具备了跨主机多子网的能力,同一个子网内的不同容器可以运行在不同主机上。比如,同属于192.168.0.0/24子网IP地址分别为192.168.0.1和192.168.0.2的容器可以位于不同的主机上且可以直接通信,而持有IP 192.168.1.1的容器即使与IP为192.168.0.1的容器处于同一主机也不能互通。
Libnetwork已经实现了五种驱动(driver):
- bridge
Docker默认的容器网络驱动。Container通过一对veth pair连接到docker0网桥上,由Docker为容器动态分配IP及配置路由、防火墙规则等。 - host
容器与主机共享同一Network Namespace,共享同一套网络协议栈、路由表及iptables规则等。容器与主机看到的是相同的网络视图。 - null
容器内网络配置为空,需要用户手动为容器配置网络接口及路由等。 - remote
Docker网络插件的实现。Remote driver使得Libnetwork可以通过HTTP RESTful API对接第三方的网络方案,类似SocketPlane的SDN方案只要实现了约定的HTTP URL处理函数及底层的网络接口配置方法,就可以替换Docker原生的网络实现。 - overlay
Docker原生的跨主机多子网网络方案。主要通过使用Linux bridge和vxlan隧道实现,底层通过类似于etcd或consul的KV存储系统实现多机的信息同步。overlay驱动当前还未正式发布,但开发者可以通过编译实验版的Docker来尝试使用,Docker实验版同时提供了额外的network和service子命令来进行更灵活的网络操作,不过,需要内核版本>=3.16才可正常使用。
以上五种驱动已经随Docker 1.8一同发布。Docker的网络模块是可插拔式的,默认有五种网络模式可以选择,通过docker network ls这个命令来查看本机中所有的网络模式。
bridge
Docker daemon启动时会在主机创建一个Linux网桥(默认为docker0,可通过-b参数手动指定)。容器启动时,Docker会创建一对veth pair(虚拟网络接口)设备,veth设备的特点是成对存在,从一端进入的数据会同时出现在另一端。Docker会将一端挂载到docker0网桥上,另一端放入容器的Network Namespace内,从而实现容器与主机通信的目的。bridge模式下的网络拓扑图如图docker-network02所示:
在桥接模式下,Docker容器与Internet的通信,以及不同容器之间的通信,都是通过iptables规则控制的。总之,Docker网络的初始化动作包括:创建docker0网桥、为docker0网桥新建子网及路由、创建相应的iptables规则等。Bridge模式是Docker默认的容器运行模式,以bridge模式启动的容器,默认会从172.17.42.1/16子网内分配IP。
bridge模式是docker的默认网络模式,此模式会为每一个容器设置network namespace、ip地址等,在docker启动时候,就会在主机上创建一个名为docker0的虚拟网桥,在该主机上启动的docker容器都会连接到这个虚拟网桥上,这样就可以和同一宿主机上桥接模式的其它容器进行通信啦。
从上面的示例可以看出,同一节点下的容器默认都是可以彼此交流哒~
host
host模式下,容器不会设置自己的network namespace、ip等,而是和宿主机共用,通过--network host可以将容器直接绑定在Docker主机的网络,没有网络隔离,但是其它方面,比如文件系统、进程列表还是与宿主机隔离的。外界也可以直接访问容器。
none
使用的none模式后,这个容器就是封闭的,不会去参与网络通信,这样就能够保证容器的安全性。
macvlan
对于某一些应用程序,比如需要监视网络流量,期望直接连接到物理网络,这种情况下,可以使用macvlan的网络模式,docker会为容器的虚拟网络接口分配MAC地址。
创建一个macvlan网络
启动一个busybox容器,网络模式是macvlan
overlay
overlay网络是使用在swarm集群中,用于连接不同主机上的docker容器,允许不同宿主机上的容器相互通信。
然后执行以下命令将工作节点加入集群
新建一个overlay网络
分别在manager节点和work节点上启动一个busybox容器,并连接到overlay网络
然后我们在同一个overlay网络下的容器中互相去ping对方,是可以连接哒~
我们也可以利用overlay网络去创建一个集群服务,使用docker swarm去管理我们的集群服务。现在创建一个五副本的连接到overlay网络的nginx服务,暴露端口为80;
利用docker ps命令我们可以发现工作节点上也启动了nginx应用,这个就是通过overlay来实现不同主机中容器之间的通信。细心的小伙伴还会发现在任一节点结束一个副本,集群服务就会重启一个新的副本,会一直保持节点内的nginx副本数量为五个,有木有觉得还蛮有意思的!
overlay网络模型在docker集群节点间的加入了一层虚拟网络,它有独立的虚拟网段,因此docker容器发送的内容,会先发送到虚拟子网,再由虚拟子网包装为宿主机的真实网址进行发送。
总 结
docker网络就介绍到这啦,通过上面的实践我们不难发现:
1、在需要多个docker容器在同一个宿主机上进行通信,最好就直接使用默认的bridge模式;
2、当多个应用程序需要组成集群提供高可用服务时候,overlay肯定是最佳的选择;
3、host模式对于优化性能以及在容器需要处理大量端口的情况下很有用,因为它不需要NAT,并且也不会为每个端口创建“ userland-proxy”。当想要容器对网络传输效率有较高要求,就可以选择host模式,但是要注意端口占用的问题哦~