本文是对容器网络学习的提炼总结和学习加深(以下出现的容器皆指docker容器)。详细介绍了涉及到的概念及整个流程。
本次学习得出的结论:被限制在各自Network Namespace里的容器进程,实际上是通过Veth Pair设备 + 宿主机网桥的方式实现了与其他容器的数据交换。
一些概念
网络栈:网卡(Network Interface)、回环设备(Loopback Device)、路由表(Routing Table)和 iptables 规则。对于一个进程来说这些要素构成了它发起和响应网络请求的基本环境。
每个容器都是自己的Network Namespace,而宿主机本身则是Host Namespace
网桥(Bridge):在Linux系统中起到虚拟交换机作用的网络设备,它工作在数据链路层(Data Link),主要功能是根据 MAC 地址将数据包转发到网桥的不同端口(Port)上。
ARP(Address Resolution Protocol):通过三层的 IP 地址找到对应的二层 MAC 地址的协议。
一些注意的地方
1,Docker 项目会默认在宿主机上创建一个名叫docker0的网桥,只要是连接在docker0网桥上的容器都可以通过它来进行通信。
2,容器如何“连接”到 docker0 网桥?——Veth Pair设备,两端分别连在docker0和容器上,两端彼此对应。充当网线的作用。
3,容器a访问容器b时,需要知道b的MAC地址,需要先发送ARP广播。
基础条件
在宿主机上有两个运行的容器a、b,进入到其中一个容器ifconfig,会看到有一个名为eth0的虚拟网卡;而在宿主机中ifconfig,则会看到该虚拟网卡在docker0上的名称,veth-xxxxx,此时即可称该虚拟设备被插在了docker0网桥上,另一个容器也是如此,一端在容器网络中可用看到,另一端则在docker0网桥上可以看到。
这时候,如果在a容器里 ping 一下b容器的IP地址,就会发现同一宿主机上的两个容器默认就是相互连通的。
分析之旅
a容器访问b容器,首先根据目的IP(b容器)匹配到对应的路由规则,可以看到,这条路由规则的网关(Gateway)是 0.0.0.0,这就意味着这是一条直连规则,即:凡是匹配到这条规则的 IP 包,应该经过本机的 eth0 网卡,通过二层网络直接发往目的主机。
此时就需要有 172.17.0.3 这个 IP 地址对应的 MAC 地址。所以a容器的网络协议栈,就需要通过eth0网卡发送一个 ARP 广播,通过IP地址查找对应的 MAC 地址。
如果虚拟网卡eth0插在docker0网桥上,它就会变成该网桥的“从设备”,它会被“剥夺”调用网络协议栈处理数据包的资格,从而“降级”成为网桥上的一个端口。而这个端口唯一的作用,就是接收流入的数据包,然后把这些数据包的“生杀大权”(比如转发或者丢弃),全部交给对应的网桥。
在收到这些 ARP 请求之后,docker0 网桥就会扮演二层交换机的角色,把 ARP 广播转发到其他被“插”在 docker0 上的虚拟网卡上。这样,同样连接在 docker0 上的 nginx-2 容器的网络协议栈就会收到这个 ARP 请求,从而将 172.17.0.3 所对应的 MAC 地址回复给 nginx-1 容器。有了这个目的 MAC 地址,nginx-1 容器的 eth0 网卡就可以将数据包发出去。
docker0 处理转发的过程,则继续扮演二层交换机的角色。此时,docker0 网桥根据数据包的目的 MAC 地址(也就是 nginx-2 容器的 MAC 地址),在它的 CAM 表(即交换机通过 MAC 地址学习维护的端口和 MAC 地址的对应表)里查到对应的端口(Port)为:vethb4963f3,然后把数据包发往这个端口。而这个端口,正是 nginx-2 容器“插”在 docker0 网桥上的另一块虚拟网卡,当然,它也是一个 Veth Pair 设备。这样,数据包就进入到了 nginx-2 容器的 Network Namespace 里。