docker的网络模型如下图:
代码语言:txt复制[root@test-a-docker01 ~]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:dbff:feb7:ad6e prefixlen 64 scopeid 0x20<link>
ether 02:42:db:b7:ad:6e txqueuelen 0 (Ethernet)
RX packets 170 bytes 19218 (18.7 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 222 bytes 36474 (35.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.11.23 netmask 255.255.255.0 broadcast 192.168.11.255
inet6 fd15:4ba5:5a2b:1008:192:168:11:23 prefixlen 64 scopeid 0x0<global>
inet6 fe80::f906:733a:ec14:9a9a prefixlen 64 scopeid 0x20<link>
inet6 fe80::b57c:b4f:30d1:d6e2 prefixlen 64 scopeid 0x20<link>
inet6 fe80::b7ae:6dc9:eb0b:6f0d prefixlen 64 scopeid 0x20<link>
ether 00:50:56:29:ce:cc txqueuelen 1000 (Ethernet)
RX packets 6636 bytes 1370980 (1.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3443 bytes 452340 (441.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 32 bytes 2592 (2.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 32 bytes 2592 (2.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
vethc1173e2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::e8db:16ff:fe96:ef87 prefixlen 64 scopeid 0x20<link>
ether ea:db:16:96:ef:87 txqueuelen 0 (Ethernet)
RX packets 55 bytes 4354 (4.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 75 bytes 8788 (8.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@test-a-docker01 ~]#
- 「veth」xxxxxxx:它主要用于解决网络名称空间之间的隔离,当启动一个容器,会跟着自动创建一个veth虚拟接口,好比是容器接了一条网线到这个veth虚拟接口,并且通过veth虚拟接口和docker0进行通信,veth会随着的容器的启动而自动增加,也会随着容器的销毁而自动销毁,每个容器都会有各自的veth。
- docker0:是一个虚拟网卡,类似网桥,也可以看成是一个二层网络设备,通过它可以将linux支持的不同的端口连接起来,实现多对多的通信。docker0这个虚拟网卡有个IP地址(172.17.0.1),进去容器里面看网络地址消息,会发现它就是容器的网关
接下来剖析一下细节
不管是运行的还是没有运行的,那么当前都只有一个web01容器在运行
代码语言:txt复制[root@test-a-docker01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a809b11833c6 nginx "/docker-entrypoint.…" 4 hours ago Up 4 hours 0.0.0.0:8080->80/tcp, :::8080->80/tcp web01
[root@test-a-docker01 ~]#
查看web01容器的详情,它的输出是json,为了方便查看,可复制出来对json串进行解析
代码语言:txt复制[root@test-a-docker01 ~]# docker inspect web01
丢到https://www.json.cn/进行解析
可通过--format选项直接获取容器web01的ip地址
代码语言:txt复制[root@test-a-docker01 ~]# docker inspect web01 --format='{{.NetworkSettings.IPAddress}}'
172.17.0.2
接下来再拉起一个容器web02
代码语言:txt复制[root@test-a-docker01 ~]# docker run -d -p 8081:80 --name web02 -h web02 -v /data/webdata:/usr/share/nginx/html nginx
092f185073eb5834097fe0d1c4ada3a65b6016e5ad717f1471927ed6c351afec
[root@test-a-docker01 ~]#
[root@test-a-docker01 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
092f185073eb nginx "/docker-entrypoint.…" 5 seconds ago Up 4 seconds 0.0.0.0:8081->80/tcp, :::8081->80/tcp web02
a809b11833c6 nginx "/docker-entrypoint.…" 5 hours ago Up 5 hours 0.0.0.0:8080->80/tcp, :::8080->80/tcp web01
[root@test-a-docker01 ~]#
现在有了两个容器,继续看下网络接口的情况
代码语言:txt复制[root@test-a-docker01 ~]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:dbff:feb7:ad6e prefixlen 64 scopeid 0x20<link>
ether 02:42:db:b7:ad:6e txqueuelen 0 (Ethernet)
RX packets 205 bytes 23535 (22.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 271 bytes 46325 (45.2 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.11.23 netmask 255.255.255.0 broadcast 192.168.11.255
inet6 fd15:4ba5:5a2b:1008:192:168:11:23 prefixlen 64 scopeid 0x0<global>
inet6 fe80::f906:733a:ec14:9a9a prefixlen 64 scopeid 0x20<link>
inet6 fe80::b57c:b4f:30d1:d6e2 prefixlen 64 scopeid 0x20<link>
inet6 fe80::b7ae:6dc9:eb0b:6f0d prefixlen 64 scopeid 0x20<link>
ether 00:50:56:29:ce:cc txqueuelen 1000 (Ethernet)
RX packets 6935 bytes 1400532 (1.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3598 bytes 473025 (461.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 32 bytes 2592 (2.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 32 bytes 2592 (2.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth3a0e879: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::5c99:aaff:fe4e:9cfb prefixlen 64 scopeid 0x20<link>
ether 5e:99:aa:4e:9c:fb txqueuelen 0 (Ethernet)
RX packets 26 bytes 4357 (4.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 48 bytes 10080 (9.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
vethc1173e2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::e8db:16ff:fe96:ef87 prefixlen 64 scopeid 0x20<link>
ether ea:db:16:96:ef:87 txqueuelen 0 (Ethernet)
RX packets 64 bytes 4804 (4.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 87 bytes 9389 (9.1 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@test-a-docker01 ~]#
docker0网桥还是1个,「veth」xxxxxxx多了1个,也就是说veth会随着的容器的增加而增加,也会随着容器的销毁而销毁,每个容器都会有各自的veth。
接下来探讨一下,外部是如何访问到容器里提供的服务
创建容器web01
代码语言:txt复制docker run -d -p 8080:80 --name web01 -h web01 -v /data/webdata:/usr/share/nginx/html nginx
-p 选项中,当宿主机接收到一个来自8080端口的请求就会转发给容器的80端口进行处理
这个转发的动作是由iptables的PREROUTING实现,PREROUTING是目的地址转换(DNAT),再结合路由表就可以得知发往172.17.0.0/16网络的数据包由docker0接收,再到veth,最终到达容器。
代码语言:txt复制# 查看dant规则
[root@test-a-docker01 ~]# iptables -t nat -vnL DOCKER
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
7 364 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
2 104 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8081 to:172.17.0.3:80
# 查看路由
[root@test-a-docker01 ~]# ip route
default via 192.168.11.2 dev ens32 proto static metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.11.0/24 dev ens32 proto kernel scope link src 192.168.11.23 metric 100
那么,容器又是如何访问到外部的呢?主要是由iptables的POSTROUTING进行实现,POSTROUTING是源地址转换(SNAT)。
代码语言:txt复制# 查看SNAT规则
[root@test-a-docker01 ~]# iptables -t nat -vnL POSTROUTING
Chain POSTROUTING (policy ACCEPT 18 packets, 1296 bytes)
pkts bytes target prot opt in out source destination
13 759 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
0 0 MASQUERADE tcp -- * * 172.17.0.3 172.17.0.3 tcp dpt:80
[root@test-a-docker01 ~]#
# 查看路由表
[root@test-a-docker01 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.11.2 0.0.0.0 UG 100 0 0 ens32
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.11.0 0.0.0.0 255.255.255.0 U 100 0 0 ens32
[root@test-a-docker01 ~]#
本文转载于(喜欢的盆友关注我们哦):https://mp.weixin.qq.com/s/0DgBK2gXFvV9iY-HJbSDfw