Istio的架构,分为控制平面和数据面平两部分。
- 数据平面:由一组智能代理([Envoy])组成,被部署为 sidecar。这些代理通过一个通用的策略和遥测中心传递和控制微服务之间的所有网络通信。
- 控制平面:管理并配置代理来进行流量路由。此外,控制平面配置 Mixer 来执行策略和收集遥测数据。
下图展示了组成每个平面的不同组件:
架构图可以看到,主要分为两个平面,控制面主要包括Istio的一些组件,例如:Pilot、Mixer、Citadel等服务组件;数据面由伴随每个应用程序部署的代理程序Envoy组成,执行针对应用程序的治理逻辑。为了避免静态、刻板地描述组件,在介绍组件的功能前,我们先通过一个动态场景来了解图架构图中对象的工作机制,即观察前端服务对后台服务进行一次访问时,在 Istio 内部都发生了什么,以及 Istio 的各个组件是怎样参与其中的,分别做了哪些事情。
先简单理解
Pilot:提供服务发现功能和路由规则
Mixer:策略控制,比如:服务调用速率限制
Citadel:起到安全作用,比如:服务跟服务通信的加密
Sidecar/Envoy: 代理,处理服务的流量
架构图上带圆圈的数字代表在数据面上执行的若干重要动作。虽然从时序上来讲,控制面的配置在前,数据面执行在后,但为了便于理解,在下面介绍这些动作时以数据面上的数据流为入口,介绍数据面的功能,然后讲解涉及的控制面如何提供对应的支持,进而理解控制面上组件的对应功能。
(1)自动注入:(由架构图得知前端服务跟后端服务都有envoy,我们这里以前端服务envoy为例说明)指在创建应用程序时自动注入 Sidecar代理。那什么情况下会自动注入你?在 Kubernetes场景下创建 Pod时,Kube-apiserver调用管理平面组件的 Sidecar-Injector服务,然后会自动修改应用程序的描述信息并注入Sidecar。在真正创建Pod时,在创建业务容器的同时在Pod中创建Sidecar容器。
# 原始的yaml文件 apiVersion: apps/v1 kind: Deployment spec: containers: - name: nginx image: nginx ...省略
调用Sidecar-Injector服务之后,yaml文件会发生改变
# 原始的yaml文件 apiVersion: apps/v1 kind: Deployment spec: containers: - name: nginx image: nginx ...省略 # 增加一个容器image地址 containers: - name: sidecar image: sidecar ...省略
总结:会在pod里面自动生产一个代理,业务服务无感知
(2)流量拦截:在 Pod 初始化时设置 iptables 规则,当有流量到来时,基于配置的iptables规则拦截业务容器的入口流量和出口流量到Sidecar上。但是我们的应用程序感知不到Sidecar的存在,还以原本的方式进行互相访问。在架构图中,流出前端服务的流量会被 前端服务侧的 Envoy拦截,而当流量到达后台服务时,入口流量被后台服务V1/V2版本的Envoy拦截。
总结:每个pod中都会有一个代理来来拦截所有的服务流量(不管是入口流量还是出口流量)
(3)服务发现:前端服务怎么知道后端服务的服务信息呢?这个时候就需要服务发现了,所以服务发起方的 Envoy 调用控制面组件 Pilot 的服务发现接口获取目标服务的实例列表。在架构图中,前端服务内的 Envoy 通过 控制平面Pilot 的服务发现接口得到后台服务各个实例的地址,为访问做准备。
总结:Pilot提供了服务发现功能,调用方需要到Pilot组件获取提供者服务信息
(4)负载均衡:数据面的各个Envoy从Pilot中获取后台服务的负载均衡衡配置,并执行负载均衡动作,服务发起方的Envoy(前端服务envoy)根据配置的负载均衡策略选择服务实例,并连接对应的实例地址。
总结:Pilot也提供了负载均衡功能,调用方根据配置的负载均衡策略选择服务实例
(5)流量治理:Envoy 从 Pilot 中获取配置的流量规则,在拦截到 入口 流量和出口 流量时执行治理逻辑。比如说,在架构图中,前端服务的 Envoy 从 Pilot 中获取流量治理规则,并根据该流量治理规则将不同特征的流量分发到后台服务的v1或v2版本。当然,这只是Istio流量治理的一个场景,Istio支持更丰富的流量治理能力。
总结:Pilot也提供了路由转发规则
(6)访问安全:在服务间访问时通过双方的Envoy进行双向认证和通道加密,并基于服务的身份进行授权管理。在架构图中,Pilot下发安全相关配置,在前端模块服务和后端服务的Envoy上自动加载证书和密钥来实现双向认证,其中的证书和密钥由另一个控制平面组件Citadel维护。
总结:Citadel维护了服务代理通信需要的证书和密钥
(7)服务遥测:在服务间通信时,通信双方的Envoy都会连接控制平面组件Mixer上报访问数据,并通过Mixer将数据转发给对应的监控后端。比如说,在架构图中,前端模块服务对后端服务的访问监控指标、日志和调用链都可以通过Mixer收集到对应的监控后端。
总结:Mixer组件可以收集各个服务上的日志,从而可以进行监控
(8)策略执行:在进行服务访问时,通过Mixer连接后端服务来控制服务间的访问,判断对访问是放行还是拒绝。在架构图中,数据面在转发服务的请求前调用Mixer接口检查是否允许访问,Mixer 会做对应检查,给代理(Envoy)返回允许访问还是拒绝, 比如:可以对前端模块服务到后台服务的访问进行速率控制。
总结:Mixer组件可以对服务速率进行控制(也就是限流)
(9)外部访问:在架构图中,外部服务通过Gateway访问入口将流量转发到服务前端服务内的Envoy组件,对前端服务的负载均衡和一些流量治理策略都在这个Gateway上执行。
**总结:**这里总结在以上过程中涉及的动作和动作主体,可以将其中的每个过程都抽象成一句话:服务调用双方的Envoy代理拦截流量,并根据控制平面的相关配置执行相应的服务治理动作,这也是Istio的数据平面和控制平面的配合方式。
Pilot在Istio架构中必须要有
思考: 为什么Envoy能够服务发现?并且Envoy为什么可以流量控制?
就是因为Pilot存在
什么是Pilot
Pilot类似传统C/S架构中的服务端Master,下发指令控制客户端完成业务功能。和传统的微服务架构对比,Pilot 至少涵盖服务注册中心和向数据平面下发规则 等管理组件的功能。
服务注册中心
如图下图所示,Pilot 为 Envoy sidecar 提供服务发现、用于智能路由的流量管理功能(例如,A/B 测试、金丝雀发布等)以及弹性功能(超时、重试、熔断器等)。
Pilot本身不做服务注册,它会提供一个API接口,对接已有的服务注册系统,比如Eureka,Etcd等。
说白了,Pilot可以看成它是Sidecar的一个领导
(1)Platform Adapter是Pilot抽象模型的实现版本,用于对接外部的不同平台
(2)Polit定了一个抽象模型(Abstract model),处理Platform Adapter对接外部不同的平台, 从特定平台细节中解耦
(3)Envoy API负责和Envoy的通讯,主要是发送服务发现信息和流量控制规则给Envoy流程总结: service服务C会注册到Pilot注册中心平台适配器(Platform Adapter)模块上(假如对接的是Eureka, 那么service服务C会注册到Eureka里面),然后抽象模型(Abstract model)进行平台细节的解耦并且用于处理Platform Adapter对接外部的不同平台,最后通过Envoy API负责和Envoy的通讯,主要是发送服务发现信息和流量控制规则给Envoy
数据平面下发规则
Pilot 更重要的一个功能是向数据平面下发规则,Pilot 负责将各种规则转换换成 Envoy 可识别的格式,通过标准的 协议发送给 Envoy,指导Envoy完成动作。在通信上,Envoy通过gRPC流式订阅Pilot的配置资源。
Pilot将表达的路由规则分发到 Evnoy上,Envoy根据该路由规则进行流量转发,配置规则和流程图如下所示。
规则如下:
# http请求
http:
-match: # 匹配
-header: # 头部
cookie:
# 以下cookie中包含group=dev则流量转发到v2版本中
exact: "group=dev"
route: # 路由
-destination:
name: v2
-route:
-destination:
name: v1
Mixer在Istio架构中不是必须的
Mixer分为Policy和Telemetry两个子模块,Policy用于向Envoy提供准入策略控制,黑白名单控制,速率限制等相关策略;Telemetry为Envoy提供了数据上报和日志搜集服务,以用于监控告警和日志查询。
Telemetry介绍
Mixer是一个平台无关的组件。Mixer的Telemetry 在整个服务网格中执行访问控制和策略使用,并从 Envoy 代理和其他服务收集遥测数据,流程如下图所示。
- 遥测报告上报,比如从Envoy中收集数据[请求数据、使用时间、使用的协议等],通过Adapater上
报给Promethues、Heapster等
说白了,就是数据收集,然后通过adapter上传到监控容器里面
policy介绍
policy是另外一个Mixer服务,和istio-telemetry基本上是完全相同的机制和流程。数据面在转发服务的请求前调用istio-policy的Check接口是否允许访问,Mixer 根据配置将请求转发到对应的 Adapter 做对应检查,给代理返回允许访问还是拒绝。可以对接如配额、授权、黑白名单等不同的控制后端,对服务间的访问进行可扩展的控制。
- 策略控制:检查请求释放可以运行访问
Citadel在Istio架构中不是必须的
Istio的认证授权机制主要是由Citadel完成,同时需要和其它组件一起配合,参与到其中的组件还有Pilot、Envoy、Mixer,它们四者在整个流程中的作用分别为:
- Citadel:用于负责密钥和证书的管理,在创建服务时会将密钥及证书下发至对应的Envoy代理中;
- Pilot: 用于接收用户定义的安全策略并将其整理下发至服务旁的Envoy代理中;
- Envoy:用于存储Citadel下发的密钥和证书,保障服务间的数据传输安全;
- Mixer: 负责核心功能为前置条件检查和遥测报告上报;
流程如下
具体工作流程可描述如下:
- Kubernetes某集群节点新部署了服务Service,此时集群中有两个Pod被启动,每个Pod由Envoy代理容器和Service容器构成,在启动过程中Istio的Citadel组件会将密钥及证书依次下发至每个Pod中的Envoy代理容器中,以保证后续服务A,B之间的安全通信。
- 用户通过Rules API下发安全策略至Pilot组件,Pilot组件通过Pilot-discovery进程整理安全策略中Kubernetes服务注册和配置信息并以Envoy API方式暴露给Envoy。
- Pod 中的Envoy代理会通过Envoy API方式定时去Pilot拉取安全策略配置信息,并将信息保存至Envoy代理容器中。
- 当pod内的服务相互调用时,会调用各自Envoy容器中的证书及密钥实现服务间的通信,同时Envoy容器还会根据用户下发的安全策略进行更细粒度的访问控制。
- Mixer在整个工作流中核心功能为前置条件检查和遥测报告上报,在每次请求进出服务时,服务中的Envoy代理会向Mixer发送check请求,检查是否满足一些前提条件,比如ACL检查,白名单检查,日志检查等,如果前置条件检查通过,处理完后再通过Envoy向Mixer上报日志,监控等数据,从而完成审计工作。
使用场景:
在有一些场景中,对于安全要求是非常高的,比如支付,所以Citadel就是用来保证安全的。
回顾kubernetes API Server的功能: * 提供了集群管理的REST API接口(包括认证授权、数据校验以及集群状态变更); * 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd); * 资源配额控制的入口; * 拥有完备的集群安全机制.
总结:
用于负责密钥和证书的管理,在创建服务时会将密钥及证书下发至对应的Envoy代理中
Galley在istio架构中不是必须的
Galley在控制面上向其他组件提供支持。Galley作为负责配置管理的组件,并将这些配置信息提供给管理面的 Pilot和 Mixer服务使用,这样其他管理面组件只用和 Galley打交道,从而与底层平台解耦。
galley优点
- 配置统一管理,配置问题统一由galley负责
- 如果是相关的配置,可以增加复用
- 配置跟配置是相互隔离而且,而且配置也是权限控制,比如组件只能访问自己的私有配置
MCP协议
Galley负责控制平面的配置分发主要依托于一一种协议,这个协议叫(MCP)
MCP提供了一套配置订阅和分发的API,里面会包含这个几个角色:
- source: 配置的提供端,在istio中Galley即是source 说白了就是Galley组件,它提供yaml配置
- sink:配置的消费端,istio组件中Pilot和Mixer都属于sink
- resource: source和sink关注的资源体,也就是yaml配置
Galley 代表其他的 Istio 控制平面组件,用来验证用户编写的 Istio API 配置。Galley 接管 Istio 获取配置、 处理和分配组件的顶级责任。它将负责将其他的 Istio 组件与从底层平台(例如 Kubernetes)获取用户配置的细节中隔离开来。
说白了:这样其他控制平面(Pilot和 Mixer)面组件只用和 Galley打交道,从而与底层平台解耦。
Sidecar-injector 是负责自动注入的组件,只要开启了自动注入,那么在创建pod的时候就会自动调用Sidecar-injector 服务
配置参数:istio-injection=enabled,我们后面会有案例演示
在istio中sidecar注入有两种方式
- 需要使用istioctl命令手动注入 (不需要配置参数:istio-injection=enabled)
- 基于kubernetes自动注入(配置参数:istio-injection=enabled)
手动注入和自动注入会在istio安装之后案例演示
两种区别:
手动注入需要每次在执行配置都需要加上istioctl命令
自动注入只需要做一下开启参数即可
sidecar模式具有以下优势
- 把业务逻辑无关的功能抽取出来(比如通信),可以降低业务代码的复杂度
- sidecar可以独立升级、部署,与业务代码解耦
注入流程
在 Kubernetes环境下,根据自动注入配置,Kube-apiserver在拦截到 Pod创建的请求时,会调用自动注入服务 istio-sidecar-injector 生成 Sidecar 容器的描述并将其插入原 Pod的定义中,这样,在创建的 Pod 内, 除了包括业务容器,还包括 Sidecar容器。这个注入过程对用户透明,用户使用原方式创建工作负载。
总结:sidecar模式具有以下优势
Proxy是Istio数据平面的轻量代理。
Envoy是用C++开发的非常有影响力的轻量级高性能开源服务代理。作为服务网格的数据面,Envoy提供了动态服务发现、负载均衡、TLS、HTTP/2 及 gRPC代理、熔断器、健康检查、流量拆分、灰度发布、故障注入等功能。
Envoy 代理是唯一与数据平面流量交互的 Istio 组件。
Envoy组件解析
为了便于理解Istio中Envoy与服务的关系,如图所示:
一个pod里面运行了一个Envoy容器和service A容器,而Envoy容器内部包含了两个进程,分别是Pilot-agent和Envoy两个进程
pilot-agent
pilot-agent跟Envoy打包在同一个docker镜像里面
- pilot-agent作用
* 生成envoy配置 * 启动envoy * 监控envoy的运行状态,比如envoy出错是pilot-agent负责重启envoy,huozhe envoy配置变更之后reload envoy
Envoy
负责拦截pod流量,负责从控制平面pilot组件获取配置和服务发现,上报数据给mixer组件
ingressgateway 就是入口处的 Gateway,从网格外访问网格内的服务就是通过这个Gateway进行的。ingressgateway比较特别,是一个Loadbalancer类型的Service,不同于其他服务组件只有一两个端口,ingressgateway 开放了一组端口,这些就是网格内服务的外部访问端口。
网格入口网关ingressgateway和网格内的 Sidecar是同样的执行体,也和网格内的其他 Sidecar一样从 Pilot处接收流量规则并执行。因为入口处的流量都走这个服务。
流程图如下
由于gateway暴露了一个端口,外部的请求就可以根据这个端口把请求发给gateway了然后由gateway把请求分发给网格内部的pod上
在Istio集群中一般还安装grafana、Prometheus、Tracing组件,这些组件提供了Istio的调用链、监控等功能,可以选择安装来完成完整的服务监控管理功能。
总结
主要介绍了一些常见的istio组件,其中有一些组件是istio默认就已经使用了,有一些组件我们后面也会来演示。