6

当从Pod访问百度时会用到VTEP吗

 2 years ago
source link: https://www.51cto.com/article/706243.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
当从Pod访问百度时会用到VTEP吗-51CTO.COM
当从Pod访问百度时会用到VTEP吗
作者:LanceZhang 2022-04-11 18:35:03
Netfilter conntrack 又名 CT ,译作连接跟踪。它是一个内核模块(nf_conntrack),用于维护可跟踪协议(trackable protocols)的连接状态。目前只支持以下六种协议:TCP、UDP、ICMP、DCCP、SCTP、GRE。

d7c68e991d9a3fd2e121912218a89fad649d8d.png

大家好,我是二哥。

一个公众号关注者私信问我一个问题:从 Pod 内发起的,向外网的访问过程会涉及到 VTEP 吗?涉及到的 NAT 细节是什么?

我大概整理了一下,写成此文。

写公众号大概有半年左右的时间了,写一段小感想:于我,每篇文章的选题和文章所涉及知识点的汇编、学习、整理、成文都是一个历练过程;于你,是一个恰好数分钟的的短暂停留;于我们,是一个交流的纽带。利是断然没有的,虚名会有一丁点,但那绝非我初衷。

在文章《​​tun设备的妙用-Flannel UDP模式篇​​》中,二哥借助 tun 设备,画了几张高清大图和老铁们详细聊了下 Pod 间通信时,数据流向是什么样子的,以及在这个数据流淌过程中涉及到了哪些网络设备,这些设备又是如何在各自的位置上尽心尽责地处理、搬移每一份网络包的。

那篇文章涉及到的是 Pod 间网络通信的场景。在 K8s Overlay 网络模型下,这个过程不需要对进、出 Pod 的 traffic 进行任何的 NAT。在 VXLAN 这个神器加持下,宿主机网络根本不关心、也看不到 Pod traffic 的细节,因为 traffic 都被封装起来了。

但当 Pod 想访问外网,比如 www.baidu.com 的时候,就是另外一个场景了。一是 VXLAN 在这里帮不上忙,VXLAN 是在通信双方所涉及到的 work node 上利用各自的 VTEP 分别进行封包和解包,很显然外网 remote service 不可能有这个对等的 VTEP。二是也没有必要使用 VXLAN 。

其实大家多多少少能大概猜得出来或隐约觉得这里面涉及到了 NAT 。可架不住细问,比如:

  • 一定需要NAT吗?
  • 假如要NAT的话,从 Pod a 看来,既然 NAT 涉及到对去程的网络包进行 IP 或 Port 的修改,那它势必需要记得这些连接在被修改过之前的信息,这样才能在网络包回来的时候再修改一番。那这些连接信息记录在那里呢?
  • NAT 这个过程到底发生在哪里呢?Pod 里还是宿主机上?具体是网络包流经到哪个位置发生了 NAT 呢?

先回答第一个问题:当 traffic 离开宿主机的时候不一定需要NAT。这取决于 K8s 所使用的网络模型。比如在 Underlay 模型下,就完全没有必要用到NAT, 具体内容详见二哥在《多图汇总梳理VPC与三种K8s网络模型》中的总结。但在 Overlay 模型下,NAT就很有必要了,所以本文的场景限定于 Overlay 模型。

另外,本文所讨论的 NAT 只会到 work node 这一级。我们知道从网络包离开 work node 到最终达到百度服务器,中间可能会经过若干次 NAT ,那些我们就管不着了。不过二哥在《广角-聊聊Underlay》这篇文章里,画出了数据中心网络拓扑高清大图,如果你感兴趣的话,可以打开看看。

来吧,进入正题。

Netfilter conntrack

照例,我们先从 NAT 所涉及到的基础知识开始。

Netfilter conntrack 又名 CT ,译作连接跟踪。它是一个内核模块(nf_conntrack),用于维护可跟踪协议(trackable protocols)的连接状态。目前只支持以下六种协议:TCP、UDP、ICMP、DCCP、SCTP、GRE。

既然说跟踪,得有一个或一组标记可供记录、查找、回溯。在这里 CT 利用到了每个网络包里面的源 IP ,目的 IP ,源 Port ,目的 Port 和 Protocol 这5个参数所组成的一组标记。更简单地说,CT 认为这5个参数可用来唯一标识一个单向连接。注意,这里说的是单向连接。网络通信涉及到去和回两个单向连接。

你可以用命令 conntrack -L 查看本机的 CT 记录。如下表所示,第一条记录了去、回两个方向的记录。每一个这样的记录叫做:connection tracking entry (conntrack entry)。

# conntrack -L
udp      17 172 src=127.0.0.1 dst=127.0.0.53 sport=59837 dport=53 src=127.0.0.53 dst=127.0.0.1 sport=53 dport=59837 [ASSURED] mark=0 use=1
tcp      6 5 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=35074 dport=2379 src=127.0.0.1 dst=127.0.0.1 sport=2379 dport=35074 [ASSURED] mark=0 use=1

看完了一条 conntrack entry 长什么样子,我们再来看下记录是在哪里发生的。下图中 routing + iptables of root namespace 里面,你会看到一共两处有椭圆形所标记的 conntrack 。一处是在 PREROUTING 链附近,一处是在 OUTPUT 链附近。

为什么是这两个 hook 点创建连接跟踪记录呢?因为它们都是新连接的第一个包最先达到的地方:

  • PRE_ROUTING 是外部包或者源自本机其它 network namepsace 的包最先到达的地方。从 eth0 进来的包为外部包,而从 1.5 处 cni0 bridge 进来的则为本机上其它 network namepsace 的包。
  • LOCAL_OUT 是本机通过 root network namepsace 主动与对方通信时,网络包最先到达的地方。这里的“对方”既可以是外部服务,也可以是位于本机上的,但使用的是其它 network namepsace 的进程。

当然,在LOCAL_IN和POSTROUTING处还会执行一次 confirm 操作,以确保这样一件事情:刚才所说的这个新创建的 conntrack entry ,它对应的是一条新的单向连接,这个连接的第一个包经过各种处理,一直到这里仍然健在、没有被丢弃。这并非本文重点,略过不聊。

没有特殊情况,我们可以粗略地认为前文所提 conntrack entry 在 PREROUTING 和 OUTPUT 链被成功地记录下来了,以备后用。

013d91d75df68dce57252071e08db210d377f8.png

图 1:从 Pod a 访问外网时的数据流

连接跟踪是许多网络应用的基础,例如 Kubernetes Service、ServiceMesh sidecar、 软件四层负载均衡器 LVS/IPVS、Docker network、OVS、iptables 主机防火墙等等都依赖连接跟踪功能。NAT更是离不开 CT 。

我们结合上图来看看当 Pod a 访问百度的时候,网络包流经协议栈以及在 routing table 和 iptables 共同作用下,具体发生了什么。

www.baidu.com IP 地址是 180.101.49.11 , 我们的 Pod a IP 地址为 10.244.0.2 。

1.1:从Pod a发起的请求会从 1.1 一路来到 1.5 的位置。二哥在《​​tun设备的妙用-Flannel UDP模式篇​​》里面已细聊过细节,这里就跳过去了。

1.6:当bridge将网络包递交到网络层后,网络包在 1.6 处便开始了它在 root network namespace 的新旅程。与之对应的是从 1.1 ~ 1.4 网络包还依旧只是在 Pod a 自己的 network namespace 里面转悠。在 1.5 处,网络包从一个 network namespace 跳转到了另外一个。

1.7:如前一节所述,这里的 conntrack 会记录新的连接。

1.8:经过路由选择,网络包需要从宿主机的 eth0 离开。于是走 FORWARD 链,来到 POSTROUTING 链。

1.9:现在来到了 NAT 现场。结合下面的 iptables dump,我们可以清楚地看到当源IP位于 CIDR 10.244.0.0/16 ,且不是去 docker0 这个interface ,则会进行 NAT 。将Pod a的源 IP 地址修改成了 Node 1 的 IP 地址。

1.10:开始将网络包送到链路层。

1.11:网络包从 eth0 离开宿主机。

-A POSTROUTING -s 10.244.0.0/16 ! -o docker0 -j MASQUERADE

看完 Pod 访问百度时,CT 和 NAT 的介入细节,我们再来梳理一下这位同学的问题:为什么 Pod a 访问百度时 VTEP 不会介入?

图2是文章《tun设备的妙用-Flannel UDP模式篇》的配图。它详细地标出了从 Node 1 上的 Pod a 访问 Node X 的 Pod b 时的数据流。为了方便理解,我们将 Flannel VXLAN 模式所用的 VTEP 换成了 UDP 模式所用的 tun 设备 + flannel daemon 组合。这样的更换只是把原本位于内核态的数据解、封装动作挪动到用户态的 daemon 里面来完成了,换汤不换药。

当请求从 Pod a 发起,无论是访问外网还是访问另一个 Pod,图1和图2中 1.1 ~ 1.5 这个流程是不变的。

当网络包从 1.5 处进入网络层后,网络包的去向发生了变化:

  • 如果是 Pod 间通信,网络包会经由图2中的 1.7 流动到 1.9,再完成后续的数据封包过程。
  • 与之相比,当 Pod 访问百度时,网络包在图1中 1.9 处经过 NAT 处理后,直接从 1.11 处离开了宿主机,不需要任何的封包过程,也就不需要VTEP的介入。

37d64f7237017879a92418012ed3ec3f073562.png

图 2:Pod间通信时的数据流

以上就是本文的全部内容。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK