docker有3种网络:
使用命令docker network ls
,执行结果如下。
NETWORK ID NAME DRIVER SCOPE
82e8822065c7 bridge bridge local
a36f938bc6c6 host host local
55ee9a442ee8 none null local
1,bridge:是NAT Bridge。在宿主机器上创建一个软件的交换机或者是网卡。
用ifconfig
可以看到多了个【docker0】。
【docker0】既可以作为交换机,也可以作为网卡。不给它地址就是交换机,给它地址就既能当交换机也能当网卡。
linux内核可以为进程创建虚拟网卡对,这个网卡对就像网线一样,有2个头。
一头连接到自己进程所属的网络命名空间,另一头连接任何地方。
linux内核也可以创建软件交换机,使用【brctl】命令创建。
创建虚拟网络,以实现让进程C1和进程C2可以通信。
- 步骤1:创建一个网线m
- 步骤2:创建一个网线n
- 步骤3:创建一个虚拟交换机S1。
- 步骤4:让网线m的一端连上进程C1所属的网络命名空间,让网线m的另一端连上虚拟交换机S1。
- 步骤5:让网线n的一端连上进程C2所属的网络命名空间,让网线n的另一端连上虚拟交换机S1。
- 进程C1和进程C2就可以通信了。
创建虚拟网络,以实现让进程C1和进程C3可以通信。
- 步骤1:创建一个网线k
- 步骤2:创建一个虚拟交换机S2。
- 步骤3:创建一个图中间的微内核,让这个内核代替路由器。或者不需要路由器的话,创建1根网线,连接S1和S2,这样一来就不需要步骤4了。
- 步骤4:创建2根网线,让S1和S2都连都微内核上。
- 进程C1和进程C3就可以通信了。
有个著名的开源的创建虚拟交换机的软件:OVS(OpenVSwitch).
overlay network(叠加网络)
C1(192.168.1.3)和C5(192.168.1.4)在同一个网段,物理机器h1(10.1.1.3)和h2(10.1.1.4)连接在同一个交换机上。因为C1和C5在同一个网段,所以它们2个可以互相看见,当C1要发送数据给C5时,ip报文里是C1:C5,然后经过虚拟网桥(docker0),转发给物理机器h1,物理机器h1在【ip报文C1:C5】外面再包裹一层【h1:h2】,物理机器h2接受到报文后,拆掉外层的【h1:h2】,发现里面还有【C1:C5】,所以通过虚拟网桥(docker0),转发给C5。
上图里面的【docker0】,就是在运行docker daemon进程的机器上,执行ifconfig,看到的【docker0】,它是nat bridge。每启动一个容器,就产生一条网线,一端就插在【docker0】上,一端插在自己容器的网络命名空间上。。
那么如何查看,【docker0】上插了几根网线呢?
使用【yum install bridge-utils】里面的【brctl show】命令,查看网桥上插了哪些网线。
[root@localhost ys]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242af11c649 no veth93593bc
vethc7cb2ca
从上面的执行结果可以看出来,在【docker0】上插了2根网线分别是veth93593bc和vethc7cb2ca。用在宿主机上使用ifconfig,可以看到这2个网线。
[root@localhost ys]# ifconfig
veth93593bc: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 ..... prefixlen 64 scopeid 0x20<link>
ether ..... txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 656 (656.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
vethc7cb2ca: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 .. prefixlen 64 scopeid 0x20<link>
ether ..... txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 656 (656.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
使用【ip link show】也可以看到veth93593bc和vethc7cb2ca,而且还可以发现veth93593bc的另一端是if14,vethc7cb2ca的另一端是if12
[root@localhost ys]# ip link show
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:af:11:c6:49 brd ff:ff:ff:ff:ff:ff
13: vethc7cb2ca@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether a2:a3:b8:3c:8c:88 brd ff:ff:ff:ff:ff:ff link-netnsid 0
15: veth93593bc@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether b2:24:a8:13:4d:56 brd ff:ff:ff:ff:ff:ff link-netnsid 1
【iptables -t nat -vnL】查看,发现了下面的规则,所以说明docker0是nat bridge。
Chain POSTROUTING (policy ACCEPT 47 packets, 3073 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
in:*,代表:从任何接口进来
out:!docker0,代表:不从docker0出去
source:172.17.0.0/16,代表:原地址来自172.17.0.0/16的任何主机地址,
destination:0.0.0.0/0,代表:发送到任何主机地址,
target:MASQUERADE,代表:做源地址转换 (SNAT ),也就是自动在本机上选择一个源地址。
把上面的话连接起来的意思:从任何接口进来,不从docker0出去,原地址是来自172.17.0.0/16的任何主机地址,发送到任何主机地址,做源地址转换。
有个问题,docker容器间是如何互相通信的呢?
假设容器都是以bridge方式启动
2个容器都插在docker0上,那么这2个容器都在172.17网段上,互相通信没有任何问题。
容器和宿主机互相通信没有问题。
客户端CL1,要通过80端口访问nginx容器WEB1,但是客户端CL1同nginx容器WEB1在不同的网络,如何通信呢?nginx容器WEB1所在的宿主机只能使用DNAT技术,才能实现通信。也就是说客户端CL1访问的是宿主机,宿主机再转发给nginx容器WEB1。
这就有个问题了,如果web2和web3也是nginx,也要使用80端口,那么宿主机转发的时候就不知道转给哪个容器了。
另一种方式:容器可以有独立的6个命名空间,为了2个容器间可以用lo(127.0.0.1)通信,让他们只拥有3个(user,mount, pid)独立的命名空间,另外3个(uts, net, ipc)他们共享使用。
二,host:
容器间可以共用3个(uts, net, ipc)空间,那么容器可以和宿主机(docker daemon进程所运行的机器)共用吗?是可以的。让一个容器A和宿主机共用3个(uts, net, ipc)空间,让其他的容器使用桥接,这样一来容器A就有了管理网络的特权。这就是docker的host连接方式。
三,none:容器没有网卡,只有lo。所以不能网络通信。
docker 网络种类:
查看网络连接具体信息的命令(inspect 可以查看任何docker object):
# docker network inspect bridge/host/none
查看容器的网络连接具体信息。
# docker container inspect ng1