关于istio:全网最细-深度解析-Istio-Ambient-Mesh-流量路径

4次阅读

共计 13774 个字符,预计需要花费 35 分钟才能阅读完成。

前言

Istio Ambient Mesh 是 Istio 社区的推出的将 Sidecar 的能力抽离至 ztunnel 和 waypoint 的全新架构,同时基于 iptables 和策略路由实现了该架构下的流量规定,目前网络上曾经有些材料对这部分的实现进行了肯定水平的分析(比方 http://Solo.io 推出的三篇系列文章),但依然有很多细节尚没有任何文章提及。本文旨在对 Istio Ambient Mesh 的流量门路进行具体解读,力求尽可能清晰地出现细节,以帮忙读者齐全了解 Istio Ambient Mesh 中最为要害的局部。浏览本文须要读者具备根本的 TCP/IP 协定常识和操作系统网络常识,包含 iptables 和路由等。鉴于篇幅限度,本文不会具体介绍这些根底概念,对于感兴趣的读者,倡议自行查阅相干材料以深刻理解。

环境

咱们应用一个最简化的场景来阐明 Ambient Mesh 流量门路:从一个运行在 Node-A 上的 sleep Pod 中通过 curl 发动一个 HTTP 申请,申请的对象是集群中名为 httpbin 的服务。在该服务下有一个位于 Node-B 上的 httpbin Pod,因为服务(ClusterIP)在 K8s 中只是一个虚构的 IP(它并不是任何实在存在的网络设备地址),所以在这个场景中,这个申请是间接发往 httpbin 利用 Pod 的,该场景的网络门路看起来会像是这样:

然而,在 Ambient Mesh 流量规定的影响下,实际上从 sleep Pod 收回的数据包须要经验一系列 iptables、策略路由被转发至 ztunnel 或 waypoint 之后能力达到对端的 httpbin 利用当中。这里为了在后续的篇幅中便于形容,咱们须要先介绍一下在这一流程中的所有参与者,读者无需记住这些设施的地址和名称,此处列出只是为了不便查阅:

残缺流量门路

sleep -> httpbin 的申请门路尽管看起来非常简略,然而在 Ambient Mesh 下,ztunnel 接管了所有的出入连贯,从 sleep pod 收回的 ip 包都会被劫持到 ztunnel 的 15001 端口,通过 ztunnel 加密后再收回,所以事实上 sleep pod 中执行的 curl 发动的连贯实际上是连贯到了 ztunnel Pod 中的协定栈,同样地,httpbin Pod 接管到的连贯实际上则是来自它所在 Node 上运行的 ztunnel,所以理论建设的 TCP 连贯有 3 条:

  • sleep -> NodeA ztunnel
  • NodeA ztunnel -> NodeB ztunnel
  • NodeB ztunnel -> httpbin

因为 Ambient Mesh 是 4 层通明设计,尽管两头通过了 ztunnel 或是 waypoint proxy 的转发,但无论是 sleep Pod 中的 curl 利用还是 httpbin pod 中的 httpbin 利用都无奈感知到两头代理的存在。为了达到这个目标,数据包在很多环节无奈间接通过 DNAT 及 SNAT 进行转发,因为 DNAT 和 SNAT 动作会批改数据包的源 / 指标信息,Ambient Mesh 设计的这些规定很大水平是为了贯彻两端都通明的传输门路,为了可能对每一部分逐个解说,咱们须要再将上图进一步细化:

咱们来解读一下这张图,笔者将整个门路分为三大部分,第一部分为 curl 到 ztunnelA,用红色连线示意;第二局部为 ztunnelA 到 ztunnelB,用蓝色线示意;第三局部为 ztunnelB 到 httpbin,用黄色线示意。此外,线的类型分为两种,两端没有箭头的连线示意这些设施是间接连贯的,即数据包从这一头进入,就会从另一头进去,尽管两台宿主机 eth0 设施的连贯形式与 Pod 和宿主机的连贯形式不同,但这并不是本文的重点,咱们也视为它是直连的即可,本文重点将解释有箭头的连线,对下面分进去的三局部门路逐个剖析,说明数据包在这部分门路上是如何被转发的。

第一局部:curl 到 ztunnel-A

当咱们运行 curl 发送申请时,curl 向 httpbin 服务发动连贯,通过 DNS 解析后,咱们的连贯指标是 httpbin 服务的 ClusterIP(而不是 Pod),在 K8s 集群中,发往 Cluster IP 的数据包会被一系列 iptables 规定将指标地址转化为 PodIP 而后通过宿主机收回,然而 在 Ambient Mesh 中,则须要先通过 ztunnel 加密后再收回,本节咱们就先来看看数据包是怎么被路由到 ztunnel Pod 中的 ztunnel 过程的。

1)Sleep NS -> Node-A NS

因为 sleep Pod 中只有一个网络设备 eth0,它是 pod 的 veth pair 在 pod 网络命名空间内的一端,它的对端是宿主机网络命名空间里的 vethbda3de4b 设施,pod 与内部的所有网络通信无论是上下行都经由这个通道进行收发。在 Sidecar 模式下,为了将流量重定向到 Sidecar,pod 网络命名空间内有一系列 iptables 规定,然而在 Ambient 模式下,因为 Pod 内不再注入 Sidecar,所以 Pod 网络命名空间不再有任何 iptables 规定,所以这一阶段的流量门路与个别 K8s pod 无异,从该 Pod 网络协议栈收回的数据包,将都通过 Pod 惟一的网络设备 eth0 收回,而后从宿主机端的 veth 设施达到宿主机的网络命名空间。

2)Node-A NS -> ztunnelA NS

首个上行数据包

数据包达到宿主机后须要被重定向至 ztunnel,然而这个门路上的首个数据包(TCP 的握手数据包)将和前面的数据包经由不同的门路被转发至 ztunnel,咱们先从首个数据包开始。因为 sleep pod 中 curl 发动连贯的对象是 httpbin 服务,通过 DNS 解析,其真正连贯的指标是 httpbin 服务的 ClusterIP,所以,sleep pod 协定栈收回的三层数据包的源地址和指标地址将会是这样的:

K8s 为服务路由配置了 iptables 规定,以将服务地址 DNAT 为具体的 Endpoint 地址,为了跳过这个逻辑将数据包重定向到 ztunnel,Ambient Mesh CNI 为宿主机在 K8s 的规定之前增加了一些 iptables 规定和路由规定。数据包从 sleep pod 的 veth 达到宿主机后,开始执行 PREROUTING 链,咱们来看一下 PREROUTING 链中的内容:

=== PREROUTING ===
    --- raw ---
    --- mangle ---
        -A PREROUTING -j ztunnel-PREROUTING
    --- nat ---
        -A PREROUTING -j ztunnel-PREROUTING
        -A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
        -A PREROUTING -d 172.18.0.1/32 -j DOCKER_OUTPUT

能够看到,Istio Ambient Mesh 在 mangle 表和 nat 表中退出了规定,强制跳转到 ztunnel-PREROUTING 链解决,因为是无条件跳转到 ztunnel-PREROUTING 链,所以非 Ambient Mesh 的 Pod 收回的数据包也会跳转到这个链解决,为了防止将网分外的 Pod 的流量谬误地重定向到 ztunnel,在 Pod 启动时,Ambient Mesh 的 CNI 会对其进行断定,若断定后果为启用 Ambient,则会将这个 Pod 的 IP 退出到宿主机网络命名空间下名为 ztunnel-pods-ips 的 ipset 中。在本文的场景中,sleep Pod 将被退出 Node-A 上名为 ztunnel-pods-ips 的 ipset,所以来自 sleep Pod 的数据包将命中 ztunnel-PREROUTING 链中的下列规定:(规定省略了与以后阶段无关的内容):

=== ztunnel-PREROUTING ===
    --- raw ---
    --- mangle ---
        ......
        -A ztunnel-PREROUTING -p tcp -m set --match-set ztunnel-pods-ips src -j MARK --set-xmark 0x100/0x100
    --- nat ---
        -A ztunnel-PREROUTING -m mark --mark 0x100/0x100 -j ACCEPT
    --- filter ---

在执行 mangle 表阶段,因为数据包的源地址(sleep Pod 地址)在 ztunnel-pods-ips 内,所以这条规定匹配胜利,数据包将被打上 0x100 标记,打上 0x100 标记的数据包将在随后的 nat 表阶段间接被承受,这就使得数据包跳过了 K8s iptables 规定的解决。到目前为止,规定只是为数据包打上了一个标记,数据包的指标地址没有产生任何扭转,要扭转数据包的路由,还须要借助路由表来实现。PREROUTING 完结后,数据包会进入路由阶段,因为数据包被打上了 0x100 标记,所以在策略路由阶段,将会命中如下规定(省略了无关规定):

......
101:    from all fwmark 0x100/0x100 lookup 101
......

命中这条策略路由规定后,将对该数据包应用路由表 101,咱们再来看一下 101 路由表的内容:

default via 192.168.127.2 dev istioout 
10.244.2.3 dev veth51e3b96d scope link

因为数据包的指标地址是 httpbin 服务的 Cluster IP,在本文应用的演示环境中,httpbin 服务的 Cluster IP 为 10.96.0.105,所以将命中这个路由表中的默认规定,这条规定的意思是:通过 istioout 设施发往网关 192.168.127.2。而 istioout 设施是一个 bridge 设施,其另一端就是 ztunnel Pod 内的 pistioout 设施,其地址便是 192.168.127.2,数据包利用这条路由规定后,将通过 istioout 设施来到宿主机,而后从 pistioout 达到 ztunnel Pod 网络命名空间。

数据包通过 pistioout 达到 ztunnel Pod 网络命名空间后,因为数据包的指标地址并非 ztunnel Pod 中的任何网络设备,所以如果不进行任何干涉,这个数据包将被 ztunnel Pod 的协定栈抛弃。ztunnel 过程的 outbound 代理监听在 15001 端口上,为了将数据包正确地送达该端口,在 ztunnel Pod 内也设置了一些 iptables 规定和路由规定,数据包达到 ztunnel Pod 网络命名空间后,将命中如下规定:

=== PREROUTING ===
    --- raw ---
    --- mangle ---
        ......
        -A PREROUTING -i pistioout -p tcp -j TPROXY --on-port 15001 --on-ip 127.0.0.1 --tproxy-mark 0x400/0xfff
        ......
    --- nat ---
    --- filter ---

这条规定将从 pistioout 设施进入的数据包的指标地址重定为 127.0.0.1 的 15001 端口上,并为数据包打上 0x400 的标识,须要留神的是,这里尽管重定向了指标地址,然而 tproxy 会保留数据包的原始指标地址,应用程序能够通过 getsockopt 的 SO_ORIGINAL_DST 选项取得数据包的原始指标地址。iptables 规定执行结束后,将执行策略路由,数据包将命中如下策略路由规定:

20000:  from all fwmark 0x400/0xfff lookup 100

该策略路由指定应用 100 路由表进行路由,咱们再看一下 100 路由表的内容:

local default dev lo scope host

100 路由表只有一条规定,即通过 lo 设施发往本机协定栈,至此数据包进入 ztunnel Pod 本机协定栈,因为在 iptables 中将数据包重定向到 127.0.0.1:15001,所以数据包最终达到 ztunnel 过程监听的 15001 端口,从 curl 到 ztunnel 过程的首个数据包的门路曾经梳理结束:

上行数据包

这一阶段的回程数据包也有一些特地的规定解决,当回程数据包通过 ztunnel 在宿主机上的 veth 进入宿主机时,它将命中如下规定:

-A ztunnel-PREROUTING ! -s 10.244.2.3/32 -i veth51e3b96d -j MARK --set-xmark 0x210/0x210
-A ztunnel-PREROUTING -m mark --mark 0x200/0x200 -j RETURN

这条规定的意义是:数据包不是来自 ztunnel Pod IP,然而却是从 ztunnel Pod 的 veth 进入宿主机的,就打上 0x210 标记。

为什么是这样的条件呢?因为 ztunnel 事实上是一个通明代理,也就是说 ztunnel 是在表演对端的指标服务回复数据包,所以数据包中的源地址是对端服务地址,而不是 ztunnel Pod 的地址。

随后,因为数据包被打上了 0x210 标记,在路由阶段将命中宿主机上的如下策略路由规定。

100:    from all fwmark 0x200/0x200 goto 32766
......
32766:  from all lookup main

该路由规定批示通过 main 路由表进行路由,回程数据包的地址是 sleep Pod 地址,即 10.244.2.8,将命中 main 路由表中由 K8s 网络增加的规定:

10.244.2.8 dev vethbda3de4b scope host

该规定将数据包路由到 vethbda3de4b 设施,vethbda3de4b 是 sleep Pod 在宿主机端的 veth 设施,进入该设施的数据包将通过 sleep Pod 内的 eth0 设施进入 sleep Pod。

到这里还没有完结,确定路由后,因为该数据包的指标地址并非本机,所以将再执行 iptables FORWARD 链,在 FOWARD 链的 mangle 表中有如下规定:

-A FORWARD -j ztunnel-FORWARD

同样是无条件跳转到 ztunnel-FORWARD 链,在 ztunnel-FORWARD 链中,因为数据包带有 0x210 标识,将命中如下规定:

-A ztunnel-FORWARD -m mark --mark 0x210/0x210 -j CONNMARK --save-mark --nfmask 0x210 --ctmask 0x210

该规定将数据包上的标记保留到连贯上,至此,这条连贯上同样保留了 0x210 标记,属于该连贯的数据包通过宿主机时,通过连贯标记 0x210 将能够匹配到这条连贯上的后续所有数据包。

后续上行数据包

因为第一个回复数据包会使得这条连贯被打上 0x210 标记,后续再从 sleep Pod veth 进入宿主机的上行数据包将在 PREROUTING 阶段命中如下规定:

-A ztunnel-PREROUTING ! -i veth51e3b96d -m connmark --mark 0x210/0x210 -j MARK --set-xmark 0x40/0x40

能够看到,这里通过 iptables 的 connmark 模块匹配连贯标记,而后为该数据包再打上 0x40 标记,打上 0x40 标记的数据包将在随后的路由阶段命中如下规定:

102:    from all fwmark 0x40/0x40 lookup 102

随后应用 102 路由表进行路由:

default via 10.244.2.3 dev veth51e3b96d onlink
10.244.2.3 dev veth51e3b96d scope link

该路由表是 Ambient Mesh 创立的向 ztunnel Pod 路由的规定,因为数据包的指标地址是 httpbin 服务的 ClusterIP,所以这一阶段将命中 102 路由表中的默认路由规定,通过 veth51e3b96d 设施发往 ztunnel Pod。数据包进入 veth51e3b96d 设施后,会从 ztunnel Pod 的 eth0 设施进入 ztunnel Pod 网络命名空间,并命中如下 iptables 规定:

-A PREROUTING ! -d 10.244.2.3/32 -i eth0 -p tcp -j MARK --set-xmark 0x4d3/0xfff

该规定的条件是,如果数据包的指标地址不是 ztunnel Pod 地址,且从 eth0 设施进入,且协定为 TCP,则为数据包打上 0x4d3 标识,打上该标识后,数据包将在路由阶段命中如下规定:

20003:  from all fwmark 0x4d3/0xfff lookup 100

命中该策略路由后,将应用 100 路由表:

local default dev lo scope host

该路由表将数据包路由至 lo 设施,强制送入本机协定栈。

总结

咱们来简略总结一下,在从 Node-A 到 ztunnel 的这一阶段,首个数据包是从 istioout 接口来到宿主机,pistioout 接口进入 ztunnel Pod,而后续数据包因为连贯打上了 0x210 标记的缘故,将通过 ztunnel Pod 的 veth 设施来到宿主机,再从 ztunnel Pod 的 eth0 设施进入 ztunnel Pod。

第二局部:ztunnel-A 到 ztunnel-B

数据包达到 ztunnel 后,会进行 4 层负载平衡,对于这一部分能够参考我的这篇文章 [1]。通过 4 层负载平衡之后,ztunnel 将指标服务 IP 转换为 Pod IP,因为零信赖平安设计的缘故,ztunnel 须要先将数据转发给这个 Pod IP 所在节点的 ztunnel 而不是指标 Pod。Ambient Mesh 对于这一点的设计是,ztunnel 收回的数据包的指标地址是指标 Pod(也就是 httpbin Pod)的地址,这样以来就能够利用 K8s 的路由规定,使得这个数据包达到指标 Pod 所在的宿主机,在对端宿主机上,再通过一系列规定,将这个数据包路由到 ztunnel Pod,那么接下来这一节咱们就来看看这条门路是如何实现的。

1)ztunnel-A Networking Namespace -> Node-A Networking Namespace

通过 4 层负载平衡,ztunnel 将向对端 Pod 的 15008 端口发动连贯,之所以应用 15008 端口(而不是服务端口或者后端 Pod 端口)的起因是在对端 ztunnel 的 iptables 规定匹配时这个端口被用作了匹配条件,细节在第三局部将会探讨。ztunnel 收回的数据包首先须要从 ztunnel Pod 达到宿主机以便通过宿主机转发到对端 Node,ztunnel Pod 与 sleep Pod 一样,也有一对 veth pair 与宿主机连贯,在 ztunnel Pod 网络命名空间下的设施名为 eth0,进入该设施的数据包会从宿主机端的 veth 设施进入宿主机网络命名空间,ztunnel 收回的数据包指标地址为 httpbin Pod 的地址,并且不会命中任何 ztunnel Pod 内的 iptables 规定,在路由阶段,该数据包将命中默认路由规定,将数据包通过 eth0 发往宿主机。

2)Node-A -> Node-B

数据包达到 NodeA 后,因为其指标地址是 httpbin Pod 的 IP 地址(10.244.1.17),所以将命中 K8s 在 main 路由表中增加的针对 pod 网段路由规定:

......
10.244.1.0/24 via 172.18.0.4 dev eth0
......

该规定表明去往 10.244.1.0/24 网段的数据包通过 eth0 设施发往网关 172.18.0.4(Node-B 地址),ztunnel Pod 收回的数据包为 httpbin Pod 地址 10.244.1.7,所以将命中这条规定,通过 eth0 设施来到 Node-A 去往 Node-B,最初通过 NodeB 的 eth0 设施进入 NodeB 网络命名空间:

3)Node-B Networking Namespace -> ztunnel-B Networking Namespace

首个上行数据包

在 Inbound 阶段的节点到 ztunnel 的门路上,与 Outbound 阶段相似地,首个数据包(TCP 的握手数据包)将和前面的数据包经由不同的门路被转发至 ztunnel。同样先从首包开始剖析,咱们来看看 Node-B 的策略路由规定,因为这个数据包未携带任何标记,也不在 NodeB 的 ztunnel-pod-ips ipset 中,同时,数据包的指标地址是 Pod IP,也不会命中 K8s 网络的 iptables 规定,那么咱们间接来看策略路由阶段:

0:      from all lookup local
100:    from all fwmark 0x200/0x200 goto 32766
101:    from all fwmark 0x100/0x100 lookup 101
102:    from all fwmark 0x40/0x40 lookup 102
103:    from all lookup 100
32766:  from all lookup main
32767:  from all lookup default

因为 local 路由表中都是本地路由规定所以无奈命中,数据包没有任何标记,也不会命中 100、101、102,所以数据包将命中 103 规定,应用 100 路由表,接下来咱们看看这个路由表的内容:

10.244.1.3 dev vethbcda8cd4 scope link 
10.244.1.5 via 192.168.126.2 dev istioin src 10.244.1.1 
10.244.1.6 via 192.168.126.2 dev istioin src 10.244.1.1
10.244.1.7 via 192.168.126.2 dev istioin src 10.244.1.1

100 路由表中为每一个在本节点上运行的 Pod 的 IP 地址都配置了一条路由规定,每一条规定都指向节点上的 istioin 设施,也就是说,应用该路由表进行路由时,只有数据包的指标地址是本机上的 Pod,则路由到 istioin 设施。本数据包的指标地址是 httpbin Pod 地址 10.244.1.7,则将命中第 4 行的路由规定:10.244.1.7 via 192.168.126.2 dev istioin src 10.244.1.1,从而进入 istioin 设施。咱们在后面的探讨中提到过 istioout 设施,与之相似地,istioin 设施则用于解决 inbound 流量,其另一端为 ztunnel B Pod 中的 pistioin 设施。

数据包通过 pistioin 设施进入 ztunnel-B 后,同样还是因为指标地址是 httpbin Pod 的缘故,为了不被 ztunnel Pod 抛弃,也须要通过 iptables 规定的重定向,因为数据包的指标地址为 15008,所以该数据包将命中如下规定:

-A PREROUTING -i pistioin -p tcp -m tcp --dport 15008 -j TPROXY --on-port 15008 --on-ip 127.0.0.1 --tproxy-mark 0x400/0xfff

该规定匹配来自 pistioin 设施,协定为 tcp,且指标端口为 15008 的数据包,并将其通过 TPROXY 重定向到 127.0.0.1 的 15008 端口,同时为数据包打上 0x400 标记,数据包被打上标记后,将在策略路由阶段命中如下规定:

20000:  from all fwmark 0x400/0xfff lookup 100

该策略路由规定批示应用 100 路由表来路由数据包:

local default dev lo scope host

与 ztunnel-A 中相似,100 路由表只有一条路由规定,行将数据包路由到 lo 设施,强制使数据包进入本机协定栈,因为数据包的指标地址被 TPROXY 批改为 15008,所以数据包将最终达到 ztunnel 过程在 15008 端口上监听的 socket。至此,来自 ztunnel-A 的数据包胜利达到 ztunnel 过程:

上行数据包

当 ztunnel Pod 协定栈收回上行数据包后,数据包将通过 eth0 设施进入宿主机,在宿主机上将命中如下 iptables 规定:

-A ztunnel-PREROUTING ! -s 10.244.2.3/32 -i veth51e3b96d -j MARK --set-xmark 0x210/0x210

这条规定的匹配条件为,如果数据包的源地址不是 ztunnel Pod IP,然而来自 ztunnel Pod veth 设施,则打上 0x210 标记,与 Outbound 阶段一样,打上 0x210 标记的数据包都会应用 main 路由表进行路由:

100:    from all fwmark 0x200/0x200 goto 32766
......
32766:  from all lookup main

因为上行数据包的指标地址是 sleep Pod 地址(10.244.2.8),所以在 main 路由表中借助 K8s 网络的路由规定,发往 10.244.2.0/24 地址段的数据包将通过宿主机的 eth0 设施来到,被宿主机网络中的路由器路由到对端 pod 所在的宿主机上。

10.244.2.0/24 via 172.18.0.3 dev eth0

在确定路由后,命中 ztunnel-FORWARD 链中的如下规定:

-A ztunnel-FORWARD -m mark --mark 0x210/0x210 -j CONNMARK --save-mark --nfmask 0x210 --ctmask 0x210

与 Outbound 阶段在 Node-A 上一样,通过回复数据包为该连贯打上了 0x210 标识,连贯上的标识将使得后续数据包命中其余规定。

后续上行数据包

因为连贯打上了 0x210 标识,所以后续数据包进入 Node-B 后将命中如下 iptables 规定:

-A ztunnel-PREROUTING ! -i vethbcda8cd4 -m connmark --mark 0x210/0x210 -j MARK --set-xmark 0x40/0x40
-A ztunnel-PREROUTING -m mark --mark 0x200/0x200 -j RETURN

与 Node-A 上相似,如果数据包不是来自 ztunnel veth,且带有 0x210 连贯标记,则为数据包打上 0x40,目标是让数据包在接下来的路由阶段应用 102 路由表进行路由:

102:    from all fwmark 0x40/0x40 lookup 102

102 路由表是通往 ztunnel-B 的路由表,数据包将命中默认路由规定,被路由到 vethbcda8cd4(即 ztunnel-B 在宿主机上的网络设备),从而进入 ztunnel Pod。

default via 10.244.1.3 dev vethbcda8cd4 onlink 
10.244.1.3 dev vethbcda8cd4 scope link

进入 ztunnel Pod 后的流程与 Inbound 阶段统一,这里不再赘述。

总结

Node-B 上的 Inbound 阶段与 Node-A 上的 Outbound 阶段相似,在从 Node-B 到 ztunnel 的这一阶段,首个数据包是从 istioin 接口来到宿主机,pistioin 接口进入 ztunnel Pod,而后续数据包因为连贯打上了 0x210 标记的缘故,将通过 ztunnel Pod 的 veth 设施来到宿主机,再从 ztunnel Pod 的 eth0 设施进入 ztunnel Pod。

第三局部:ztunnel-B 到 httpbin

ztunnel-B 收到来自对端 ztunnel 的连贯后,将立刻建设一条通往指标 Pod 的 TCP 连贯,以便将解密的数据通过这个连贯发往指标 Pod,ztunnel-B 通过调用 getsockopt 应用 SO_ORIGINAL_DST 选项从连贯取得到原始指标地址,并通过 ztunnel-A 发来的 HTTP CONNECT 握手音讯获知实在指标端口,同时,为了让 httpbin Pod 认为数据包来自 sleep Pod,ztunnel 须要在用于连贯到 httpbin 的 sockt 上通过 IP_TRANSPARENT 选项将连贯的源地址强制设置为 sleep Pod 的地址(ztunnel 能够通过连贯的源地址来得悉 sleep Pod 的地址)。这样一来,从 ztunnelB 收回的数据包的源地址是 sleep Pod 地址,指标地址则是 httpbin Pod 地址,就像数据包真的是从 sleep Pod 发来的一样。接下来,咱们看看这个数据包如何从 ztunnel Pod 来到,并最终达到 httpbin Pod。

1)ztunnel-B Netwoking Namespace -> Node-B Netwoking Namespace

因为发往 httpbin Pod 的数据包不会命中任何 ztunnel B Pod 内的 iptables 规定,所以 Pod 不会携带任何标签,该数据包将命中 ztunnel Pod 内的以下策略路由,应用 main 路由表。

0:      from all lookup local
20000:  from all fwmark 0x400/0xfff lookup 100
20003:  from all fwmark 0x4d3/0xfff lookup 100
32766:  from all lookup main
32767:  from all lookup default

main 路由表的内容如下:

default via 10.244.1.1 dev eth0 
10.244.1.0/24 via 10.244.1.1 dev eth0 src 10.244.1.3 
10.244.1.1 dev eth0 scope link src 10.244.1.3 
192.168.126.0/30 dev pistioin proto kernel scope link src 192.168.126.2 
192.168.127.0/30 dev pistioout proto kernel scope link src 192.168.127.2

因为 httpbin Pod 的地址为 10.244.1.7,所以将应用路由表中的默认规定 default via 10.244.1.1 dev eth0 进行路由,数据包将被送往 eth0 网络接口来到 ztunnel Pod,进入宿主机。

2)Node-B Netwoking Namespace -> httpbin Netwoking Namespace

数据包达到宿主机后,因为其指标地址是本机上的 Pod 的地址,所以须要防止其命中在前一阶段命中的将数据包重定向到 ztunnel Pod 的路由规定,Ambient Mesh 为此在 ztunnel-PREROUTING 链中增加了如下规定(如何跳转到 ztunnel-PREROUTING 链参考前文,这里不再赘述):

......
-A ztunnel-PREROUTING ! -s 10.244.1.3/32 -i vethbcda8cd4 -j MARK --set-xmark 0x210/0x210
......

vethbcda8cd4 即是 ztunnel B Pod 的 veth pair 在宿主机一端的设施,数据包进入 ztunnel Pod 的 eth0 设施后,正是通过这个设施达到宿主机,这条规定匹配的正是来自 ztunnel Pod veth 的数据包,命中这条规定的数据包将打上 0x210 的标识,在第二局部中,来自 ztunnel-A 的数据包命中了编号为 103 的策略路由规定,应用了 100 路由表从而被路由至 ztunnel Pod,但以后数据包因为存在 0x210 标记,所以会先命中编号为 100 的策略路由规定,最终应用 main 路由表进行路由:

0:      from all lookup local
100:    from all fwmark 0x200/0x200 goto 32766
101:    from all fwmark 0x100/0x100 lookup 101
102:    from all fwmark 0x40/0x40 lookup 102
103:    from all lookup 100
32766:  from all lookup main
32767:  from all lookup default

咱们来看一下 main 路由表的内容:

default via 172.18.0.1 dev eth0 
10.244.0.0/24 via 172.18.0.2 dev eth0 
10.244.1.2 dev veth1eb71e57 scope host 
10.244.1.3 dev vethbcda8cd4 scope host 
10.244.1.5 dev veth6cba8664 scope host 
10.244.1.6 dev vetheee0622e scope host
10.244.1.7 dev vethfc1b555e scope host
10.244.2.0/24 via 172.18.0.3 dev eth0 
172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.4 
192.168.126.0/30 dev istioin proto kernel scope link src 192.168.126.1

K8s 网络会在 main 路由表中插入以后节点上所有 pod 路由的条目,发往 Pod IP 的数据包将被路由到连贯到 Pod 网络命名空间内的 veth 设施,这个发往 httpbin Pod 的数据包将命中第 7 行的路由规定,从而被路由到 vethfc1b555e 设施,而后数据包将从该设施的另一端 — 也就是位于 httpbin Pod 内的 eth0 设施进入 httpbin Pod。至此,咱们曾经走完了数据包的残缺门路。

结语

本文中笔者分析了 Ambient Mesh 中从源 Pod 到指标 Pod 的残缺门路,但限于篇幅,实际上还有一些细节在本文中尚未提及,非 Pod 间通信的数据包路由等,笔者将在将来的分享中逐渐分享这些内容。阿里云服务网格 ASM[2] 在刚刚公布的 1.18 版本中也正式反对了 Ambient 模式,作为业界首个反对 Ambient 模式的全托管服务网格,ASM 对局部常见网络插件进行了适配,并提供了 Ambient 模式下路由规定、平安规定等相应的配套文档,欢送各位读者前来体验。

相干链接:

[1] 这篇文章

https://developer.aliyun.com/article/1290950

[2] 阿里云服务网格 ASM

https://account.aliyun.com/login/login.htm?oauth_callback=htt…

作者:史泽寰

点击立刻收费试用云产品 开启云上实际之旅!

原文链接

本文为阿里云原创内容,未经容许不得转载。

正文完
 0