Docker网络模型介绍


theme: geek-black

这是我参与更文挑战的第9天,活动详情查看: 更文挑战

Docker网络介绍

引言

本文简单介绍Docker每种网络类型是如何进行网络交换的,Docker内容器在被NetworkNamespace隔离的情况下如何进行网络通信,跨主机容器间是如何进行网络通信

预准备

我这里创建了两台centos7的虚拟机,分别关闭了selinux和swap,filewalld。两台主机之间是可以相互ping通的。

| 主机 | | --- | | 172.16.3.141 | | 172.16.3.142 |

1.Bridge网络

当需要多个容器在同一个 Docker 主机上进行通信时,用户定义的桥接网络是最佳选择

Bridge是Docker默认使用的网络模型,我们来看下Bridge是如何使两个容器可以相互通信的,此时该主机所有配置均为默认配置。

粗略画一张图

image.png

``` [root@localhost ~]# docker -v Docker version 20.10.7, build f0df350

``` 我们发现这个出现了个docker0的网桥设备,同一台主机的容器都需要与本机的docker0网桥进行通信

``` [root@localhost ~]# ifconfig docker0: flags=4163 mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 inet6 fe80::42:d2ff:fe1d:22a5 prefixlen 64 scopeid 0x20> ether 02:42:d2:1d:22:a5 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 5 bytes 446 (446.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ens33: flags=4163 mtu 1500 inet 172.16.3.141 netmask 255.255.0.0 broadcast 172.16.255.255 inet6 fe80::8d1e:c5fb:7a84:89a prefixlen 64 scopeid 0x20> ether 00:0c:29:81:ed:94 txqueuelen 1000 (Ethernet) RX packets 104250 bytes 139817031 (133.3 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 42132 bytes 4974745 (4.7 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73 mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10 loop txqueuelen 1000 (Local Loopback) RX packets 198 bytes 16420 (16.0 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 198 bytes 16420 (16.0 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ```

  1. 我们来创建两个沙盒容器,然后查看网卡的变化

docker run -it -d --name busybox busybox docker run -it -d --name busybox1 busybox [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c7d208c90e23 busybox "sh" 19 minutes ago Up 19 minutes busybox1 15e045ae83f8 busybox "sh" 25 minutes ago Up 25 minutes busybox 我们再次查看发现多了两个虚拟网卡分别为veth7c9ae7d,vethd5dab10,veth pair是一种虚拟设备,它通常是成对存在的,从其中一个网卡接收的请求会立即出现在对端的网卡上,也就是说宿主机上面的两个veth pair分别对应容器内的eth0 ``` veth7c9ae7d: flags=4163 mtu 1500 inet6 fe80::bc27:7fff:fe48:9a77 prefixlen 64 scopeid 0x20> ether be:27:7f:48:9a:77 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

vethd5dab10: flags=4163 mtu 1500 inet6 fe80::e409:5dff:fef4:6293 prefixlen 64 scopeid 0x20> ether e6:09:5d:f4:62:93 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 13 bytes 1102 (1.0 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 我们看下网桥设备,上面的两个虚拟设备插在了docker0网桥上,看到这就算不知道原理也应该知道容器之间通过这个docekr0网桥进行交互 [root@localhost ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242d21d22a5 no veth7c9ae7d vethd5dab10 在看一下docker network,为了方便看我删除了一些信息,我们可以看到,新创建的两个容器已经出现在这个默认Bridge的配置里了,并分别分配了子网的ip172.17.0.2和172.17.0.3 [root@localhost ~]# docker network inspect 0f2e3e50513e [ { "Name": "bridge", ......... "IPAM": { "Driver": "default", "Options": null, "Config": [ #配置的子网范围 { "Subnet": "172.17.0.0/16" } ] }, "Containers": { "15e045ae83f863c0c74588f8a1cea51e49f11128e46c37df7707c91fafb5a996": { "Name": "busybox", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", }, "c7d208c90e23137846c6fbdba0af8f3e28c79503dbd37cbc41ec5677343a3ae5": { "Name": "busybox1", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", } }, } ] ``` 我们尝试在容器内进行ping另一个容器的ip看是否可以通,此时的网络情况

| 容器 | ip | | --- | --- | | busybox | 172.17.0.2 | | busybox1 | 172.17.0.3 |

``` [root@localhost ~]# docker exec -it busybox sh -c 'ping 172.17.0.3' PING 172.17.0.3 (172.17.0.3): 56 data bytes 64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.419 ms 64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.830 ms

[root@localhost ~]# docker exec -it busybox1 sh -c 'ping 172.17.0.2' PING 172.17.0.2 (172.17.0.2): 56 data bytes 64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.419 ms 64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.942 ms 他们是如何进行通信的?不是被NetworkNamespace隔离了吗?我们进入容器看下网卡信息和路由表,所有对172.17.0.0网段的请求会经过eth0,这个eth0是个啥,他是怎么将请求路由到另一个容器里的eth0的? [root@localhost ~]# docker exec -it busybox1 sh -c 'ifconfig' eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03 inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:20 errors:0 dropped:0 overruns:0 frame:0 TX packets:12 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1496 (1.4 KiB) TX bytes:840 (840.0 B)

lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

[root@localhost ~]# docker exec -it busybox1 sh -c 'route -n' Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0 ```

我们来看下宿主机的路由表,所有对172.17.0.0网段的请求都会被路由到docker0网桥上,那么我们现在知道从172.17.0.3(busybox1)容器发出的请求会被经过自己的eth0网卡经由对应宿主机上的vethpair发送给docker0,那么docker0是如何找到172.17.0.2这个目标ip的呢? [root@localhost ~]# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 172.16.3.1 0.0.0.0 UG 100 0 0 ens33 172.16.0.0 0.0.0.0 255.255.0.0 U 100 0 0 ens33 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 由容器中的路由表可知,目标地址为172.17.0.0会走eth0,而Flags=U,说明他是一个直连规则,而直连规则只需要走二层网络,但是二层网络需要目的ip 172.17.0.2的mac地址,此时会通过docker0发一个Arp广播找到172.17.0.2所对应的mac地址,然后发起直连请求,下面我们来验证一下这个过程


开启TRACE功能,看下数据包怎么走的 iptables -t raw -A OUTPUT -p icmp -j TRACE iptables -t raw -A PREROUTING -p icmp -j TRACE 此时我们在busybox(172.17.0.2)容器中ping一下busybox1(172.17.0.3)

跟踪下iptables trace日志查看下对应的信息,从内容中我们知道,我们从172.17.0.2发起了一个icmp请求到172.17.0.3上 ``` tail -f /var/log/message Jun 23 08:17:17 localhost kernel: TRACE: raw:PREROUTING :rule:4 IN=docker0 #数据包进入的接口,若为空表示本机产生 OUT= #数据包离开的接口,若为空表示本机接收 PHYSIN=vethd5dab10

目标mac地址02:42:ac:11:00:03 ,源 02:42:ac:11:00:02

MAC=02:42:ac:11:00:03:02:42:ac:11:00:02:08:00 #08:00 为上层协议代码,即表示IP协议 SRC=172.17.0.2 #源ip DST=172.17.0.3 #目标ip LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=41094 DF PROTO=ICMP #传输协议(因为这里是ping了一下所以是icmp) TYPE=8 CODE=0 ID=20 SEQ=0 看下arp表,目标172.17.0.3对应的mac地址是02:42:ac:11:00:03,然后通过CAM表获取到目标的veth pari,由于veth pair的特性,直接就进入了容器内部,自然就可以ping通了(CAM是mac地址学习的功能获取到的) [root@localhost ~]# cat /proc/net/arp IP address HW type Flags HW address Mask Device 172.17.0.3 0x1 0x2 02:42:ac:11:00:03 * docker0 172.16.3.1 0x1 0x2 3e:22:fb:a1:32:64 * ens33 172.17.0.2 0x1 0x2 02:42:ac:11:00:02 * docker0 ```

知道了容器直接网络传输的流程,那我们在宿主机机上直接ping容器的ip会怎么样呢?可以看到也是ping的通的,此时的数据走向是如何的呢 [root@localhost ~]# ping 172.17.0.2 PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data. 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=1.68 ms 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.445 ms 根据宿主机的路由表可知,发往172.17.0.2的数据包会经过docker0网桥设备,可以看到也是一个直连类型,然后又回到了上面arp的流程 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 ojbk,那如果是外部请求访问容器呢?比如我起了一个nginx容器端口为80,但是请求的目的ip为宿主机的ip比如172.16.3.140,此时如何转发到容器内呢?其实很容易猜到了,就是DNAT(目标地址转换) [root@localhost ~]# iptables -t nat -L -n Chain DOCKER (2 references) target prot opt source destination RETURN all -- 0.0.0.0/0 0.0.0.0/0 DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.4:80 然后又回到了路由表、arp的操作

参考官网文档

2.Host网络

这个就比较简单了,它的网络命名空间使用的其实就是宿主机的(其他的依然是独立的,被隔离的) docker run -d -it --name busybox2 --network host busybox 此时我们查看ifconfig,是没有veth pair的设备被创建出来的,进入容器后使用ifconfig网络视图和宿主机上看到的是一模一样的。

"Containers": { "45e964d3ccf99c044f0bae5aef145e8036ecda5da7bb6dd8495a4c0ca7588a84": { "Name": "busybox2", "EndpointID": "fecfcdbf4a8324362b6e7fdda835c9ad110bd31b72254beba8e3e04ef42d33d7", "MacAddress": "", "IPv4Address": "", "IPv6Address": "" } },

3.container模式

container模式就是,多个容器使用一个容器的网络命名空间。

image.png

我们启动两个容器busybox busybox1,busybox1使用busybox的网络视图 docker run -d -it --name busybox busybox docker run -d -it --name busybox1 --network container:busybox busybox 查看一下两个容器的网络命名空间,是一模一样的。 ``` [root@localhost ~]# docker exec -it busybox sh -c 'ifconfig' eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:13 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1102 (1.0 KiB) TX bytes:0 (0.0 B)

lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

[root@localhost ~]# docker exec -it busybox1 sh -c 'ifconfig' eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:13 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1102 (1.0 KiB) TX bytes:0 (0.0 B)

lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

```

4.MacVlan(跨主机)

您的网络设备需要能够处理“混杂模式”,即一个物理接口可以分配多个 MAC 地址。

使用macvalan需要开启网卡的混杂模式,目前显然并不支持(两台主机均需要执行)

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 ```

我这里虚拟机网卡叫ens33

ifconfig ens33 promisc

看到PROMISC就代表开启了

ens33: flags=4419 mtu 1500 此时我们来创建一个驱动为macvaln的网络(两台主机均需要执行) docker network create -d macvlan \ --subnet=172.16.3.0/24 \ #必须和宿主机一个网段 --gateway=172.16.3.1 \ -o parent=ens33 sup-net #指定物理网卡名称 分别在两台主机创建一个容器

172.16.3.140

docker run -itd --name aaa --ip=172.16.3.100 --network sup-net busybox

172.16.3.141

docker run -itd --name bbb --ip=172.16.3.101 --network sup-net busybox 两个容器已经启动完成 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dbd7da305fcf busybox "sh" 22 seconds ago Up 20 seconds aaa [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 70a6f2d0a2aa busybox "sh" 38 seconds ago Up 37 seconds bbb 我们来ping一下,可以发现已经互通了 [root@localhost ~]# docker exec -it aaa sh -c 'ping 172.16.3.101' PING 172.16.3.101 (172.16.3.101): 56 data bytes 64 bytes from 172.16.3.101: seq=0 ttl=64 time=1.822 ms

反向

[root@localhost ~]# docker exec -it bbb sh -c 'ping 172.16.3.100' PING 172.16.3.100 (172.16.3.100): 56 data bytes 64 bytes from 172.16.3.100: seq=0 ttl=64 time=0.679 ms 64 bytes from 172.16.3.100: seq=1 ttl=64 time=0.621 ms ```

参考官网文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值