docker四种网络模式

一.为何要了解docker网络

当你开始大规模使用Docker时,你会发现须要了解不少关于网络的知识。Docker做为目前最火的轻量级容器技术,有不少使人称道的功能,如Docker的镜像管理。然而,Docker一样有着不少不完善的地方,网络方面就是Docker比较薄弱的部分。所以,咱们有必要深刻了解Docker的网络知识,以知足更高的网络需求。本文首先介绍了Docker自身的4种网络工做方式,而后介绍一些自定义网络模式。nginx

二.docker 网络理论

Docker使用Linux桥接(参考《Linux虚拟网络技术》),在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每一个容器的默认网关。由于在同一宿主机内的容器都接入同一个网桥,这样容器之间就可以经过容器的Container-IP直接通讯。web

Docker网桥是宿主机虚拟出来的,并非真实存在的网络设备,外部网络是没法寻址到的,这也意味着外部网络没法经过直接Container-IP访问到容器。若是容器但愿外部访问可以访问到,能够经过映射容器端口到宿主主机(端口映射),即docker run建立容器时候经过 -p 或 -P 参数来启用,访问容器的时候就经过 [宿主机IP]:[容器端口] 访问容器。docker

当你安装Docker时,它会自动建立三个网络。你可使用如下 docker network ls 命令列出这些网络:segmentfault

# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
857db65319fa        bridge              bridge              local
c16cf8722909        host                host                local
d39a88b56801        none                null                local

三.docker的四类网络模式

网络模式 配置 说明
bridge模式 --net=bridge (默认为该模式)此模式会为每个容器分配、设置IP等,并将容器链接到一个docker0虚拟网桥,经过docker0网桥以及Iptables nat表配置与宿主机通讯。
host模式 --net=host 容器和宿主机共享Network namespace。
container模式 --net=container:NAME_or_ID 容器和另一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。
none模式 --net=none 该模式关闭了容器的网络功能。

3.1 bridge模式

当Docker进程启动时,会在主机上建立一个名为docker0的虚拟网桥,此主机上启动的Docker容器会链接到这个虚拟网桥上。虚拟网桥的工做方式和物理交换机相似,这样主机上的全部容器就经过交换机连在了一个二层网络中。安全

从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上建立一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新建立的容器中,并命名为eth0(容器的网卡),另外一端放在主机中,以vethxxx这样相似的名字命名,并将这个网络设备加入到docker0网桥中。能够经过brctl show命令查看。网络

bridge模式是docker的默认网络模式,不写--net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables作了DNAT规则,实现端口转发功能。可使用iptables -t nat -vnL查看。tcp

bridge模式以下图所示:性能

docker网络模式-bridge

3.2 host模式

若是启动容器的时候使用host模式,那么这个容器将不会得到一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出本身的网卡,配置本身的IP等,而是使用宿主机的IP和端口。可是,容器的其余方面,如文件系统、进程列表等仍是和宿主机隔离的。url

使用host模式的容器能够直接使用宿主机的IP地址与外界通讯,容器内部的服务端口也可使用宿主机的端口,不须要进行NAT,host最大的优点就是网络性能比较好,可是docker host上已经使用的端口就不能再用了,网络的隔离性很差。spa

Host模式以下图所示:

docker网络模式-host

3.3 container模式

这个模式指定新建立的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新建立的容器不会建立本身的网卡,配置本身的 IP,而是和一个指定的容器共享 IP、端口范围等。一样,两个容器除了网络方面,其余的如文件系统、进程列表等仍是隔离的。两个容器的进程能够经过 lo 网卡设备通讯。

Container模式示意图:

docker网络模式container

3.4 none模式

使用none模式,Docker容器拥有本身的Network Namespace,可是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。须要咱们本身为Docker容器添加网卡、配置IP等。

这种网络模式下容器只有lo回环网络,没有其余网卡。none模式能够在容器建立时经过--network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

None模式示意图:

docker网络模式none

四.bridge模式下容器的通讯

4.1 防火墙开启状态

在bridge模式下,连在同一网桥上的容器能够相互通讯(若出于安全考虑,也能够禁止它们之间通讯,方法是在DOCKER_OPTS变量中设置–icc=false,这样只有使用–link才能使两个容器通讯)。

容器也能够与外部通讯,咱们看一下主机上的Iptable规则,能够看到这么一条

这条规则会将源地址为172.17.0.0/16的包(也就是从Docker容器产生的包),而且不是从docker0网卡发出的,进行源地址转换,转换成主机网卡的地址。这么说可能不太好理解,举一个例子说明一下。假设主机有一块网卡为eth0,IP地址为192.168.21.10/24,网关为192.168.21.255。从主机上一个IP为172.17.0.1/16的容器中ping百度(www.baidu.com)。IP包首先从容器发往本身的默认网关docker0,包到达docker0后,也就到达了主机上。而后会查询主机的路由表,发现包应该从主机的eth0发往主机的网关192.168.21.255/24。接着包会转发给eth0,并从eth0发出去(主机的ip_forward转发应该已经打开)。这时候,上面的Iptable规则就会起做用,对包作SNAT转换,将源地址换为eth0的地址。这样,在外界看来,这个包就是从192.168.21.10上发出来的,Docker容器对外是不可见的。

那么,外面的机器是如何访问Docker容器的服务呢?咱们首先用下面命令建立一个含有web应用的容器,将容器的80端口映射到主机的80端口。

docker run -itd --name=nginx_bridge --net=bridge -p 80:80 nginx

而后查看Iptable规则的变化,发现多了这样一条规则:

-A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80

此条规则就是对主机eth0收到的目的端口为80的tcp流量进行DNAT转换,将流量发往172.17.0.2:80,也就是咱们上面建立的Docker容器。因此,外界只需访问192.168.21.10:80就能够访问到容器中的服务。

4.2 防火墙关闭状态

若是docker网络使用了bridge模式,也不须要防火墙,那直接关掉FirewallD服务就能够了。能够解决诸多由于防火墙网络问题致使的docker容器端口不通的问题。