系列文章:


总目录索引:九析带你轻松完爆 istio 服务网格系列教程

目录

1 前言

2 查看 iptables 规则

    2.1 确定 pod 所在主机

    2.2 定位 istio-proxy 容器

    2.3 登录 istio-proxy 容器

    2.4 查看 iptables 规则

3 网络宏观流量流向介绍

4 网络微观流量流向介绍

5 istio 入口流量分析

6 istio 出口流量分析

7 小节


1 前言

        如果你对博客有任何疑问,请告诉我。

        上节中我们举例介绍了执行 istio 注入操作后,对 nginx pod 所产生的影响,即在 pod 中会多创建两个容器:istio-init、istio-proxy,如下图所示:

        如果从进程角度来看 pod,则是下面这个样子:

        从上图可知,nginx pod 内的三个容器共享同一个网络命名空间,该网络命名空间内的流量流向规则在初始化容器 istio-init 启动时完成的,如下图所示:


2 查看 iptables 规则

        一般情况下,我们可以通过 kubectl exec 命令跟 pod 进行交互并获取到 pod 内信息,但这里我们不能此法获取到 pod 内的 iptables 信息。如下截图所示:

        如果想获取到 iptables 信息,必须通过宿主机的 docker 才能获取到。

2.1 确定 pod 所在主机

        使用如下命令获取运行 nginx pod 的宿主机地址:

kubectl get pods -n jiuxi -o wide

        命令执行结果如下图所示:

2.2 定位 istio-proxy 容器

        ssh 命令登录到 10.244.10.80 宿主机,并执行如下命令定位 istio-proxy 容器:

docker ps | grep -i istio-proxy

        执行结果如下图所示:

2.3 登录 istio-proxy 容器

docker exec -it --privileged $(docker ps | grep -i istio-proxy | awk '{print $(1)}') bash

2.4 查看 iptables 规则

        执行如下命令查看 iptables 规则:

iptables -nvL -t nat

        执行结果会报如下错误:

can't initialize iptables table `nat': Permission denied (you must be root)

        执行如下命令切换成 root 用户轻松完爆:

sudo su root

        再次执行 iptables 即可,操作成功如下图所示:


3 网络宏观流量流向介绍

        下面宏观介绍一下基本的网络流量流向知识,如下图所示:

        用户从客户端发起一个 http 请求,该请求会通过互联网到达公司网络的外部边界(路由器),路由器会将网络流量送到交换机,因为反向代理服务器跟交换机联通,因此流量到达反向代理服务器(nginx),nginx 再将网络请求按照预先制定的分发策略转给后面真正处理请求的 web 服务器。

        你可以通过 traceroute 命令定位一下外部网络流向。比如访问 www.baidu.com:

traceroute -I www.baidu.com

        访问截图如下:

        通过上面的截图可知,本人访问 baidu.com 共经过了 13 个路由器。

        当然也可以通过 traceroute 定位 k8s 中 pod 的网络流向,如下截图所示:

        由上图可知:

1 首先定位 nginx pod 的 ip 为 10.244.10.80

2 其次开始 traceroute 进行追踪,发现流量先经过 10.244.10.0,然后访问到 10.244.10.80

3 接着查看本地路由表得知访问 10.244.10.0 的流量是从网络设备 flannel.1 发出去的

4 最后查看了一下网络设备 flannel.1 的详细信息


4 网络微观流量流向介绍

        微观是指流量进入宿主机的情况分析,如下图所示:

        由上图可知:

1 入口流量经过服务器网卡进入服务器的网络协议栈

2 服务器网络协议栈会根据预先定制的网络规则(iptables/netfilter)对报文进行检查

3 协议栈规则检查后,符合要求的流量会从内核态进入到用户态,并进入指定监听端口的进程

4 处于用户态的用户进程接收到网络流量报文进行处理后,将处理后的结果再通过用户态返回给内核态的网络协议栈

5 网络协议栈检查报文,并将结果报文根据指定的网络策略通过网卡输送出去


5 istio 入口流量分析

        有了宏观和微观的网络流量流向分析之后,下一步就可以分析一下 istio 的入口流量了。因为涉及到 iptables 相关的知识,这里我仅仅把结论呈现给大家,具体 iptables 的使用如果大家有兴趣可以参考本人其他的博客轻松完爆。

        在上面我们已经展示了 istio-init 容器在启动时就完成了网络空间协议栈规则的初始化,如下图:

        现在可以通过 curl 访问 nginx pod。

curl 10.244.10.80

        curl 后的入口流量进入 nginx pod 后的流转路径如下图所示:

        由上图可知,整个网络流向如下:

1 因为匹配 iptables nat 表的 prerouting 链的第一条规则,因此网络流量被路由到 ISTIO_INBOUND 链

2 在 ISTIO_INBOUND 链一共有三条规则,因为访问的端口是 nginx 80,所以会匹配该链的第三条规则而将流量路由到 ISTIO_IN_REDIRECT 链

3 路由到 ISTIO_IN_REDIRECT 链的流量最终会从内核态打入到用户态监听端口为 15006 的进程

        端口 15006 的进程是什么呢?通过 netstat -ntlp 命令可知是 envoy 进程,如下图所示:

        由此可知,当我们 curl nginx pod 时,虽然指定的目标访问端口为 80,但是网络协议栈规则仍然会将整个流量劫持送到 envoy 进程,由于 envoy 进程可以获取到入口流量,所以可以在此制定一系列的操作起到流控的目的。envoy 处理完后,流量会继续移动,流向路径如下图所示:

        由上图可知,整个网络流向如下:

1 端口 15006 的进程处理完流量后,会将流量从用户态的进程传回内核态的网络协议栈,根据预先定义好的协议栈规则,流量会流经 output 链,output 链又会根据规则再把流量路由给 ISTIO_OUTPUT 链

2 因为 envoy 处理完流量最终要重新路由给 80 端口的 nginx 进程,因此处于 ISTIO_OUTPUT 链的第一条规则被匹配(因为 envoy 跟 nginx 在同一个网络命名空间,因此环回地址 lo 被匹配),此时流量会重新从内核态返回到用户态,并进入监听端口为 80 的 nginx 进程

3 nginx 处理完后,将结果通过 socket 连接返回给 envoy 进程(用户态)

4 envoy 再将流量通过 postrouting 链、网卡再将响应流量返回给用户


6 istio 出口流量分析

        上面介绍了 istio 入口请求流量流向分析,下面介绍一下 istio 出口流量流向分析,首先在 docker 容器内执行 curl 命令:

curl www.baidu.com

        下面截图展示出口流量的流向:

        从图可知:

1 出口流量首先会通过 iptables nat 表的 output 链进入到 istio_output 链

2 因为目的是 baidu,因此最终会匹配到 istio_redirect 链

3 istio_redirect 会将流量路由给端口 15001 的进程

        端口 15001 进程依旧是 envoy 进程,该端口处理的是 outbound 流量。如下截图所示:

        由此可知,访问 baidu 前,流量依旧会被 envoy 劫持。处理完毕后,envoy 流量处理结果如下图所示:

1 envoy 将处理后的网络流量重新通过用户态进入到内核态的网络协议栈,流量会首先经过 OUTPUT 链

2 流经 OUTPUT 链的流量会进入 ISTIO_OUTPUT 链

3 流入到 ISTIO_OUTPUT 链的流量会匹配 owner UID match 1337 规则

4 流量最终会通过 POSTROUTING 链进入到网卡

5 从网卡随风而出


7 小节

        本小节九析带你轻松完爆了 istio 注入 pod 后所导致的网络流量流向的改变。大家可以自己操作进行验证。这里告诉大家一个小窍门,如果想定位网络流量流向匹配 iptables 的哪条规则,可以通过观察 iptables 规则的 pkts、bytes 变化来确定。