背景介绍
微服务架构带来的开发便捷性使业务功能的开发周期明显缩短,通过对于云计算平台架构的原生优化,让业务功能的持续集成与交付更为敏捷。但同时微服务架构也引入了服务治理的诸多问题:一个应用由多个服务组成,每个服务有数个实例,每个实例的运行状态又在实时变化,这些催生了服务间通讯层的出现。通讯层既不与应用程序代码耦合,又能捕获到底层环境的动态变化并作出适当的调整,避免业务出现单点故障。
1.ServiceMesh简介
1.1服务网格(Service Mesh)简介
服务网络是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格负责在这些拓扑中实现请求的可靠传递。在实践中,服务网格通常实现为一组轻量级网络代理,它们与应用程序一起部署,但对应用程序透明。
从局部看,服务网格技术就是在应用节点上部署代理,应用将请求发给代理,由代理完成点对点的路由转发。
在上面的图中,如果把左边图中的应用程序去掉,只呈现出来代理和它们之间的调用关系(即右图)。这时Service Mesh的概念就会清晰:代理和调用关系形成完整的网络,代表服务间复杂的调用关系,承载着系统内的所有应用。
1.2服务网络架构特点及优势
1)点对点通讯:没有中心瓶颈。
2)对应用无入侵:可以支持异构技术产品的集成。同时对应用透明,应用开发不再需要关心复杂的网络通讯实现,可以专注业务逻辑的实现。
2.Istio及Envoy简介
Istio是一个由Google,IBM和Lyft团队合作开发的开源Service Mesh框架。目前已成为ServiceMesh的事实技术标准,被广泛应用于各个行业的IT架构。
Envoy 是用 C++语言开发的高性能代理,其内置服务发现、负载均衡、TLS终止、HTTP/2、GRPC代理、熔断器、健康检查,基于百分比流量拆分的灰度发布、故障注入等功能,用于协调服务网格中所有服务的入站和出站流量。
3.Envoy流量管理的原理
3.1Iptables介绍
Istio调用Linux中的iptables进行流量管理。iptables是一个运行在用户空间的应用软件,它通过控制Linux内核netfilter模块,来管理网络数据包的流动与转送,实际上netfilter才是防火墙真正的安全框架。netfilter是Linux网络安全大厦的基石,它提供了一整套钩子(Hook)函数机制,IP层的5个钩子点对应了iptables的5个内置链条:
- PREROUTING:在此DNAT。
- POSTROUTING:在此SNAT。
- INPUT:处理输入给本地进程的封包。
- OUTPUT:处理本地进程输出的封包。
- FORWARD:处理转发给其他机器、其他网络命名空间的封包。
3.2关于网络入站的IP封包
从网络入站的IP封包,先入TREOUTING链,而后进行路由判断:
1)如果封包路由目的地是本机:则进入INPUT链,然后发给本地进程。
2)如果封包路由目的地不是本机,并且启用了IP转发,则进入FORWARD链,然后通过POSTROUTING链,最后经过网网络接口发走。
3)对于本地进程发往协议栈的封包,则首先通过OUTPUT链,然后通过POSTROUTING链,最后经过网络接口发走。
3.3关于自定义链
除此以外,我们还可以自定义链,但自定义链只能被某个默认的链当做动作去调用才能起作用。
在Kubernetes中Istio通过Admission webhook的机制将Envoy Sidecar自动注入,与应用容器运行于同一个Pod中,这种情况下它们将共享网络名称空间,因此也使用同一个网络协议栈。
Istio 给应用 Pod 注入的配置主要包括:
1)Init 容器 istio-init:用于Pod中设置iptables端口转发。
2) Sidecar 容器 istio-proxy:运行Envoy Sidecar代理。
3.4Iptables配置规则
在容器初始化后,我们进入Sidecar容器切换为root用户,查看配置的iptables规则。
1 |
iptables -t nat -S |
ISTIO_INBOUND 链:对所有进入Pod但非指定端口(如22)的流量全部重定向至15006端口(Envoy入口流量端口)进行拦截处理。
ISTIO_OUTPUT 链:将由 istio-proxy 用户空间发出且目的地不为localhost的Pod流出流量全部重定向至15001端口(envoy出口流量端口)。其他流量全部直接放行至下一个POSTROUTING链,不用被Envoy拦截处理。
整体流量流向示意图如下图所示:
1)进入Pod的Inbound流量首先被PREROUTING链拦截并处理。
2)当TCP请求进入PREROUTING链时全部交给ISTIO_INBOUND处理。
1 |
-A PREROUTING -p tcp -j ISTIO_INBOUND |
3)请求目标端口非15008/22/15090/15021/15020的TCP请求全部交给ISTIO_IN_REDIRECT处理。
1 |
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT |
4)将发送到此的TCP请求全部重定向至15006端口(Envoy入口流量端口)
1 |
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006 |
5)在Envoy内部处理后,决定将数据包转发到应用,这一步对Envoy来说属于出口流量,会被netfilter拦截转发至出口流量OUTPUT链。
6)出站请求,当TCP请求进入OUTPUT链时全部交给ISTIO_OUTPUT处理。
1 |
-A OUTPUT -p tcp -j ISTIO_OUTPUT |
7)匹配出站请求对应规则,请求本地服务,出口为lo网卡同时来自istio-proxy用户空间,流量返回到它的调用点中的下一条链执行,即POSTROUTING链 。
1 2 |
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN -A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN |
8)Sidecar发出的请求到达目标应用。
9)目标应用处理完业务逻辑后响应Sidecar,这一步对应用来说属于出口流量,再次被netfilter拦截转发至出口流量OUTPUT链。
10) 出站请求,当TCP请求进入OUTPUT链时全部交给ISTIO_OUTPUT处理。
1 |
-A OUTPUT -p tcp -j ISTIO_OUTPUT |
11)请求下一个服务/响应请求,即请求非本地服务同时不来自istio-proxy用户空间,流量被转发至ISTIO_REDIRECT链。
1 |
-A ISTIO_OUTPUT -j ISTIO_REDIRECT |
12)将重定向于此的TCP协议请求流量全部重定向至15001端口(Envoy出口流量端口)。
1 |
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001 |
13)在Envoy内部处理后,决定将数据包对外转发,这一步对Envoy来说属于出口流量,会被netfilter拦截转发至出口流量OUTPUT链。
14)出站请求,当TCP请求进入OUTPUT链时全部交给ISTIO_OUTPUT处理。
1 |
-A OUTPUT -p tcp -j ISTIO_OUTPUT |
15)请求非本地的服务,出口不为lo网卡同时来自istio-proxy用户空间则跳过了ISTIO_REDIREC处理,直接RETURN到下一个链,即POSTROUTING链
1 2 |
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN -A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN |
16)POSTROUTING链处理完成后,根据路由表选择合适的网卡发送Outbound流量。
4.总结
Envoy的核心工作内容在于对业务透明的请求拦截,将所有进出流量进行管理。对拦截的请求进行一定的规则进行安全访问控制、接入控制、流量控制等诸多方面处理后,发送给应用程序。通过使用Envoy,可以使开发者专注于应用功能的开发,不用考虑复杂的网络通讯。