node1  eth0 : 10.168.0.2
docker0 : 172.17.0.1
Container1 : 172.17.0.2
Container2 : 172.17.0.3

node2 eth0 :10.168.0.3
Container1 PING  node2 的过程

Container1 内部的准备工作

当在 Container1 内部执行 `ping 10.168.0.3` 命令时,首先会在 Container1 内部进行一系列准备工作,为后续的 ICMP 报文发送奠定基础。

(一)解析目标 IP 地址

ping 命令的参数是目标主机的 IP 地址 10.168.0.3,由于这里直接使用的是 IP 地址,而非域名,所以不需要进行 DNS 域名解析过程。Container1 直接明确了要通信的目标 IP 地址。

(二)检查本地路由表

Container1 会检查自身的路由表,以确定如何将数据包发送到目标 IP 地址 10.168.0.3。
在 Docker 容器中,默认情况下,路由表会配置一条默认路由,指向 docker0 网桥在容器网络中的地址(即 172.17.0.1)。
我们可以通过在 Container1 内部执行 `route -n` 或 `ip route show` 命令查看路由表,通常会看到类似如下的条目:`default via 172.17.0.1 dev eth0`
这条路由表示,对于不在本地子网(172.17.0.0/16,通常 Docker 容器网络的子网)内的目标 IP 地址,Container1 会将数据包发送到默认网关 172.17.0.1。
由于目标 IP 地址 10.168.0.3 不在 Container1 的本地子网(172.17.0.0/16)中,所以 Container1 会按照默认路由的指示,将 ICMP 回显请求报文发送给默认网关 172.17.0.1。

(三)获取第一目标docker0的 MAC 地址(ARP 请求)

Container1 接收到 ARP 应答报文后,会将 172.17.0.1 对应的 MAC 地址存入自身的 ARP 缓存表中,以便后续数据包的发送。

(四)、Container1 到 docker0 网桥的数据传输

在获取到默认网关 172.17.0.1 的 MAC 地址后,Container1 会构建 ICMP 回显请求报文,并通过虚拟网络接口发送到 docker0 网桥。
(1)构建 ICMP 报文
ICMP(Internet Control Message Protocol,互联网控制消息协议)是 TCP/IP 协议簇的核心协议之一,ping 命令就是基于 ICMP 协议实现的。ICMP 回显请求报文(类型 8,代码 0)的结构如下:


(2)通过虚拟网络接口发送报文
Container1 的 eth0 虚拟网络接口与 node1 上的一个虚拟网络接口(通常以 veth 开头,如 vethxxxx)通过 veth pair(虚拟以太网对)的方式连接。
当 Container1 构建好 ICMP 回显请求报文后,会将其通过自身的 eth0 虚拟网络接口发送出去。
由于 veth pair 的特性,报文会立即被发送到与之配对的 node1 内核空间的 veth 接口,然后该 veth 接口将报文转发到 docker0 网桥上。

(五)、docker0 网桥的处理与转发

docker0 网桥接收到从 Container1 发送过来的 ICMP 报文后,会进行一系列处理,并将报文转发出去。
(1)接收并检查报文
(2)检查 node1 的路由表
(3)网络地址转换(NAT)处理
由于 Container1 的 IP 地址 172.17.0.2 是 Docker 容器网络的私有 IP 地址,无法在外部网络中直接路由。为了使容器能够与外部网络通信,Docker 默认会使用源地址 NAT(SNAT)或伪装(MASQUERADE)技术,将容器发送的数据包的源 IP 地址转换为 node1 的 eth0 网卡的 IP 地址 10.168.0.2。
在 node1 的 iptables 规则中,通常会有一条针对 docker0 网桥发出的、目标为外部网络的数据包的 SNAT/MASQUERADE 规则。例如,在 nat 表的 POSTROUTING 链中,可能会有类似 `-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE` 的规则。这条规则的含义是:对于源 IP 地址属于 172.17.0.0/16 网段(即 Docker 容器网络),且不是从 docker0 网桥接口(即目标不是其他容器)发出的数据包,进行 MASQUERADE 处理,即动态地将源 IP 地址替换为 node1 发送该数据包的出口网卡(这里是 eth0)的 IP 地址 10.168.0.2。
因此,当 ICMP 数据报经过 node1 的 iptables NAT 处理时,其源 IP 地址会从 172.17.0.2 被转换为 10.168.0.2,同时,node1 会在连接跟踪(conntrack)表中记录这个 NAT 转换关系,以便后续能够正确地将从 node2 返回的 ICMP 回显应答报文转发给 Container1。

(六)构建新的以太网帧头并发送

经过 NAT 处理后,node1 会为 IP 数据报重新构建以太网帧头。此时,源 MAC 地址为 node1 的 eth0 网卡的 MAC 地址,目标 MAC 地址需要是 node2 的 eth0 网卡的 MAC 地址。为了获取 node2 的 MAC 地址,node1 会在本地 ARP 缓存表中查找。如果 node1 的 ARP 缓存表中没有 10.168.0.3 对应的 MAC 地址,node1 会发送 ARP 请求报文。

(七)、物理网络中的传输

node1 的 eth0 网卡发送出的以太网帧会通过物理网络(如交换机、网线等)传输到 node2 的 eth0 网卡。
在这个过程中,物理网络设备(如交换机)会根据以太网帧的目标 MAC 地址进行转发。
由于 node1 和 node2 处于同一局域网,交换机的 MAC 地址表中会记录 node2 的 eth0 网卡 MAC 地址对应的端口,因此交换机会将该以太网帧直接转发到连接 node2 的端口,最终到达 node2 的 eth0 网卡。

(八)、node2 对 ICMP 请求报文的处理

node2 的 eth0 网卡接收到来自 node1 的以太网帧后,会进行一系列处理,并生成 ICMP 回显应答报文。
(一)接收并检查报文
node2 的 eth0 网卡接收到以太网帧后,会检查目标 MAC 地址是否为自身的 MAC 地址。如果是,node2 会接收该帧,并剥离以太网帧头,将 IP 数据报传递给内核网络协议栈进行处理。
(二)IP 层处理
node2 的内核网络协议栈会检查 IP 数据报的目标 IP 地址是否为自身的 IP 地址之一(这里是 10.168.0.3)。确认后,会检查 IP 首部的校验和,若校验通过,则查看协议字段,发现是 1(ICMP),于是将 IP 数据报的数据部分(即 ICMP 报文)传递给 ICMP 协议处理。
(三)ICMP 层处理
ICMP 协议处理模块接收到 ICMP 报文后,会检查其类型和代码字段,发现是类型 8(回显请求)、代码 0 的报文。然后,ICMP 模块会验证 ICMP 报文的校验和,确认无误后,会生成 ICMP 回显应答报文(类型 0,代码 0)。
(四)构建 IP 数据报和以太网帧
node2 会为 ICMP 回显应答报文构建 IP 数据报,并根据目标 IP 地址 10.168.0.2 检查自身的路由表。node2 的路由表中会有关于 10.168.0.0/24 网段的直接连接路由,因此确定通过 eth0 网卡将应答报文发送出去。
接下来,node2 需要获取目标 IP 地址 10.168.0.2 对应的 MAC 地址。node2 会检查自身的 ARP 缓存表

总结:

跨节点的容器和宿主机的通信原理:
1  解析目标IP 地址
2  检查本地路由表 
3  获取容器所在节点docker0的mac地址
4 container1 通过eth0发送ICMP报文到docker0 网桥 
5 docker0网桥接收并检查报文,检查node1的路由表
6 docker0网桥做网络地址转换处理 nat
7 构建新的以太网帧头
8  发送arp请求,获取node2的mac地址,将数据包发送到node2
9 node2 接收到以太网帧后,检查mac,剥离以太网帧头,得到IP数据报
10 node2 内核网络协议栈 检查IP,去掉IP头,得到ICMP报文
11 node2 ICMP协议栈 检查类型和代码后,生成ICMP回显报文
12 node2返回报文给node1的container1(回显报文:加IP头
13 IP报文: 加icmp头
14 icmp报文 : 加以太网帧头
15 网络传输到node1
16 node1 的eth0接收数据包 
17 根据路由规则,数据包发送到docker0
18 从docker0 发送到容器的eth0)

更多推荐