原文 https://thenewstack.io/why-do-you-need-istio-when-you-already-have-kubernetes/
K8s本质上是对基于声明式配置的应用 做生命周期管理,Istio本质上是做应用内流量治理,安全治理和可观察性。如果你已经用K8s构建了一个稳定的应用,你如何在两个服务之间配置一个负载均衡和流控?这时我们就需要Istio登场了。
Envoy引入的xDS协议,被包含Istio,MOSN在内的众多开源软件支持。Istio开源了xDS作为ServiceMesh,云原生基础设置。Envoy能胜任可基于API配置的,多种现代的代理场景,如API网关,ServiceMesh边车代理网关,边界网关。
本文包含如下内容:
- kube-proxy角色的描述
- K8s对于微服务治理的局限性。
- 对istio能力的介绍
- 对一些概念的对比,K8s,Envoy,ServiceMesh
Kubernetes vs Service Mesh
下面的示意图K8s和ServiceMesh(每Pod1sidecar模型)在服务访问上的区别。
流量转发
每个K8s的节点都部署了一个可以和APIServer通信的kube-proxy,获取集群信息,配置iptables,把请求直接发给EndPoint。
服务发现
Istio可以使用K8s的服务注册,也可以通过控制面的适配器(Adapter)对接其他服务发现系统生成数据面的透明代理的配置(作为CRD保存在etcd中)。数据面的透明代理作为边车容器部署在每个应用的Pod中,所有这些边车容器都会请求控制面来同步代理配置。这里说代理是“透明”的,是因为应用容器完全感觉不到代理的存在。kube-proxy组件也需要拦截流量,区别在于kube-proxy拦截进出K8s Node的流量,而边车(sidecar)代理是拦截进出Pod的流量。
ServiceMesh的缺点
当K8s每个节点都跑了大量Pod时,给每个Pod添加原始路由转发将会增加响应的延迟,这是因为边车拦截带来了更多的跳数也消耗了更多资源。为了细粒度管理流量,Istio引入了一系列抽象,这会带来更多的学习成本,但是随着Istio逐渐流行,这个情况会缓解。
ServiceMesh的优点
首先,kube-proxy的配置是全局的,不能从服务的粒度管理,然而,Istio基于边车代理能做到更细的流量管理,带来更多弹性。
Kube-proxy的缺点
首先,当某个Pod不能正常工作时,它不会自动尝试另一个Pod。每个Pod都有健康检查机制,当Pod健康检查出问题时,kubelet将会重启Pod,kube-proxy将会移除相关转发规则。此外,NodePort模式的Service不支持TLS,或者其他更负责的路由机制。
kube-proxy实现同一个Service的多个Pod之间的负载均衡。但是你怎么做多个Service之间的细粒度管理,比如根据应用的版本,按照百分比切分流量(他们都是同一个Service,但是不同的部署)或者做金丝雀发布(灰度发布)或者蓝绿发布?
Kubernetes社区给出了一种方式来用部署做金丝雀发布:本质上就是通过给部署的Pod打标签。
Kubernetes Ingress vs. Istio Gateway
Kubernetes Ingress
如上面所说,kube-proxy只能路由K8s集群内的流量。K8s的Pod是通过CNI创建的网络中定位的。Ingress 是专门用于和集群外通信的K8s中的资源对象,是由位于K8s边缘节点的Ingress控制器来驱动的,负责管理南北向流量。Ingress必须依赖Ingress控制器,比如nginx controller和 traefik。Ingress只适配Http流量,非常简单易用。它只能通过匹配有限的几个字段来路由流量,比如service,port,path等。路由比如mysql,redis和其他rpc等tcp流量是不可能的。这就是为何你在ingress资源注解中别人会写nginx配置语言。直接路由南北流量的唯一方式就是使用Service的LoadBalancer模式或者NodePort模式,前者依赖云供应商的支持,后者需要额外的端口管理。
Istio Gateway
Istio Gateway功能上和Ingress 类似,那就是负责南北向流量进出集群。Istio Gateway规范描述了负责在网格边缘接收链接的负载均衡。规范还描述了一系列端口和使用这些端口的协议,比如负载均衡的SNI配置。Gateway是CRD扩展也服用了边车代理的能力,看这里的详细配置 https://istio.io/latest/docs/reference/config/networking/gateway/?utm_source=thenewstack&utm_medium=website&utm_campaign=platform
Envoy
Envoy是Istio的默认边车代理。Istio扩展了其基于xDS控制面的协议。我们在讨论xDS协议之前需要先熟悉下相关术语。下图是协议的基本项和他们在Envoy中的结构,看这里有细节:
https://www.envoyproxy.io/?utm_source=thenewstack&utm_medium=website&utm_campaign=platform
基本术语
下游(Downstream)下游Host链接Envoy,发送请求,接收响应;就是我们发送请求的Host。
上游(Upstream)上游接收来自Envoy的链接和请求,返回响应;也就是接收请求的Host。
监听器(Listener)listener是实名网络地址(比如端口,unix domain socket)下游客户端能链接监听器,Envoy会暴露一两个监听器给下游Host来连接。
集群(Cluster)一个集群是一组供Envoy连接的逻辑独立的上游Host。Envoy通过服务发现发现集群的成员。集群的成员的健康状态由主动健康检查决定,Envoy根据负责均衡策略决定路由到集群那个成员。
Envoy可以配置多个Listener,每个Listener可以配置一个过滤器链,过滤器链是可扩展的,我们可以简单的修改流量的行为,比如加密和私有rpc等。
xDS协议是Envoy提议的,是Istio默认边车代理,但是只要实现了xDS协议,那它理论上就能当作Istio的边车代理,比如蚂蚁集群开源的MOSN。
Istio是功能丰富的ServiceMesh,包含如下能力:
流量治理:Istio最基本的功能
策略控制:访问控制,遥测,配额管理,账单。
可观察性:在边车代理中实现。
安全认证:Citadel组件负责key和证书管理。
流量治理
下面的CRD是Istio用来做流量治理的:
Gateway:描述了一个运行在边缘网络的负载均衡器用来接收入站出站的TCP,Http连接。
VirtualService:实际上把Gateway和K8s Service 连接到一起。还提供了额外的操作:比如定义一组能应用于某个Host上的流量路由规则。
DestinationRule:DestinationRule定义了路由后的流量策略。简单来说,它定义了流量是如何路由的。此外还能定义负载均衡策略,连接池大小,还有一些探测(比如从连接池中移除不健康的节点)。
EnvoyFilter:此配置描述了proxy的过滤器,一般由pilot自动生成,通常很少有用户会用到。
ServiceEntry:默认情况下,Istio ServiceMesh中的Service没有能力对mesh外部做服务发现。ServiceEntry允许额外的服务加入到Isito的服务注册中来,并允许mesh内自动发现的服务访问并路由那些手动加入的service。
Kubernetes vs. xDS vs. Istio
回顾过k8s kube-proxy,xDS, and 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 |
总结
k8s的职责在于应用的生命周期管理,尤其是部署和管理(扩展,自动回复,释放)。
k8s为微服务提供了一个可扩展,高可靠的部署管理平台。
service mesh是基于透明代理的,在服务之间通过边车拦截流量,通过控制面管理流量的。
service mesh将流量治理从k8s中解耦出来,消除了service mesh内流量治理对于kube-proxy的依赖;通过提供更接近微服务应用层的抽象,来管理Service的流量,安全,可观察性。
xDS是ServiceMesh配置的标准协议之一。
ServiceMesh是K8s的服务的更高层次的抽象。
结论
如果说K8s管理的对象是Pod,那么ServiceMesh管理的对象就是Service,实际上就是K8s来管理微服务在上层应用ServiceMesh。如果你甚至不想管理微服务,你可以使用KNative这样的Serverless平台,但这是后话了。