一、Docker网络有哪些
学习Docker,会学习到docker网络,一个网络是一组可以相互联通的端点。Docker在安装时就会创建3个网络
1 | 查看网络 |
其余2个是自己创建的网络,可以暂时不关注
host网络:与宿主机在同一个网络中,与宿主机共用一个Network Namespace。容器将不会虚拟自己的网卡和IP,而是使用宿主机的IP和端口。若端口冲突就不能使用该模式了
none网络:关闭容器的网络,放在上面的容器都是不需要网络的。例如生成随机密码的功能
bridge网络:容器使用独立的Network Namespace,并连接到docker0虚拟网桥。如果不指明网络,默认创建的容器都会挂在docker0中。容器通过docker0网桥以及Iptables net表配置与宿主机通信。
二、Bridge网络是什么
Docker derver启动的时候,主机会自动创建docker0的虚拟网桥,所有新创建的容器都会连接到这个网桥之上,这样主机的容器相当于在一个二层网络中。Bridge网络会为每个容器分配veth pair对,网卡的一头在容器中,一头在挂在网桥docker0上。
1 | 查看主机的网桥 |
可以看到docker0网桥上已经挂载了3个网卡了。这里说明已经创建了三个容器,这三个就是容器的虚拟网卡。
1 | 查看bridge网络的相关信息 |
可以看到bridge网段是172.17.0.0/16,网关占用第一个ip(172.17.0.1),剩下的ip随机分配给创建的容器
接下来看一下mysqltest容器的网络配置:
apt-get install net-tools // 安装ifconfig
apt-get install iputils-ping // 安装ping
apt-get install iproute2 // 安装ip
可以看到为该容器分配的ip是172.17.0.3,容器端网卡是eth0@if1232。
通过ip addr 命令找到另一端网卡vethc991ce1
通过brctl show 命令看到vethc991ce1挂在docker0上
我们可以看到mysqltest容器2端有一对veth pair(vethc991ce1和eth0@if1232),这2端一端(eth0@if1232)在容器中,一端(vethc991ce1)挂在docker0,这相当于eth0@if1232也挂在docker0上,从而将容器连接到bridge网络中
当前的容器网络拓扑图如下:
三、容器之间是怎么相互通信的
1、主机内部,相同网络
Docker基于veth pair网卡对,实现相同网络之间的通信,不是直接端对端,是通过bridge间接实现通信。
在mysql2容器内部,ping mysql1的ip,可以看到是可以互通的
在mysql2容器内部可以看到路由表:接口是eth0,通过网卡将信息传输到docker0,docker0广播地址,通过网卡找到mysql1
2、主机内部,不同网络
不同网络之间是不能直接进行通信的,也就是在172.17.0.2容器内部不能ping通172.18.0.4。如下图是连接不通的网络拓扑图:
可以通过以下2种方法实现不同网络直接的通信:
方法一:把容器加入到另一个网络中,把想要通信的容器放在同一容器
也就是将peer0.org2容器加入到bridge
通过ifconfig可以看到peer0.org2容器在之前的网卡基础上(lo,eth0)增加了eth1网卡,且分配了一个bridge网络网段的ip。
1 | 将04aec1064812(peer0.org2)容器加入到bridge网络中 |
查看bridge网络也可以看到peer0.org2容器
进入peer0.org2容器可以看到该容器同时属于2个网络中
这样我们的网络拓扑图会变成这样:
peer0.org2加入到新网络之后,会产生一对veth pair在bridge网络上,这样就和在同一网络通信是一致的了。
方法二:修改底层iptables实现网络的通信
1 | iptables-save 查看iptables规则 |
为什么2个网络不通其实原理就在这里:在iptables规则就drop掉了网桥docker0和br-b86310df8e66之间的双向流量。规则的命名DOCKER-ISOLATION也可知道docker 在设计上就是隔离了不同的network。
所以这里最直接的办法就是修改iptables规则:增加双向关系
1 | sudo iptables -I DOCKER-USER -i docker0 -o br-b86310df8e66 -j ACCEPT |
验证一下:完美~
3、外部世界与容器的通信
在容器内ping www.baidu.com 是可以通的
可见,容器默认就可以访问外网。但是原理是什么呢?
先查一下iptables规则,在NAT表有这么一条规则:
1 | -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE |
这条语句表明:网桥docker0收到来自172.17.0.0/16网段的外出包,把它交给MASQUERADE处理。MASQUERADE的处理方式将包的源地址替换成host的地址发送出去,也就是做了一次网络地址转换(NAT)
查看路由表,可以看到默认路由是通过eth0发送出去
我们通过tcpdump抓包来看下是怎么转换的
第一步:先让docker0网络的容器ping 百度的网址
第二步:看到docker0抓包情况
docker0收到mysqltest的ping包,源地址为容器的ip 172.17.0.3,然后交给MASQUERADE处理。
第三步:看到eth0抓包情况
在eth0看到把ping包源地址转成10.0.0.234,这就是NAT规则处理的结果,保证数据包到达外网。下图就是以上的流程:
看到这里你可能还有疑问,那不同主机之间的容器是怎么通信的,这个留到下次学习~