Istio Sidecar 流量拦截机制分析

Istio Sidecar 流量拦截机制分析 :: Yingchi Blog

流量经主机的基本过程

过程如下

  1. Inbound流量经过NIC(网卡)进入主机的网络协议栈;
  2. 协议栈会根据预先制定的网络规则(iptables/netfilter)对报文进行检查
  3. 协议栈规则检查后,复合要求的Inbound流量会从内核空间进入到用户空间,并指定监听端口的进程;
  4. 处于用户态的用户进程接收到网络流量报文进行处理后,将处理后的结果再通过用户空间返回给内核空间的网络协议栈;
  5. 网络协议栈检查报文,并将结果报文根据指定的网络策略通过网卡发送出去;

Sidecar流量拦截基本过程

之前的文章已经介绍过了Sidecar的注入机制,注入到Pod中即下面俩个容器

  • Istio-init:InitContainer,用于在Pod初始化过程中对Pod的iptables进行初始化设置
  • Istio-proxy:负责与pilot组件通信以及流量的控制;该容器运行时会启动俩个关键的进程pilot-agent和envoy。pilot-agent进程会定时跟istio的pilot组件进行通信,envoy进程会接收入口和出口网络流量。

注意:Istio-proxy和Kubernetes中的kube-proxy都是通过iptables/netfilter来处理网络流量。只不过istio-proxy位于pod网络空间,处理的是pod内的网络流量,而kube-proxy位于宿主机网络空间,处理的是宿主机内网络流量(因为kube-proxy是daemonset,因此它位于每个k8s集群的每个node节点上)。

Sidecar流量拦截其实指基于iptables规则,由init容器在Pod启动的时候首先设置iptables规则

iptables规则拦截应用容器Inbound/Outbound的流量,目前只能拦截TCP流量,不能拦截UDP流量,因为Envoy目前不支持UDP转发。

下面来分析 Inbound 流量一系列走向:

  1. inbound流量在进入Pod的网络协议栈时首先被iptables规则拦截
  2. iptables规则将数据包转发给istio-proxy容器的Envoy进程
  3. Envoy在根据自身监听配置,将流量转发给app容器中的应用进程。

注意:Envoy 在将流量转发给应用时也会流经内核协议栈由 iptables 规则处理,这里 init 容器设置的规则并没有拦截,因此中间省略iptables的处理过程;

然后来分析 Outbound 流量一系列走向:

  1. Outbound流量由应用发出,首先被iptables规则拦截
  2. iptables规则将出口数据包转发给istio-proxy容器的Envoy进程;
  3. Envoy再根据自身配置决定是否将流量转发到容器外。

流量代理拦截实现细节

Istio流量代理转发模式

在istio中,流量拦截的视线依赖initContainer iptables规则的设置,目前由俩种流量拦截模式:REDIRECT模式和TPROXY模式

REDIRECT模式

REDIRECT模式下,通过iptables,可以将所有的流量都重定向到一个特定的端口上。

iptables -t nat -A PREROUTING -p tcp -j REDIRECT --to-port 15001

DNAT代表目标网络地址转换(Destination Network Address Translation)。DNAT是一种网络地址转换技术,用于修改数据包的目标IP地址和端口,以便将数据包重定向到不同的目标地址或端口。

可以用于端口转发,负载均衡,高可用性等

即将所有流量都重定向到15001端口。看起来和iptables的DNAT很像,本质REDIRECT 就是一个特殊的DNAT规则,一般情况下,我们利用iptables做DNAT的时候,需要指定目标的IP和端口,这样iptables才知道需要将数据包的目的修改成什么,而REDIRECT模式下,只需要指定端口就可以,iptables会自动帮我们判断需要设置的IP地址。

REDIRECT 模式虽然会进行源地址转换,但依然是默认的模式,因为配合Istio提供的遥测数据依然可以进行调用链分析。在Kubernetes平台上Pod及其IP地址并不是持久不变的,会随着集群的资源状态动态销毁即迁移,所以源地址这种传统的软件系统记录客户端的方式并不适合云原生应用平台Kuberntes;

TPROXY 模式

除了利用REDIRECT模式,IStio还提供TPROXY ,对于TPROXY 模式,需要借助iptables和路由,比较复杂一点,用来做透明代理,操作的是mangle表。

同时需要原始客户端socket设置IP_TRANSPARENT选项,Linux提供了一个IP_TRANSPARENT 选项,这个选项可以让程序bind一个不属于本机的地址,作为客户端,它可以使用一个不属于本机地址的IP作为源IP发起连接,作为服务端,它可以侦听一个不属于本机的IP低智商,这正式透明代理所必须的。

TPROXY 模式并没有改变数据包,所以直接通过 getsockname 获取到原始的IP端口信息。

结合iptables分析Inbound/Outbound流量走向

Inbound 流量

  • Inbound 首先匹配 iptables nat 表的 PREROUTING 链的第一条规则,因此 Inbound 流量被路由到 ISTIO_INBOUND 链;
  • 在 ISTIO_INBOUND 链中,根据访问端口,匹配该链的第 X 条规则,流量路由到 ISTIO_IN_REDIRECT 链;
  • 路由到 ISTIO_IN_REDIRECT 链的流量最终会从内核态打入到用户态的监听 xxxx 端口的 Envoy 进程;
  • Envoy 进程处理完流量后,会将流量从用户态的进程传回内核态的网络协议栈,根据预先定义好的协议栈规则,流量会流经 OUTPUT 链,OUTPUT 链又会根据规则再把流量路由给 ISTIO_OUTPUT 链;
  • 因为 Envoy 处理完流量最终要重新路由给目的端口的应用进程,因此处于 ISTIO_OUTPUT 链的第 X 条规则会被匹配(因为 Envoy 跟应用容器进程在同一个网络命名空间,因此环回地址 lo 被匹配),此时流量会重新从内核态返回到用户态,并进入监听端口为 X 的应用进程;
  • 应用进程处理完后,将结果通过 socket 连接返回给 envoy 进程(用户态);
  • Envoy 再将流量通过 POSTROUTING 链、NIC,将响应流量返回给用户。

Outbound 流量

  • Outbound 流量首先会通过 iptables nat 表的 OUTPUT 链进入到 ISTIO_OUTPUT 链;
  • 根据目的地址,匹配到 ISTIO_REDIRECT 链;
  • ISTIO_REDIRECT 链会将流量路由给 Envoy 进程;
  • Envoy 将处理后的 Outbound 流量重新通过用户态进入到内核态的网络协议栈,流量会首先经 OUTPUT 链到 ISTIO_OUTPUT 链;
  • 流量最终会通过 POSTROUTING 链进入到 NIC 然后发送出去。
Last modification:December 29, 2023
如果觉得我的文章对你有用,请随意赞赏