关于docker:Docker容器网络实现篇

50次阅读

共计 3884 个字符,预计需要花费 10 分钟才能阅读完成。

后面介绍了:Docker 容器网络 - 根底篇

前文说到容器网络对 Linux 虚拟化技术的依赖,这一篇章咱们将一探到底,看看 Docker 到底是怎么做的。通常,Linux 容器的网络是被隔离在它本人的 Network Namespace 中,其中就包含:网卡(Network Interface)、回环设施(Loopback Device)、路由表(Routing Table)和 iptables 规定。对于一个过程来说,这些因素,就形成了它发动和响应网络申请的根本环境。

管中窥豹

咱们在执行 docker run -d --name xxx 之后,进入容器外部:

## docker ps 可查看所有 docker
## 进入容器
docker exec -it 228ae947b20e /bin/bash

并执行 ifconfig:

$ ifconfig
eth0 Link encap:Ethernet HWaddr 22:A4:C8:79:DD:1A
 inet addr:192.168.65.28 Bcast:

咱们看到一张叫 eth0 的网卡,它正是一个 Veth Pair 设施在容器的这一端。

咱们再通过 route 查看该容器的路由表:

$ route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use If

咱们能够看到这个 eth0 是这个容器的默认路由设施。咱们也能够通过第二条路由规定,看到所有对 169.254.1.1/16 网段的申请都会交由 eth0 来解决。

而 Veth Pair 设施的另一端,则在宿主机上,咱们同样也能够通过查看宿主机的网络设备来查看它:

$ ifconfig
......
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
 inet 172.16.241.192 netmask 255.255.240.0 broadcast 172.16.255.255
 ether 00:16:3e:0a:f3:75 txqueuelen 1000 (Ethernet)
 RX packets 3168620550 bytes 727592674740 (677.6 GiB)
 RX errors 0 dropped 0 overruns 0 frame 0
 TX packets 2937180637 bytes 8661914052727 (7.8 TiB)
 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
......
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
 ether 02:42:16:58:92:43 txqueuelen 0 (Ethernet)
 RX packets 0 bytes 0 (0.0 B)
 RX errors 0 dropped 0 overruns 0 frame 0
 TX packets 0 bytes 0 (0.0 B)
 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
......
vethd08be47: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
 ether 16:37:8d:fe:36:eb  txqueuelen 0 (Ethernet)
 RX packets 193 bytes 22658 (22.1 KiB)
 RX errors 0 dropped 0 overruns 0 frame 0
 TX packets 134 bytes 23655 (23.1 KiB)
 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
......

在宿主机上,容器对应的 Veth Pair 设施是一张虚构网卡,咱们再用 brctl show 命令查看网桥:

$ brctl show
bridge name    bridge id        STP enabled    interfaces
docker0 8000.0242afb1a841 no vethd08be47

能够分明的看到 Veth Pair 的一端 vethd08be47 就插在 docker0 上。

我当初执行 docker run 启动两个容器,就会发现 docker0 上插入两个容器的 Veth Pair 的一端。如果咱们在一个容器外部相互 ping 另外一个容器的 IP 地址,是不是也能 ping 通?

$ brctl show
bridge name    bridge id        STP enabled    interfaces
docker0 8000.0242afb1a841 no veth26cf2cc
 veth8762ad2

容器 1:

$ docker exec -it f8014a4d34d0 /bin/bash
$ ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:0

容器 2:

$ docker exec -it 9a6f38076c04 /bin/bash
$ ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:0

从一个容器 ping 另外一个容器:

# -> 容器 1 外部 ping 容器 2
$ ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17

咱们看到,在一个容器外部 ping 另外一个容器的 ip,是能够 ping 通的。也就意味着,这两个容器是能够相互通信的。

容器通信

咱们无妨联合前文时所说的,了解下为什么一个容器能拜访另一个容器?先简略看如一幅图:

当在容器 1 里拜访容器 2 的地址,这个时候目标 IP 地址会匹配到容器 1 的第二条路由规定,这条路由规定的 Gateway 是 0.0.0.0,意味着这是一条直连规定,也就是说但凡匹配到这个路由规定的申请,会间接通过 eth0 网卡,通过二层网络发往目标主机。而要通过二层网络达到容器 2,就须要 127.17.0.3 对应的 MAC 地址。所以,容器 1 的网络协议栈就须要通过 eth0 网卡来发送一个 ARP 播送,通过 IP 找到 MAC 地址。

所谓 ARP(Address Resolution Protocol),就是通过三层 IP 地址找到二层的 MAC 地址的协定。这里说到的 eth0,就是 Veth Pair 的一端,另一端则插在了宿主机的 docker0 网桥上。eth0 这样的虚构网卡插在 docker0 上,也就意味着 eth0 变成 docker0 网桥的“从设施”。从设施会降级成 docker0 设施的端口,而调用网络协议栈解决数据包的资格全副交给 docker0 网桥。

所以,在收到 ARP 申请之后,docker0 就会表演二层交换机的角色,把 ARP 播送发给其它插在 docker0 网桥的虚构网卡上,这样,127.17.0.3 就会收到这个播送,并把其 MAC 地址返回给容器 1。有了这个 MAC 地址,容器 1 的 eth0 的网卡就能够把数据包发送进来。这个数据包会通过 Veth Pair 在宿主机的另一端 veth26cf2cc,间接交给 docker0。

docker0 转发的过程,就是持续表演二层交换机,docker0 依据数据包的指标 MAC 地址,在 CAM 表查到对应的端口为 veth8762ad2,而后把数据包发往这个端口。而这个端口,就是容器 2 的 Veth Pair 在宿主机的另一端,这样,数据包就进入了容器 2 的 Network Namespace,最终容器 2 将响应(Ping)返回给容器 1。在实在的数据传递中,Linux 内核 Netfilter/Iptables 也会参加其中,这里不再赘述。

CAM 就是交换机通过 MAC 地址学习保护端口和 MAC 地址的对应表

这里介绍的容器间的通信形式就是 docker 中最常见的 bridge 模式,当然此外还有 host 模式、container 模式、none 模式等,对其它模式有趣味的能够去浏览相干材料。

跨主通信

好了,这里不禁问个问题,到目前为止只是单主机外部的容器间通信,那跨主机网络呢?在 Docker 默认配置下,一台宿主机的 docker0 网桥是无奈和其它宿主机连通的,它们之间没有任何关联,所以这些网桥上的容器,天然就没方法多主机之间相互通信。然而无论怎么变动,情理都是一样的,如果咱们创立一个公共的网桥,是不是集群中所有容器都能够通过这个公共网桥去连贯?

当然在失常的状况下,节点与节点的通信往往能够通过 NAT 的形式,然而,这个在互联网倒退的明天,在容器化环境下未必实用。例如在向注册核心注册实例的时候,必定会携带 IP,在失常物理机内的利用当然没有问题,然而容器化环境却未必,容器内的 IP 很可能就是上文所说的 172.17.0.2,多个节点都会存在这个 IP,大概率这个 IP 是抵触的。

如果咱们想防止这个问题,就会携带宿主机的 IP 和映射的端口去注册。然而这又带来一个问题,即容器内的利用去意识到这是一个容器,而非物理机,当在容器内,利用须要去拿容器所在的物理机的 IP,当在容器外,利用须要去拿以后物理机的 IP。显然,这并不是一个很好的设计,这须要利用去配合配置。所以,基于此,咱们必定要寻找其余的容器网络解决方案。


在上图这种容器网络中,咱们须要在咱们已有的主机网络上,通过软件构建一个笼罩在多个主机之上,且能把所有容器连通的虚构网络。这种就是 Overlay Network(笼罩网络)。

对于这些具体的网络解决方案,例如 Flannel、Calico 等,我会在后续篇幅持续陈说。

_链接:https://www.cnblogs.com/sally…
作者 Mr_Zack_



正文完
 0