这不是一篇教程,本文试图带您梳理清楚 Kubernetes、Envoy(xDS 协议)以及 Istio Service Mesh 之间的关系及内在联系。本文介绍了 Kubernetes 中的负载均衡方式,Envoy 的 xDS 协议对于 Service Mesh 的意义以及为什么说有了 Kubernetes 还需要 Istio。
Envoy 对于 Service Mesh 或者说 Cloud Native 最大的贡献就是定义了 xDS,Envoy 虽然本质上是一个 proxy,但是它的配置协议被众多开源软件所支持,如 Istio 、 Linkerd 、 AWS App Mesh 、 SOFAMesh 等。
2018年9月1日, Bilgin Ibryam 在 InfoQ 发表了一篇文章 Microservices in a Post-Kubernetes Era ,中文版见 后 Kubernetes 时代的微服务 (译文有些错误,仅供参考)。本文标题中虽然没有明确指明”后 Kubernetes 时代的微服务“是什么,但是从文中可以看出作者的观点是:在后 Kubernetes 时代,服务网格(Service Mesh)技术已完全取代了使用软件库实现网络运维(例如 Hystrix 断路器)的方式。本文索性就借用该标题。
如果你没有心里阅读下文的所有内容,那么可以先阅读看下下面列出的本文中的一些主要观点:
kube-proxy
本文假定您已经对 Kubernetes 有比较全面的了解,同时还使用过 Istio service mesh,但是对于 Kubernetes、Envoy 及 Istio 之间的关系不甚了解,及 Istio 如何使用 xDS 协议控制所有的 Sidecar 有浓厚的兴趣,那么推荐您继续阅读。
推荐大家在阅读本文之前希望您对微服务、容器和 Kubernetes 有一定认识,如果您已经阅读过以下几篇文章将对您理解本文更有帮助,本文中也引用过了下面文章中的部分观点。
使用 Service Mesh 并不是说与 Kubernetes 决裂,而是水到渠成的事情。Kubernetes 的本质是通过声明式配置对应用进行生命周期管理,而 Service Mesh 的本质是应用间的流量和安全性管理。假如你已经使用 Kubernetes 构建了稳定的微服务平台,那么如何设置服务间调用的负载均衡和流量控制?
我想听说过 Service Mesh 并试用过 Istio 的人可能都会有以下几个疑问:
从 ServiceMesher 社区 的反馈来看,很多初次接触 Istio 和 Service Mesh 的同学,跟着那个 Istio 官方文档 可以迅速的搭建和试用 Istio 的各种功能,了解 Service Mesh 能为你做什么,但用户所有的操作都仅是在控制平面完成的,至于 Istio 如何操作数据平面,即每个 Sidecar proxy 的呢?
Kubernetes 1.13 如期发布了,Kubernetes 依然按照四个月一个版本的速度迭代着,但是我们能看到的重大革新越来越少了,已经过了技术采纳的初级阶段,正在大规模落地,关于 Kubernetes 的书籍、演讲已经扎堆,我不会过多得讲到 Kubernetes。本文不一定能够回答以上所有问题,本文仅为我个人理解,抛砖引玉。
下图展示的是 Kubernetes 与 Service Mesh 中的的服务访问关系,本文仅针对 sidecar per-pod 模式,详情请参考服务网格的实现模式。
Kubernetes 集群的每个节点都部署了一个 kube-proxy
组件,该组件会与 Kubernetes API Server 通信,获取集群中的service 信息,然后设置 iptables 规则,直接将对某个 service 的请求发送到对应的 Endpoint(属于同一组 service 的 pod)上。
Istio Service Mesh 中沿用了 Kubernetes 中的 service 做服务注册,通过 Control Plane 来生成数据平面的配置(使用 CRD 声明,保存在 etcd 中),数据平面的 透明代理 (transparent proxy)以 sidecar 容器的形式部署在每个应用服务的 pod 中,这些 proxy 都需要请求 Control Plane 来同步代理配置,之所以说是透明代理,是因为应用程序容器完全无感知代理的存在,该过程 kube-proxy 组件一样需要拦截流量,只不过 kube-proxy
拦截的是进出 Kubernetes 节点的流量,而 sidecar proxy 拦截的是进出该 Pod 的流量,详见 理解 Istio Service Mesh 中 Envoy Sidecar 代理的路由转发 。
因为 Kubernetes 每个节点上都会运行众多的 Pod,将原先 kube-proxy
方式的路由转发功能置于每个 pod 中,这将导致大量的配置分发、同步和最终一致性问题。为了细粒度的机型流量管理,必将代理一系列新的抽象,增加了用户的心智负担,但随着技术的普及慢慢将得到缓解。
kube-proxy
的设置都是全局生效的,无法对每个服务做细粒度的控制,而 Service Mesh 通过 sidecar proxy 的方式将 Kubernetes 中对流量的控制从 service 一层抽离出来,可以做更多的扩展。
在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy
进程。 kube-proxy
负责为 Service
实现了一种 VIP(虚拟 IP)的形式。 在 Kubernetes v1.0 版本,代理完全在 userspace 实现。Kubernetes v1.1 版本新增了iptables 代理模式,但并不是默认的运行模式。从 Kubernetes v1.2 起,默认使用 iptables 代理。在 Kubernetes v1.8.0-beta.0 中,添加了ipvs 代理模式。关于 kube-proxy 组件的更多介绍请参考 kubernetes 简介:service 和 kube-proxy 原理 和 使用 IPVS 实现 Kubernetes 入口流量负载均衡 。
在上面的链接中作者指出了 kube-proxy 的不足之处 :
首先,如果转发的 pod 不能正常提供服务,它不会自动尝试另一个 pod,当然这个可以通过 liveness probes
来解决。每个 pod 都有一个健康检查的机制,当有 pod 健康状况有问题时,kube-proxy 会删除对应的转发规则。另外, nodePort
类型的服务也无法添加 TLS 或者更复杂的报文路由机制。
Kube-proxy 实现了流量在 Kubernetes service 多个 pod 实例间的负载均衡,但是如何对这些 service 间的流量做细粒度的控制,比如按照百分比划分流量到不同的应用版本(这些应用都属于同一个 service,但位于不同的 deployment 上),做金丝雀发布(灰度发布)和蓝绿发布?Kubernetes 社区给出了 使用 Deployment 做金丝雀发布的方法 ,该方法本质上就是通过修改 pod 的label 来将不同的 pod 划归到 Deployment 的 Service 上。
Kubernetes 中的 Ingress 资源对象跟 Istio Service Mesh 中的 Gateway 的功能类似,都是负责集群南北流量(从集群外部进入集群内部的流量)。
kube-proxy
只能路由 Kubernetes 集群内部的流量,而我们知道 Kubernetes 集群的 Pod 位于CNI 创建的外网络中,集群外部是无法直接与其通信的,因此 Kubernetes 中创建了ingress 这个资源对象,它由位于 Kubernetes边缘节点(这样的节点可以是很多个也可以是一组)的 Ingress controller 驱动,负责管理 南北向流量 (从集群外部进入 Kubernetes 集群的流量),Ingress 必须对接各种个 Ingress Controller 才能使用,比如 nginx ingress controller 、 traefik 。Ingress 只适用于 HTTP 流量,使用方式也很简单,只能对 service、port、HTTP 路径等有限字段匹配来路由流量,这导致它无法路由如 MySQL、redis 和各种私有 RPC 等 TCP 流量。要想直接路由南北向的流量,只能使用 Service 的 LoadBalancer 或 NodePort,前者需要云厂商支持而且可能需要付费,后者需要进行额外的端口管理。有些 Ingress controller 支持暴露 TCP 和 UDP 服务,但是只能使用 Service 来暴露,Ingress 本身是不支持的,例如 nginx ingress controller ,服务的暴露的端口是通过创建 ConfigMap 的方式来配置的。
Istio Gateway
描述的负载均衡器用于承载进出网格边缘的连接。该规范中描述了一系列开放端口和这些端口所使用的协议、负载均衡的 SNI 配置等内容。Gateway 是一种CRD 扩展,它同时复用了 Envoy proxy 的能力,详细配置请参考 Istio 官网 。
下面这张图大家在了解 Service Mesh 的时候可能都看到过,每个方块代表一个服务的示例,例如 Kubernetes 中的一个 Pod(其中包含了 sidecar proxy),xDS 协议控制了 Istio Service Mesh 中所有流量的具体行为,即将下图中的方块链接到了一起。
xDS 协议是由 Envoy 提出的,在 Envoy v2 版本 API 中最原始的 xDS 协议只指 CDS、EDS、LDS 和 RDS。
下面我们以两个 service,每个 service 都有两个实例的例子来看下 Envoy 的 xDS 协议。
上图中的箭头不是流量在进入 Enovy Proxy 后的路径或路由,而是想象的一种 Envoy 中 xDS 接口处理的顺序并非实际顺序,其实 xDS 之间也是有交叉引用的。
Envoy 通过查询文件或管理服务器来动态发现资源。概括地讲,对应的发现服务及其相应的 API 被称作 *xDS*。Envoy 通过 订阅(*subscription*) 方式来获取资源,订阅方式有以下三种:
path
参数中。 ApiConfigSource
,指向对应的上游管理服务器的集群地址。 以上的 xDS 订阅方式详情请参考xDS 协议解析。Istio 使用的 gRPC 流式订阅的方式配置所有的数据平面的 sidecar proxy。
关于 xDS 协议的详细分解请参考丁轶群博士的这几篇文章:
文章中介绍了 Istio pilot 的总体架构、Envoy 配置的生成、pilot-discovery 模块的功能,以及 xDS 协议中的 CDS、EDS 及 ADS,关于 ADS 详情请参考 Enovy 官方文档 。
最后总结下关于 xDS 协议的要点:
Envoy 是 Istio Service Mesh 中默认的 Sidecar,Istio 在 Enovy 的基础上按照 Envoy 的 xDS 协议扩展了其控制平面,在讲到 Envoy xDS 协议之前还需要我们先熟悉下 Envoy 的基本术语。下面列举了 Envoy 里的基本术语及其数据结构解析,关于 Envoy 的详细介绍请参考 Envoy 官方文档 ,至于 Envoy 在 Service Mesh(不仅限于 Istio) 中是如何作为转发代理工作的请参考网易云刘超的这篇 深入解读 Service Mesh 背后的技术细节 以及 理解 Istio Service Mesh 中 Envoy 代理 Sidecar 注入及流量劫持 ,本文引用其中的一些观点,详细内容不再赘述。
下面是您应该了解的 Enovy 里的基本术语:
Envoy 中可以设置多个 Listener,每个 Listener 中又可以设置 filter chain(过滤器链表),而且过滤器是可扩展的,这样就可以更方便我们操作流量的行为,例如设置加密、私有 RPC 等。
xDS 协议是由 Envoy 提出的,现在是 Istio 中默认的 sidecar proxy,但只要实现 xDS 协议理论上都是可以作为 Istio 中的 sidecar proxy 的,例如蚂蚁金服开源的 SOFAMosn 和 nginx 开源的 nginmesh 。
Istio 是一个功能十分丰富的 Service Mesh,它包括如下功能:
Istio 中定义了如下的CRD 来帮助用户进行流量管理:
DestinationRule
所定义的策略,决定了经过路由处理之后的流量的访问策略。简单的说就是定义流量如何路由。这些策略中可以定义负载均衡配置、连接池尺寸以及外部检测(用于在负载均衡池中对不健康主机进行识别和驱逐)配置。 EnvoyFilter
对象描述了针对代理服务的过滤器,这些过滤器可以定制由 Istio Pilot 生成的代理配置。这个配置初级用户一般很少用到。 ServiceEntry
能够在 Istio 内部的服务注册表中加入额外的条目,从而让网格中自动发现的服务能够访问和路由到这些手工加入的服务。 在阅读完上文对 Kubernetes 的 kube-proxy
组件、Envoy xDS 和 Istio 中流量管理的抽象概念之后,下面将带您仅就流量管理方面比较下三者对应的组件/协议(注意,三者不可以完全等同)。
Kubernetes | Envoy xDS | Istio Service Mesh |
---|---|---|
Endpoint | Endpoint | - |
Service | Route | VirtualService |
kube-proxy | Route | DestinationRule |
kube-proxy | Listener | EnvoyFilter |
Ingress | Listener | Gateway |
Service | Cluster | ServiceEntry |
如果说 Kubernetes 管理的对象是 Pod,那么 Service Mesh 中管理的对象就是一个个 Service,所以说使用 Kubernetes 管理微服务后再应用 Service Mesh 就是水到渠成了,如果连 Service 你也不像管了,那就用如 knative 这样的 serverless 平台,这就是后话了。
Envoy 的功能也不只是做流量转发,以上概念只不过是 Istio 在 Kubernetes 之上新增一层抽象层中的冰山一角,但因为流量管理是服务网格最基础也是最重要的功能,所以本文从这里开始,以后将给大家介绍更多关于服务网格的细节,请关注我的博客jimmysong.io 和istio-handbook。