近期在复习容器网络的相关知识,将单机容器网络到跨主机网络通信的实现方法做以总结。
这里是第一篇,后面还会发布其他笔记:
不同容器具有不同namespace,位于同一个宿主机上的不同容器进行通信时,相当于不同namespace之间通信,需要借助一个设备将二者联系起来,docker0网桥就有这个作用,有了docker0网桥,还需要与容器联系起来, 我们就需要虚拟设备 veth pair,Veth Pair 常常被用作连接不同 Network Namespace 的“网线”,一端在容器上,一端插在网桥上,docker0网桥位于宿主机的名称空间内,与容器的名称空间分隔开来。
现考虑以下两个场景下的数据包传输过程:
1:当宿主机上的进程需要访问容器container1内应用时,数据包传输过程如下图中红色线条所示:数据包先到达宿主机名称空间内的docker0上,然后再转发到对应的veth pair设备上,最后出现在目标容器上。
同时docker0在转发过程中,还扮演了二层交换机的角色,docker0 网桥根据数据包的目的 MAC 地址,在它的 CAM 表(即交换机通过 MAC 地址学习维护的端口和 MAC 地址的对应表)里查到对应的端口,然后把数据包发往这个端口。这就是为什么docker0不会把数据包转发给container2对应的veth pair设备。也正是因为docker0可以作为二层交换机的这个原因,使得同一宿主机上的两个容器默认就是相互连通的(联想二层网络里的各个主机之间的通信,只要发送ARP报文就知道对方MAC地址了)。
这里所述的端口就是Veth pair设备插到docker0上的那一端,由于一旦一张虚拟网卡被“插”在网桥上,它就会变成该网桥的“从设备”。从设备会被“剥夺”调用网络协议栈处理数据包的资格,从而“降级”成为网桥上的一个端口。而这个端口唯一的作用,就是接收流入的数据包,然后把这些数据包的“生杀大权”(比如转发或者丢弃),全部交给对应的网桥。
2:当宿主机X上的容器需要访问宿主机Y上的应用时,数据包传输过程如下图中绿色线条所示:
数据包首先根据路由规则出现在Docker0网桥上,然后根据宿主机的路由表规则,将数据包给宿主机的eth0网卡设备,然后数据包经过Node X的eth0设备的转发到达Node Y上。但这个需要两个节点是能够通信的,因此在发现宿主机容器联不通外网时,应该先检查,容器和Docker0网桥是否正常通信,再检查docker0和veth pair相关的iptables规则是否设置错误。
容器要想跟外界进行通信,它发出的 IP 包就必须从它的 Network Namespace 里出来,来到宿主机上。而解决这个问题的方法就是:为容器创建一个一端在容器里充当默认网卡、另一端在宿主机上的 Veth Pair 设备。
后记:本文是学习课程极客时间-张磊:《深入剖析Kubernetes》进行的总结笔记。