什么是Envoy?

对于一些对于Envoy不是很了解的人,可能对于这个程序的功能完全没有认知,这里我讲下其功能。

在istio service mesh中分为两个平面,一个是数据平面,一个是控制平面。对于Envoy来说他就是数据平面最为重要的功能体现。

 那么envoy的功能到底是什么呢,其实我们可以理解为他是一个代理,类似硬件f5 或者 软件nginx,简单来说就是云原生时代下东西南北流量的代理。

那么为什么在有nginx的情况下 istio还要用envoy作为服务代理呢?其实在早期istio也考虑过使用nginx作为代理,但在2018年的时候放弃了,放弃的原因主要就是不适合云原生环境(nginx在云原生时代太过于鸡肋)。

Envoy的功能

Envoy无论是入口的listerner 类似F5的VS以及部分profile配置,NGINX的listerner以及部分server段落配置还是路由控制逻辑(类似于F5 LTM policy,NGINX的各种location匹配等),还是CLUSTERS(类似于F5 pool,NGINX的upstream),ENDPOINT(类似F5 pool member,NGINX 的upsterm里的server),乃至SSL证书完全可以通过接口从服务册自动化发现过来。

如下图为envoy的几个比较重要的结构,除了一下几个可能还会涉及secret ds 以及ads

在 Istio 场景下,Envoy 的容器里运行两个进程,一个叫 pilot-agent,一个是 envoy-proxy 本身,pilot-agent 负责管理与启动 Envoy,并产生一个位于 /etc/istio/proxy/ 下的 envoy-rev0.json 初始配置文件,这个文件里定义了 Envoy 应该如何与 pilot server 进行通信以获取配置,利用该配置文件最终启动 Envoy 进程。但是 Envoy 最终运行的配置并不仅仅是 envoy-rev0.json 里的内容,它包含上文所说的通过 xDS 协议发现的所有动态配置。

$ ps -aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
istio-p+       1  0.1  0.1 768356 34560 ?        Ssl  Sep18  32:19 /usr/local/bin/pilot-agent proxy sidecar --domain xhzy-pe.svc.cluster.local --serviceCluster pgy-chunfeng.xhzy-pe --proxyLogLevel=warning
istio-p+      24  0.7  0.6 449476 226928 ?       Sl   Sep18 185:22 /usr/local/bin/envoy -c etc/istio/proxy/envoy-rev0.json --restart-epoch 0 --drain-time-s 45 --parent-shutdown-time-s 60 --service-cluster
istio-p+      40  0.0  0.0  18648  2204 pts/0    Ss   10:56   0:00 bash
istio-p+      52  0.0  0.0  34416  1472 pts/0    R+   11:23   0:00 ps -aux

那么对于一些通过xds生成的动态配置我们可以通过如下命令获取

curl 127.0.0.1:15000/config_dump 

这里我们看到了envoy生成了15000端口去获取配置,除了这个端口还会生成

15006: 接收所有经 iptables 拦截的 Inbound 流量并转交给虚拟监听器处理(入站监听器,在1.6版本之后出现的新端口)

15001: 接收所有经 iptables 拦截的 Outbound 流量并转交给虚拟监听器处理(出站监听器)

15012: Istiod http dns

15020: Ingress Gateway,Pilot 健康检查

istio envoy sidecar proxy 配置解析:

主要包含以下四部分

bootstrap: envoy proxy 启动时候加载的静态配置,主要是配置了节点信息 traceing admin和统计信息

listerner: 监听配置使用LDS下发

clusters: 集群配置,静态配置中包含xds-grpc的zipkin地址动态配置使用cds下发

routes: 路由配置 静态配置包含了本地监听的服务的集群信息,其中引用了cluster,动态配置使用rds下发每个部分中都包含了静态配置与动态配置,其中bootstrap配置又是在集群启动的时候通过sidecar启动参数注入的,配置文件在/etc/istio/proxy/envoy-rev0.json

bootstrap是envoy 中配置的根本来源,bootstrap 消息有一个很关键的概念,就是静态和动态资源之间的区别,例如listerner活cluster这些资源既可以从static_resources静态获得也可以从dynamic_resources中配置的LDS或CDS之类的xDS服务获取。

那么istio是如何截取流量经过envoy的?

1.首先istio会通过 Admission Controller 自动注入sidecar容器,这里的sidecar容器就是envoy以及初始化容器。

2.那么初始化容器的工作就是设置改network namespace下的所有流量都劫持到 Envoy sidecar proxy,这里实现方式是通过iptables,当然也可以使用ipvs,bpf等。

这里会出现一个问题: 因为在初始化的时候所有流量都是经过envoy,如何保证业务容器晚于envoy启动?

那么如果先于envoy启动会对一些业务产生影响,比如业务应用启动的时候会去访问其他资源获取配置,获取文件等。如果envoy没启动的话直接导致业务启动失败。

在1.6版本以前。我们通常的做法就是写一个sdk该sdk的作用就是先判断15000端口是否可以访问。

在1.7 版本之后,社区修改了sidecar的在pod里的顺序,将pod提前到了业务应用之前。并通过postStart保证了envoy先于业务应用启动。然而在kubernetes 1.18之后 为了解决这个问题,k8s提出了sidecar容器的概念彻底解决了这个问题。但是目前istio还在使用postStart的形式。未来可能会考虑跟着kubernetes走。

3.不论是进入还是从 Pod 发出的 TCP 请求都会被 iptables 劫持,inbound 流量被劫持后经 Inbound Handler 处理后转交给应用程序容器处理,outbound 流量被 iptables 劫持后转交给 Outbound Handler 处理,并确定转发的 upstream 和 Endpoint。

Inbound handler 的作用是将 iptables 拦截到的 downstream 的流量转交给 localhost,与 Pod 内的应用程序容器建立连接。

outbound handler的作用是将iptables 拦截到的本地应用程序发出的流量,经由 sidecar 判断如何路由到 upstream

以上是envoy大致介绍,之后我会慢慢将围绕这一块慢慢补充,后续还会持续更新。

 

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐