「网络拓扑」Kubernetes 网络模型来龙去脉( 二 )

  • 第三个是通道 , 即两个主机之间通过什么方式完成包的传输 。 我们有很多种方式 , 比如以路由的方式 , 具体又可分为 BGP 路由或者直接路由 。 还有各种各样的隧道技术等等 。 最终我们实现的目的就是一个容器内的包通过容器 , 经过接入层传到宿主机 , 再穿越宿主机的流控模块(如果有)到达通道送到对端 。
3. 一个最简单的路由方案:Flannel-host-gw这个方案采用的是每个 Node 独占网段 , 每个 Subnet 会绑定在一个 Node 上 , 网关也设置在本地 , 或者说直接设在 cni0 这个网桥的内部端口上 。 该方案的好处是管理简单 , 坏处就是无法跨 Node 迁移 Pod 。 就是说这个 IP、网段已经是属于这个 Node 之后就无法迁移到别的 Node 上 。
「网络拓扑」Kubernetes 网络模型来龙去脉
本文插图
这个方案的精髓在于 route 表的设置 , 如上图所示 。 接下来为大家一一解读一下 。
  • 第一条很简单 , 我们在设置网卡的时候都会加上这一行 。 就是指定我的默认路由是通过哪个 IP 走掉 , 默认设备又是什么;
  • 第二条是对 Subnet 的一个规则反馈 。 就是说我的这个网段是 10.244.0.0 , 掩码是 24 位 , 它的网关地址就在网桥上 , 也就是 10.244.0.1 。 这就是说这个网段的每一个包都发到这个网桥的 IP 上;
  • 第三条是对对端的一个反馈 。 如果你的网段是 10.244.1.0(上图右边的 Subnet) , 我们就把它的 Host 的网卡上的 IP (10.168.0.3) 作为网关 。 也就是说 , 如果数据包是往 10.244.1.0 这个网段发的 , 就请以 10.168.0.3 作为网关 。
再来看一下这个数据包到底是如何跑起来的?
假设容器 (10.244.0.2) 想要发一个包给 10.244.1.3 , 那么它在本地产生了 TCP 或者 UDP 包之后 , 再依次填好对端 IP 地址、本地以太网的 MAC 地址作为源 MAC 以及对端 MAC 。 一般来说本地会设定一条默认路由 , 默认路由会把 cni0 上的 IP 作为它的默认网关 , 对端的 MAC 就是这个网关的 MAC 地址 。 然后这个包就可以发到桥上去了 。 如果网段在本桥上 , 那么通过 MAC 层的交换即可解决 。
这个例子中我们的 IP 并不属于本网段 , 因此网桥会将其上送到主机的协议栈去处理 。 主机协议栈恰好找到了对端的 MAC 地址 。 使用 10.168.0.3 作为它的网关 , 通过本地 ARP 探查后 , 我们得到了 10.168.0.3 的 MAC 地址 。 即通过协议栈层层组装 , 我们达到了目的 , 将 Dst-MAC 填为右图主机网卡的 MAC 地址 , 从而将包从主机的 eth0 发到对端的 eth0 上去 。
所以大家可以发现 , 这里有一个隐含的限制 , 上图中的 MAC 地址填好之后一定是能到达对端的 , 但如果这两个宿主机之间不是二层连接的 , 中间经过了一些网关、一些复杂的路由 , 那么这个 MAC 就不能直达 , 这种方案就是不能用的 。 当包到达了对端的 MAC 地址之后 , 发现这个包确实是给它的 , 但是 IP 又不是它自己的 , 就开始 Forward 流程 , 包上送到协议栈 , 之后再走一遍路由 , 刚好会发现 10.244.1.0/24 需要发到 10.244.1.1 这个网关上 , 从而到达了 cni0 网桥 , 它会找到 10.244.1.3 对应的 MAC 地址 , 再通过桥接机制 , 这个包就到达了对端容器 。
大家可以看到 , 整个过程总是二层、三层 , 发的时候又变成二层 , 再做路由 , 就是一个大环套小环 。 这是一个比较简单的方案 , 如果中间要走隧道 , 则可能会有一条 vxlan tunnel 的设备 , 此时就不填直接的路由 , 而填成对端的隧道号 。
Service 究竟如何工作
Service 其实是一种负载均衡 (Load Balance) 的机制 。
我们认为它是一种用户侧(Client Side) 的负载均衡 , 也就是说 VIP 到 RIP 的转换在用户侧就已经完成了 , 并不需要集中式地到达某一个 NGINX 或者是一个 ELB 这样的组件来进行决策 。


推荐阅读