什么是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大致介绍,之后我会慢慢将围绕这一块慢慢补充,后续还会持续更新。