Kubernetes:Ingress总结(二)
Blog:博客园 个人
参考:Ingress | Kubernetes、《Kubernetes进阶实战》
Contour是Kubernetes Ingress控制器的另一款开源实现,它以高性能的Envoy代理程序作为数据平面,支持开箱即用的动态配置和多种高级路由机制,支持TCP代理,并且提供了自定义资源类型HTTPProxy资源以扩展IngressAPI,以更丰富的功能集部分解决了Ingress原始设计中的缺点,是Ingress控制器较为出色的实现之一。
Contour Ingress controller 由两个组件组成:
Envoy
: 提供高性能反向代理。Contour
: 充当 Envoy 的控制平面,为 Envoy 的路由配置提供统一的来源。
官方文档提供了部署方法:Getting Started with Contour (projectcontour.io)
Envoy
Envoy是专为大型现代SOA架构设计的应用代理和通信总线,使用C++语言编写,是高性能的HTTP/HTTPS协议代理,支持负载均衡、超时、重试、熔断、限流和回退等多种高级路由功能,支持HTTP/2和gRPC,而且能够作为HTTP/1.1和HTTP/2之间的双向透明代理机制。Envoy原生支持动态配置和服务发现机制,能够通过xDS API从控制平面(管理服务器)获取配置信息,同时提供了良好的可观测性,未来甚至会作为UPDA(Universal Data Plane API)的标准实现之一。
作为代理服务,Envoy使用“侦听器”(listener)维护与下游客户端的连接,使用集群管理器管理上游服务器集群,并根据侦听器上配置的代理层级和路由策略“桥接”客户端与后端服务器。它支持配置任意数量的侦听器和任意数量的上游集群,这些配置可使用静态方式指定,也可分别基于不同的服务发现API动态生成。
Envoy通过侦听器监听网络套接字以接收客户端请求,并且支持在一个进程上启用任意数量的侦听器,从而赋予用户按需配置Envoy监听一至多个套接字的能力。每个侦听器都应独立配置一些网络(L3/L4)过滤器,在接收到请求后,侦听器负责实例化指定过滤器链中的各个过滤器,并由这些过滤器处理后续的相关事件。一般说来,用户可根据不同的过滤器链配置侦听器以完成不同代理任务,例如HTTP代理、TCP代理、TLS客户端认证、限速等。
HTTP是现代面向服务的架构中至关重要的组件,因此Envoy通过名为HTTP连接管理器的网络(L3/L4)过滤器实现HTTP协议的应用层代理,内置支持HTTP/1.1、WebSockets和HTTP/2几类协议。另外,Envoy在传输层和应用层分别提供了对gRPC协议的原生支持,gRPC是来自Google的RPC框架,它基于HTTP/2构建和传递请求/响应报文。Envoy内置的HTTP过滤器中的Router负责为HTTP代理实现高级路由功能,包括将DNS域映射到特定的虚拟主机、URL重定向、URL重写、重试、超时、基于权重或百分比进行流量分发、基于优先级的路由和基于哈希策略的路由等。Envoy通过配置的路由信息生成路由表,并由Router过滤器据此做出路由决策。
每个上游服务器可由一个称为端点的逻辑组件进行标识,它代表着此服务监听的套接字,因此也可直接作为上游服务的标识符使用。一个集群可以包含一到多个端点,而一个端点也可隶属于一到多个集群。
Envoy的集群管理器负责管理配置的所有上游集群,包括获知上游主机健康可用状态、负载状态、连接类型以及适用的上游通信协议(HTTP/1.1、HTTP/2)等,并向前端的过滤器堆栈暴露API,允许过滤器根据请求及处理结果按需建立与上游集群的L3/L4或L7的通信连接。一旦在配置中定义了集群,集群管理器需要知道如何解析集群中的成员,即端点配置信息。目前,Envoy支持的端点配置支持包括静态配置、严格DNS、逻辑DNS、原始目标和EDS几种。集群管理器可通过纯静态的配置信息加载并初始化集群,也可通过集群发现服务(Cluster Discovery Service,CDS)API动态获取相关的配置,而后一种方式允许将配置信息存储在集中式的配置服务中,从而减少重启Envoy或重新分发配置的次数。
服务发现是面向服务架构的基石。为了更好地适配云原生环境,Envoy内置了一个层次化的动态配置API用于集中式管理配置信息,该API可借助服务发现服务(Service Discovery Service,即服务发现自身作为一种服务)机制支持多种服务发现方式,从而为Envoy提供以下配置信息的动态发现和更新。
- 端点发现服务(Endpoint Discovery Service,EDS):用于为Envoy动态添加、更新和删除Service端点,这些端点通常是指上游集群后端提供特定服务的主机的套接字;EDS事实上是v1时代的SDS(Service Discovery Service)的替代品,而且,SDS在v2版本中专用于指代Secret Discovery Service。
- 集群发现服务(Cluster Discovery Service,CDS):用于动态添加、更新和删除Upstream集群,其中,每个集群本身都有自己的端点发现(v1版本中的服务发现)机制。
- 路由发现服务(Route Discovery Service,RDS):用于动态添加或更新HTTP路由表。
- 密钥发现服务(Secret Discovery Service,SDS):传递TLS密钥信息,从而LDS/ CDS能将主要侦听器和集群配置通过密钥管理系统与密钥信息在传送时相分离。
- 侦听器发现服务(Listener Discovery Service,LDS):用于动态添加、更新和删除整个侦听器,包括其完整的L4或L7过滤器堆栈。
- 健康发现服务(Health Discovery Service,HDS):配置Envoy成为分布式健康状态检查网络的成员,负责将健康状态检查的相关信息报告给上级或集中式的健康状态检查服务。
- 聚合发现服务(Aggregated Discovery Service,ADS):构建在单个EnvoyAPI提供的数据平面服务之上的多个管理API(例如Istio、Linkerd等);同时操作Envoy API时,使用单个管理服务器处理单个Envoy的所有更新操作有助于确保Envoy的数据一致性;此API允许所有其他API通过单个管理服务器的单个gRPC双向流进行编组,从而实现确定性排序。
- 另外还有ALS(gRPC Access Log Service)、RTDS(Runtime DiscoveryService)、RLS(Rate Limit Service)和CSDS(Client Status DiscoveryService)等,这些API统称为xDS,相较于v1版本来说,它是一种新的REST-JSON API,其中JSON/YAML格式是基于proto3规范的JSON映射机制派生而来的。另外,xDS API通过gRPC流式传输进行更新,该方式有着较低资源需求,因而能降低更新延迟。
HTTPProxy
除了能实现类似于Ingress资源的流量分发等基础功能,HTTPProxy还封装了Envoy相当一部分高级路由功能的API,例如基于标头的路由、流量镜像和流量分割等多种高级路由功能,能帮助用户实现诸如金丝雀部署、蓝绿部署和A/B测试等功能。
HTTPProxy支持在单个路由规则中同时指定多个后端服务,默认情况下,所有流量将以等量切分的方式平均分发到多个后端之上,每个后端内部再按照代理服务器配置的调度算法进行二级负载均衡。同时,HTTPProxy也允许用户为每个后端服务使用weight字段指定一个特定流量百分比,从而将流量以指定的比例在不同的后端服务间进行分发。
基于流量分割的流量切分是完成灰度发布的常用手段。上线应用的新版本时,无论是出于产品稳定性还是用户接受程度等因素的考虑,直接以新代旧都充满风险。因此,灰度发布是应用程序在生产环境安全上线的一种重要手段,而对于Envoy来说,灰度发布仅是其流量治理功能的一种典型应用,结合分割策略便能实现常见的金丝雀部署、蓝绿部署和A/B测试等应用场景。
事实上,基于标头的流量分割算是“基于请求内容”灰度部署的一种实现,而流量分割则是“基于流量比例”进行灰度部署的方式。与Kubernetes的Deployment控制器的滚动更新机制相比,HTTPProxy允许用户按需指定要切分的流量比例,而非按照Pod数量来固定分割的方式。
HTTPProxy中的负载均衡策略是路由规则中的定义,每个路由规则都可以为其后端调用的服务按需指定最为合用的负载均衡机制。目前,HTTPProxy暴露了Envoy在集群上支持的部分调度算法,主要有如下几个。
- RoundRobin:按顺序轮询选择上游端点,此为默认策略。
- WeightedLeastRequest:加权最少连接,但该算法仅随机选择两个健康的端点,并从中挑选出负载少的端点作为调度目标。
- Random:从后端健康端点中随机挑选端点。
- Cookie:粘性会话调度机制,把来自某客户端的所有请求始终调度给同一个后端端点。
工作原理
Contour 同时支持 Ingress
资源对象和 IngressRoute
资源对象(通过 CRD 创建),这些对象都是为进入集群的请求提供路由规则的集合。这两个对象的结构和实现方式有所不同,但它们的核心意图是相同的,都是为进入集群的请求提供路由规则。如不作特殊说明,后面当我们描述 “Ingress” 时,它将同时适用于 Ingress
和 IngressRoute
对象。
通常情况下,当 Envoy 配置了 CDS
的 endpoint 时,它会定期轮询端点,然后将返回的 JSON 片段合并到其运行配置中。如果返回到 Envoy 的集群配置代表当前的 Ingress 对象的集合,则可以将 Contour 视为从 Ingress
对象到 Envoy
集群配置的转换器。随着 Ingress 对象的添加和删除,Envoy 会动态添加并删除相关配置,而无需不断重新加载配置。
在实践中,将 Ingress 对象转换为 Envoy 配置更加微妙,需要将 Envoy 中的 xDS 配置(包括 CDS
,EDS
和 RDS
)映射到 Kubernetes 中。Contour 至少需要观察 Ingress
、Service
和 Endpoint
这几个资源对象以构建这些服务的响应,它通过 client-go
的 cache/informer 机制免费获得这些 watchers
。这些 watchers 提供添加,更新和删除对象的边缘触发通知,也可以通过 watch API
在本地缓存缓存对象,以便后续查询。
Contour 将收集到的这些对象处理为虚拟主机及其路由规则的有向非循环图(DAG),这表明 Contour 将有权构建路由规则的顶级视图,并将群集中的相应服务和TLS秘钥连接在一起。一旦构建了这个新的数据结构,我们就可以轻松实现 IngressRoute
对象的验证,授权和分发。改数据结构导出的 png
图片如下图所示:
Envoy API 调用和 Kubernetes API 资源之间的映射关系如下:
- CDS : 集群发现服务。映射为 Kubernetes 中的
Service
以及一部分 Ingress 对象的TLS
配置。 - EDS : 服务发现服务。映射为 Kubernetes 中的
Endpoint
。Envoy 使用 EDS 自动获取Cluster
成员,这与 Endpoint 对象中包含的信息非常匹配。Envoy 使用 Contour 在EDS
响应中返回的名称查询EDS
。 - RDS : 路由发现服务。映射为 Kubernetes 中的
Ingress
。提供了虚拟主机名和前缀路由信息的 RDS 与 Ingress 匹配得更好。
总结
基于Kubernetes内置的Ingress发布服务时,底层使用的是IngressNginx还是Contour控制器并没有本质上的区别。但Contour提供的CRD资源类型HTTPProxy能够提供更为完整的路由功能集,大大丰富了Ingress的特性表现。HTTPProxy封装了Envoy的部分API,从而支持流量切分、流量镜像、基于标头的路由、自定义使用的负载均衡策略、超时和重试、后端端点的健康状态检测等高级功能。