如果你刚听说 Service Mesh 不久,并试用过 Istio 的话,那么你可能都会有下面几个疑问:
这一节我们将试图带您梳理清楚 Kubernetes、xDS 协议以及 Istio Service Mesh 之间的内在联系。此外,本节还将介绍 Kubernetes 中的负载均衡方式,xDS 协议对于 Service Mesh 的意义以及为什么说及时有了 Kubernetes 还需要 Istio。
使用 Service Mesh 并不是说与 Kubernetes 决裂,而是水到渠成的事情。Kubernetes 的本质是通过声明式配置对应用进行生命周期管理,而 Service Mesh 的本质是提供应用间的流量和安全性管理以及可观测性。假如你已经使用 Kubernetes 构建了稳定的应用平台,那么如何设置服务间调用的负载均衡和流量控制?
Envoy 创造的 xDS 协议被众多开源软件所支持,如 Istio、MOSN 等。Envoy 对于 Service Mesh 或云原生来说最大的贡献就是定义了 xDS,Envoy 本质上是一个 proxy,是可通过 API 配置的现代版 proxy,基于它衍生出来很多不同的使用场景,如 API Gateway、Service Mesh 中的 Sidecar proxy 和边缘代理。
本节包含以下内容
如果你想要提前了解下文的所有内容,那么可以先阅读下面列出的本文中的一些主要观点:
kube-proxy
组件的支持,通过为更接近微服务应用层的抽象,管理服务间的流量、安全性和可观测性。下图展示的是 Kubernetes 与 Service Mesh 中的的服务访问关系(每个 pod 一个 sidecar 的模式)。
流量转发
Kubernetes 集群的每个节点都部署了一个 kube-proxy
组件,该组件会与 Kubernetes API Server 通信,获取集群中的 service 信息,然后设置 iptables 规则,直接将对某个 service 的请求发送到对应的 Endpoint(属于同一组 service 的 pod)上。
服务发现
Istio 可以沿用 Kubernetes 中的 service 做服务注册,还可以通过控制平面的平台适配器对接其他服务发现系统,然后生成数据平面的配置(使用 CRD 声明,保存在 etcd 中),数据平面的透明代理(transparent proxy)以 sidecar 容器的形式部署在每个应用服务的 pod 中,这些 proxy 都需要请求控制平面来同步代理配置。之所以说是透明代理,是因为应用程序容器完全无感知代理的存在,该过程 kube-proxy 组件一样需要拦截流量,只不过 kube-proxy
拦截的是进出 Kubernetes 节点的流量,而 sidecar proxy 拦截的是进出该 Pod 的流量,详见理解 Istio Service Mesh 中 Envoy Sidecar 代理的路由转发。
Service Mesh 的劣势
因为 Kubernetes 每个节点上都会运行众多的 Pod,将原先 kube-proxy
方式的路由转发功能置于每个 pod 中,因为有 sidecar 拦截流量会多一次跳转时,增加响应延迟,同时大量的配置分发、配置同步,可能会影响应用性能。为了细粒度地进行流量管理,必将添加一系列新的抽象,从而会进一步增加用户的学习成本,但随着技术的普及,这样的情况会慢慢地得到缓解。
Service Mesh 的优势
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 入口流量负载均衡。
首先,如果转发的 pod 不能正常提供服务,它不会自动尝试另一个 pod,每个 pod 都有一个健康检查的机制,当有 pod 健康状况有问题时,kubelet 会重启对应的 pod,kube-proxy 会删除对应的转发规则。另外,nodePort
类型的服务也无法添加 TLS 或者更复杂的报文路由机制。
Kube-proxy 实现了流量在 Kubernetes service 多个 pod 实例间的负载均衡,但是如何对这些 service 间的流量做细粒度的控制,比如按照百分比划分流量到不同的应用版本(这些应用都属于同一个 service,但位于不同的 deployment 上),做金丝雀发布(灰度发布)和蓝绿发布?Kubernetes 社区给出了 使用 Deployment 做金丝雀发布的方法,该方法本质上就是通过修改 pod 的 label 来将不同的 pod 划归到 Deployment 的 Service 上。
上文说到 kube-proxy
只能路由 Kubernetes 集群内部的流量,而我们知道 Kubernetes 集群的 Pod 位于 CNI 创建的网络中,集群外部是无法直接与其通信的,因此 Kubernetes 中创建了 ingress 这个资源对象,它由位于 Kubernetes 边缘节点(这样的节点可以是很多个也可以是一组)的 Ingress controller 驱动,负责管理南北向流量,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 的功能与 Kubernetes Ingress 类似,都是负责集群的南北向流量。Istio Gateway
描述的负载均衡器用于承载进出网格边缘的连接。该规范中描述了一系列开放端口和这些端口所使用的协议、负载均衡的 SNI 配置等内容。Gateway 是一种 CRD 扩展,它同时复用了 sidecar proxy 的能力,详细配置请参考 Istio 官网。
下面这张图大家在了解 Service Mesh 的时候可能都看到过,每个方块代表一个服务的实例,例如 Kubernetes 中的一个 Pod(其中包含了 sidecar proxy),xDS 协议控制了 Istio Service Mesh 中所有流量的具体行为,即将下图中的方块链接到了一起。
xDS 协议是由 Envoy 提出的,在 Envoy v2 版本 API 中最原始的 xDS 协议指的是 CDS(Cluster Discovery Service)、EDS(Endpoint Discovery service)、LDS(Listener Discovery Service)和 RDS(Route Discovery Service),后来在 v3 版本中又发展出了 Scoped Route Discovery Service(SRDS)、Virtual Host Discovery Service(VHDS)、Secret Discovery Service(SDS)、Runtime Discovery Service(RTDS)等,详见 xDS REST and gRPC protocol。
下面我们以各有两个实例的 service,来看下 xDS 协议。
上图中的箭头不是流量进入 Proxy 后的路径或路由,也不是实际顺序,而是想象的一种 xDS 接口处理顺序,其实 xDS 之间也是有交叉引用的。
支持 xDS 协议的代理通过查询文件或管理服务器来动态发现资源。概括地讲,对应的发现服务及其相应的 API 被称作 xDS。Envoy 通过 订阅(subscription) 的方式来获取资源,订阅方式有以下三种:
path
参数中。ApiConfigSource
,指向对应的上游管理服务器的集群地址。以上的 xDS 订阅方式详情请参考 xDS 协议解析。Istio 使用 gRPC 流式订阅的方式配置所有的数据平面的 sidecar proxy。
最后总结下关于 xDS 协议的要点:
Envoy 是 Istio Service Mesh 中默认的 Sidecar,Istio 在 Envoy 的基础上按照 Envoy 的 xDS 协议扩展了其控制平面,在讲到 Envoy xDS 协议之前我们还需要先熟悉下 Envoy 的基本术语。下面列举了 Envoy 里的基本术语及其数据结构解析,关于 Envoy 的详细介绍请参考 Envoy 官方文档,至于 Envoy 在 Service Mesh(不仅限于 Istio)中是如何作为转发代理工作的请参考网易云刘超的这篇深入解读 Service Mesh 背后的技术细节 以及理解 Istio Service Mesh 中 Envoy 代理 Sidecar 注入及流量劫持,本文引用其中的一些观点,详细内容不再赘述。
下面是您应该了解的 Envoy 里的基本术语:
Envoy 中可以设置多个 Listener,每个 Listener 中又可以设置 filter chain(过滤器链表),而且过滤器是可扩展的,这样就可以更方便我们操作流量的行为,例如设置加密、私有 RPC 等。
xDS 协议是由 Envoy 提出的,现在是 Istio 中默认的 sidecar proxy,但只要实现 xDS 协议理论上都是可以作为 Istio 中的 sidecar proxy 的,例如蚂蚁集团开源的 MOSN。
Istio 是一个功能十分丰富的 Service Mesh,它包括如下功能:
Istio 中定义了如下的 CRD 来帮助用户进行流量管理:
DestinationRule
所定义的策略,决定了经过路由处理之后的流量的访问策略。简单的说就是定义流量如何路由。这些策略中可以定义负载均衡配置、连接池尺寸以及外部检测(用于在负载均衡池中对不健康主机进行识别和驱逐)配置。EnvoyFilter
对象描述了针对代理服务的过滤器,这些过滤器可以定制由 Istio Pilot 生成的代理配置。这个配置初级用户一般很少用到。ServiceEntry
能够在 Istio 内部的服务注册表中加入额外的条目,从而让网格中自动发现的服务能够访问和路由到这些手工加入的服务。在阅读完上文对 Kubernetes 的 kube-proxy
组件、xDS 和 Istio 中流量管理的抽象概念之后,下面将带您仅就流量管理方面比较下三者对应的组件/协议(注意,三者不可以完全等同)。
Kubernetes | xDS | Istio Service Mesh |
---|---|---|
Endpoint | Endpoint | WorkloadEntry |
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/MOSN 的功能也不只是做流量转发,以上概念只不过是 Istio 在 Kubernetes 之上新增一层抽象层中的冰山一角,但因为流量管理是服务网格最基础也是最重要的功能,所以这将成为本书的开始。
最后更新于 2024/11/07