服务化改造架构:
为了解决服务跟服务如何相互调用,需要一个程序之间的通信协议,把一些共用重复的服务提出来作为基础服务,应用通过调用RPC接口进行使用,让服务之间的程序调用变得像本地调用一样的简单。
服务治理:
随着业务的增大,基础服务越来越多,调用网的关系由最初的几个增加到几十上百,造成了调用链路错综复杂,需要对服务进行治理。
服务治理要求:
1、当我们服务节点数几十上百的时候,需要对服务有动态的感知,引入了注册中心。
2、当服务链路调用很长的时候如何实现链路的监控。
3、单个服务的异常,如何能避免整条链路的异常(雪崩),需要考虑熔断、降级、限流。
4、服务高可用:负载均衡
典型框架比如有:Dubbo,默认采用的是Zookeeper作为注册中心。
微服务时代:
分布式微服务时代,拆分原则是任何一个需求不会因为发布或者维护而影响到不相关的服务,一切可以做到独立部署运维。
比如传统的“用户中心”服务,对于微服务来说,需要根据业务再次拆分,可能需要拆分成“买家服务”、“卖家服务”、“商家服务”等。每个服务不会影响到其他服务,做到独立部署运维。
典型代表:Spring Cloud,相对于传统分布式架构,SpringCloud使用的是HTTP作为RPC远程调用,配合上注册中心Eureka和API网关Zuul,可以做到细分内部服务的同时又可以对外暴露统一的接口,让外部对系统内部架构无感,此外Spring Cloud的config组件还可以把配置统一管理。
问题解决思路
非业务代码:如网络协议、流量控制、数据包接收与发送。对这种非业务代码进行下沉。 —— 如通过Sidecar
SideCar
它降低了与微服务架构相关的复杂性,并且提供了负载均衡、服务发现、流量管理、电路终端、故障注入等功能特性。
Sidecar模式是一种将应用功能从应用本身剥离出来作为单独进程的方式。该模式允许我们向应用无侵入添加多种功能,避免了为满足第三方组件需求而向应用添加额外的配置代码。
比传统代理功能更加丰富。让每个服务都有独立的代理,
从图可以看出,服务的业务代码和Sidecar绑定到一起,每一个服务都配置了Sidecar代理,每个服务所有流量都需要通过Sidecar,Sidecar实现了通信相关的事情(可以理解为代理,管理治理服务的进出口流量)。
Linkerd
Linkerd比SideCar增加了更多服务治理的功能,比如说增加一些数据上报、日志收集、链路监控。
Linkerd很好地结合了Kubernetes所提供的功能,以此为基础,
Istio
通过Istio,可以轻松创建带有负载平衡,服务到服务的身份验证,监视等功能的已部署服务网络,使得服务中的代码更改很少或没有更改。 通过在整个环境中部署一个特殊的sidecar代理来拦截微服务之间的所有网络通信,然后使用其控制平面功能配置和管理,可以为服务添加Istio支持。
Istio既有数据平面也有控制平面。linkerd只有数据平面
服务网格
如果每一个格子都是一个sidecar数据平面,然后sidecar进行彼此通信,那么Servicemesh就是来管理每个格子的控制平面,这就是服务网格,从架构层面看起来跟网格很像。(Servicemesh管理Sidecar)
服务网格是一个独立的基础设施层,用来处理服务之间的通信,现代的云原生应用是由各种复杂技术构建的服务体系,服务网络负责在这些组成部分之间进行可靠的请求传递。目前典型的服务网格通常提供了一组轻量级的网络代理,这些代理会在应用无感知的情况下,同应用并行部署、运行。
特点:
Service Mesh:
解决开发与运维部署分布式微服务面临的问题,可以包括服务发现、负载平衡、故障恢复、度量和监视,服务网格通常还具有更复杂的操作需求,如A/B测试、速率限制、访问控制和端到端身份验证。
CNCF是一个开源软件基金会,致力于使云原生计算具有普遍性和可持续性。云原生计算使用开源软件技术栈将应用程序部署为微服务,将每个部分打包到自己的容器中,并动态编排这些容器以优化资源利用率。云原生技术使软件开发人员能够跟快地构建出色的产品。
服务网格是一个独立的基础设施层,用来处理服务之间的通信,现代的云原生应用是由各种复杂技术构建的服务体系,服务网络负责在这些组成部分之间进行可靠的请求传递。目前典型的服务网格通常提供了一组轻量级的网络代理,这些代理会在应用无感知的情况下,同应用并行部署、运行。
Istio有助于降低部署的复杂性,并减轻开发团队的压力。它是一个完全开放源代码的服务网格,透明地分层到现有的分布式应用程序上,它也是一个平台,包括允许它集成到任何日志平台、遥测或策略系统中的api。Istio的多种功能集使我们能够成功、高效地运行分布式微服务体系架构,并提供一种统一的方式来保护、连接和监控微服务。
Istio是基于Sidecar模式,包含了数据和控制平面,是Service Mesh的一种解决方案。
数据平面:处理流量的一些数据信息。
控制平面:控制数据平面,控制代理哪些流量由谁处理。
微服务错综复杂,要完成其业务目标,连接问题是首要问题。连接存在于所有服务的整个生命周期中,用于维持服务的运行,算得上重中之重。
相对于传统的单体应用,微服务的端点数量会急剧增加,现代的应用系统在部分或者全部生命周期中,都存在同一服务的不同版本,为不同的客户、场景或业务提供不同的服务。同时,同一服务的不同版本也可能有不同的访问要求,甚至产生了在生产环境中进行测试的新方法论。错综复杂的服务关系对开发者来说都是很严峻的考研。
安全也是一个常谈常新的话题,在过去私有基础设施结合单体应用的环境下,这一问题并不突出,然而进入容器云时代之后,以下问题出现了。
(1)有大量容器漂浮在容器云中,采用传统的网络策略应对这种浮动的应用是比较吃力的。
(2)在由不同的语言、平台所实现的微服务之间,实施一致的访问控制也经常会因为实现的不一致而困难重重。
(3)如果是共享集群,则服务的认证和加密变得尤为重要,例如:
总之,要提供网格内部的安全保障,就应具备服务通信加密、服务身份认证和服务访问控制(授权和鉴权)功能。
上述功能通常需要数字证书的支持,这就隐藏了对CA的需求,即需要完成证书的签发、传播和更新业务。
除了上述核心要求,还存在对认证失败的处理、外部证书(统一CA)的接入等相关支撑内容。
Istio 通过可动态插拔、可扩展的策略实现访问控制、速率限制、配额管理等功能使得资源在消费者之间公平分配。
在Istio中使用Mixer作为策略的执行者,Envoy的每次调用,在逻辑上都会通过Mixer进行事先预检和事后报告,这样Mixer就拥有了对流量的部分掉制能力;在Istio中还有为数众多的内部适配器及进程外适配器,可以和外部软件设施一起完成策略的制定和执行。
Mixer:Mixer在整个服务网格中执行访问控制和策略执行,并从Envoy代理和其他服务收集遥测数据。
Envoy:在istio框架中使用Envoy作为代理,使用的是C++开发的软件,用于为服务网格中的所有服务提供所有的入站和出站流量,唯一一个与数据平面打交道的。
微服务系统监控,除了有传统的主机监控,还更加重视高层次的服务健康监控。
服务的健康情况往往不是非黑即白的离散值,而是一系列连续状态,例如我们经常需要关注服务的调用成功率、响应时间、调用量、传输量等表现。
而且,面对数量众多的服务,我们应该能对各种级别和层次的指标进行采样、采集及汇总,获取较为精密、翔实的运行数据,最终通过一定的方法进行归纳总结和展示。
与此同时,服务网格还应提供分布式跟踪功能,对服务的调用链路进行跟踪。
观察性:动态获取服务运行数据和输出,提供强大的调用链、监控和调用日志收集输出的能力。配合可视化工具,可方便运维人员了解服务的运行状况,发现并解决问题。
Istio是一个服务治理平台,治理的是服务间的访问,只要有访问就可以治理,不在乎这个服务是不是所谓的微服务,也不要求跑的代码是微服务化。单体应用不满足微服务Istio治理也是完全可以的。提起“服务治理”,大家最先想到的一定是“微服务的服务治理”。
服务治理的演变至少经过了以下三种形态。
第1种形态:在应用程序中包含治理逻辑
治理的功能写在业务代码里面。
在微服务化的过程中,将服务拆分后会发现一堆麻烦事儿,连基本的业务连通都成了问题。在处理一些治理逻辑,比如怎么找到对端的服务实例,怎么选择一个对端实例发出请求,都需要自己写代码来实现。这种方式简单,对外部依赖少,但会导致存在大量的重复代码。所以,微服务越多,重复的代码越多,维护越难;而且,业务代码和治理逻辑耦合,不管是对治理逻辑的全局升级,还是对业务的升级,都要改同一段代码。
第2种形态:治理逻辑独立的代码
治理代码写在公共库,需要jar包依赖,需要进行注解、配置。业务代码和服务治理需要一起编译。
在解决第1种形态的问题时,我们很容易想到把治理的公共逻辑抽象成一个公共库,让所有微服务都使用这个公共库。在将这些治理能力包含在开发框架中后,只要是用这种开发框架开发的代码,就包含这种能力,非常典型的这种服务治理框架就是Spring cloud。这种形态的治理工具在过去一段时间里得到了非常广泛的应用。
SDK模式虽然在代码上解耦了业务和治理逻辑,但业务代码和SDK还是要一起编译的,业务代码和治理逻辑还在一个进程内。这就导致几个问题:业务代码必须和SDK基于同一种语言,即语言绑定。例如,Spring Cloud等大部分治理框架都基于Java,因此也只适用于Java语言开发的服务。经常有客户抱怨自己基于其他语言编写的服务没有对应的治理框架;在治理逻辑升级时,还需要用户的整个服务升级,即使业务逻辑没有改变,这对用户来说是非常不方便的。
第3种形态:治理逻辑独立的进程
所有通信的操作都需要经过代理,业务代码只需要关心自己的业务就可以了。
SDK模式仍旧侵入了用户的代码,那就再解耦一层,把治理逻辑彻底从用户的业务代码中剥离出来,这就是前面提过的sidecar模式,显然,在这种形态下,用户的业务代码和治理逻辑都以独立的进程存在,两者的代码和运行都无耦合,这样可以做到与开发语言无关,升级也相互独立。在对已存在的系统进行微服务治理时,只需搭配sidecar即可,对原服务无须做任何修改,并且可以对老系统渐进式升级改造,先对部分服务进行微服务化。
Kubernetes是一款用于管理容器化工作的负载和服务的可移植、可扩展的开源平台,拥有庞大、快速发展的生态系统,它面向基础设施,将计算、网络、存储等资源进行紧密整合,为容器提供最佳运行环境,并面向应用提供封装好的、易用的工作负载与服务编排接口,以及运维所需的资源规格、弹性、运行参数、调度等配置管理接口,是新一代的云原生基础设施平台。
从平台架构而言,Kubernetes的设计围绕平台化理念,强调插件化设计与易扩展性,这是它与其他同类系统的最大区别之一,保障了对各种不同客户应用场景的普遍适应性。另外,Kubernetes与其他容器编排系统的显著区别是Kubernetes并不把无状态化、微服务化等条件作为可运行的工作负载的约束。
如今,容器技术已经进入产业落地期,而Kubernetes作为容器平台的标准已经得到了广泛应用。
Istio给Kubernetes带来什么?
K8s的Service机制也已经可以做服务注册、服务发现和负载均衡,支持通过服务名访问到服务实例。
从微服务的工具集观点来看,Kubernetes本身是支持微服务的架构,在Pod中部署微服务很合适,也已经解决了微服务的互访互通问题,但对服务间访问的管理如服务的熔断、限流、动态路由、调用链追踪等都不在K8s的能力范围内。
那么,如何提供一套从底层的负载部署运行到上层的服务访问治理端到端的解决方案?
Kubernetes本身并不支持服务治理能力,通过加入Istio可以实现服务治理(服务熔断、服务限流、服务调用链路跟踪能力。)
Kubernetes可以帮Istio实现什么呢?
1、数据平面(sidecar运行在pod里面,业务感知不到sidecar。通过一个pod可以运行多个容器这个特点来实现)
Ingress 来创建一个统一的负载均衡器,可以让外部请求访问到K8s内部的资源上
Service与Ingress
3、基于CRD规则扩展自定义资源
istio通过CRD规则自定义资源,而资源数据通过apiserver保存到etcd里面。
lstio的所有路由规则和控制策略都是通过Kubernetes CRD实现的,因此各种规则策略对应的数据也被存储在Kube-apiserver中,不需要另外一个单独的APIServer和后端的配置管理。所以,可以说Istio的APIServer就是Kubernetes的APIServer,数据也自然地被存在了对应Kubernetes的etcd中。
4、结论:
Istio和Kubernetes架构的关系,可以看出,Istio不仅数据面Envoy跑在Kubernetes的Pod里,其控制面也运行在Kubernetes集群中,其控制面组件本身存在的形式也是以Kubernetes Deployment和Service,基于Kubernetes扩展和构建。
云原生应用采用Kubernetes构建应用编排能力,采用Istio构建服务治理能力,将逐渐成为企业技术转型的标准配置。
Istio的架构,分为控制平面和数据平面两部分。
1、Pilot提供服务发现和路由规则
2、Mixer策略控制,比如:对服务调用限速
3、Citadel:起安全作用,通信的证书和密钥,比如:可以保证服务跟服务通信安全
4、Envoy:代理服务的流量
前端Envoy向Pilot获取后台服务的负载均衡配置,然后根据Pilot路由规则,把流量分发给后台指定的版本上面,达到前端和后台的通信。为了保证通信安全,Envoy还需要从控制平面接到Citadel获取证书和密钥,确保Envoy通信安全。最后通信双方的Envoy都会连接到Mixer,上报访问的数据,Mixer达到控制数据,监控数据的目的。
架构图中的功能点讲解:
1、自动注入
创建Pod时,里面有一个组件叫api-server,来调用控制平面组件sidecar-injector服务。
sidecar-injector:会修改应用程序的描述信息(yaml文件,追加sidecar这个container),注入sidecar
2、流量拦截
pod在创建的时候会设置iptables的路由规则。
3、服务发现
如何进行流量分发,把流量发到后台上?前台服务发起方Envoy需要到控制平面来Pilot服务发现接口,从而获取后台目标服务的实例列表。
4、负载均衡
获取Pilot负载均衡配置,根据请求来选择服务实例。但是没有一个具体的流量动作。
6、访问安全
通信加密所需要的证书和密钥统一由控制平面Citadel维护。
7、服务监控
服务间通信时会连接到控制平面Mixer进行数据上报,而Mixer会通过Adapter,会把数据发送给监控的后端(如一些监控工具)。
8、策略执行
控制服务与服务的访问是拒绝还是发送,
例如:数据平面的前端服务把请求转发给后端服务,前端服务需要去调用控制平面Mixer来检查这个请求是通过还是放行。
9、外部访问
外部所有请求都要经过网关,网关转发给前端的Envoy。
**思考:**为什么Envoy能够服务发现?并且Envoy为什么可以流量控制?
就是因为Pilot存在,Pilot在Istio架构中必须要有。
什么是Pilot
Pilot类似传统C/S架构中的服务端Master,下发指令控制客户端完成业务功能。和传统的微服务架构对比,Pilot至少涵盖服务注册中心和向数据平面下发规则等管理组件的功能。
服务注册中心
如图下图所示,Pilot为Envoy、sidecar提供服务发现、用于智能路由的流量管理功能(例如,A/B测试、金丝雀发布等)以及弹性功能(超时、重试、熔断器等)。
Pilot本身不做服务注册,它会提供一个API接口,对接已有的服务注册系统,比如Eureka,Etcd等。
说白了,Pilot可以看成它是sidecar的一个领导。
Platform Adapter:主要用来对接外部不同注册中心厂商,如Eureka和Etcd。
Abstract model:处理Adapter对接外部不同平台,从特定平台中细节中解耦。
Enovy API:负责与Pod里面的Envoy代理进行通信,主要是发送服务发现信息和流量控制规则给Envoy。
数据平面下发规则
如图:前端Envoy代理请求到Pilot获取服务发现,再根据Pilot数据平面下发规则,前端服务根据规则进行转发到后台服务。(Pilot组件主要是提供服务发现和路由转发规则)
Mixer在Istio架构中不是必须的。
Mixer分为Policy和Telemetry两个子模块:
Telemetry介绍:
Mixer是一个平台无关的组件。Mixer的Telemetry在整个服务网格中执行访问控制和策略使用,并从Envoy代理和其他服务收集遥测数据,流程如下图所示。
Policy介绍
policy是另外一个Mixer服务,和istio-telemetry基本上是完全相同的机制和流程。数据面在转发服务的请求前调用istio-policy的Check接口是否允许访问,Mixer根据配置将请求转发到对应的Adapter做对应检查,给代理返回允许访问还是拒绝。可以对接如配额、授权、黑白名单等不同的控制后端,对服务间的访问进行可扩展的控制。
Citadel在Istio架构中不是必须的。
Istio的认证授权机制主要是由Citadel完成,同时需要和其它组件一起配合,参与到其中的组件还有Pilot、Envoy、Mixer,它们四者在整个流程中的作用分别为:
1、pod启动时,citadel会下发密钥和证书给envoy存储,便于后续服务安全通信
2、pilot服务发现和策略规则会以envoy api的方式暴露给envoy容器
3、envoy跟envoy传输是安全的
4、检查envoy请求并且收集envoy请求数据
Galley在Istio架构中不是必须的
Galley在控制面上向其他组件提供支持。Galley作为负责配置管理的组件,并将这些配置信息提供给管理面的Pilot和Mixer服务使用,这样其他管理面组件只用和Galley打交道,从而与底层平台解耦。
好处:
1、由Galley来进行配置统一管理、方便配置问题排查。可以理解为微服务的配置中心
2、增加配置的复用度。
3、配置跟配置隔离,组件访问配置增加了权限控制。
分发协议MCP,MCP角色介绍:
1、source:galley组件
2、sink:配置的消费端、比如:mixer/pilot
3、resource:yaml配置文件
注入流程:
在Kubernetes环境下,根据自动注入配置,Kube-apiserver在拦截到Pod创建的请求时,会调用自动注入服务istio-sidecar-injector 生成Sidecar容器的描述并将其插入原Pod的定义中,这样,在创建的Pod内,除了包括业务容器,还包括Sidecar容器。这个注入过程对用户透明,用户使用原方式创建工作负载。
Sidecar模式的优点:
1、可以降低业务代码的复杂度
2、易升级、部署,与业务代码解耦
Proxy是Istio数据平面的轻量代理。
Envoy是用C++开发的非常有影响力的轻量级高性能开源服务代理。作为服务网格的数据面,Envoy提供了动态服务发现、负载均衡、TLS、HTTP/2及gRPC代理、熔断器、健康检查、流量拆分、灰度发布、故障注入等功能。
Envoy代理是唯一与数据平面流量交互的Istio组件。
Envoy组件解析
为了便于理解Istio中Envoy与服务的关系,如图所示:
一个Pod里面运行了一个Envoy容器和Service A容器,而Envoy容器内部包含了两个进程,分别是Pilot-agent和Envoy两个进程
Pilot-agent
1、用于生成envoy配置
2、负责启动envoy
3、监控envoy运行状态(envoy报错,pilot-agent会负责重启envoy)
Envoy进程
1、负责拦截Pod流量
2、负责从控制平面Pilot来获取配置和服务发现
3、上报数据给控制平面Mixer
ingressgateway 就是入口处的 Gateway,从网格外访问网格内的服务就是通过这个Gateway进行的。
ingressgateway比较特别,是一个Loadbalancer类型的service,不同于其他服务组件只有一两个端口,ingressgateway开放了一组端口,这些就是网格内服务的外部访问端口。
网格入口网关ingressgateway和网格内的sidecar是同样的执行体,也和网格内的其他Sidecar一样从Pilot处接收流量规则并执行。因为入口处的流量都走这个服务。
Kubeadm是一个工具,它提供了kubeadm init 以及kubeadm join 这两个命令作为快速创建kubernetes集群的最佳实践。
https://blog.csdn.net/qq_39578545/article/details/117171753
快速部署Istio
在Istio的版本发布页面:https://github.com/istio/istio/releases/tag/1.0.6下载安装包并解压(放在master上面)
CRD:可以自定义资源类型,需要先执行CRD.yaml文件
https://www.bilibili.com/video/BV1VA411T7wp?p=35&spm_id_from=pageDriver
apiVersion: apps/v1 ## 定义了一个版本
kind: Deployment ## k8s资源类型是Deployment
metadata: ## metadata这个KEY对应的值为一个Maps
name: nginx-deployment ## 资源名字 nginx-deployment
labels: ## 将新建的Pod附加Label
app: nginx ## 一个键值对为key=app,value=nginx的Label。
spec: # 以下其实就是replicaSet的配置
replicas: 3 ## 副本数为3个,也就是有3个pod
selector: ## 匹配具有同一个label属性的pod标签
matchLabels: ## 寻找合适的label,一个键值对为key=app,value=nginx的Label
app: nginx
template: # 模板
metadata:
labels: ## 将新建的Pod附加Label
app: nginx
spec:
containers: ## 定义容器
- name: nginx ## 容器名称
image: nginx:1.7.9 ## 镜像地址
ports:
- containerPort: 80 ## 容器端口
为了解决Pod地址发生飘逸问题,用到Service
内部服务访问集群中的Pod(ClusterIP)
whoami-deployment是yaml里的metadata.name
将资源暴露为新的Kubernetes Service。
kubectl expose deployment whoami-deployment
kubectl describe svc whoami-deployment
kubectl expose deployment whoami-deployment --type=NodePort
前面我们也学习可以通过service nodeport方式实现外部访问Pod的需求,但是会占用了各个物理主机上的端口,所以这种方式不好。
whoami-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami-deployment
labels:
app: whoami
spec:
replicas: 3
selector:
matchLabels:
app: whoami
template: # template其实就是对Pod对象的定义(模板)
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: jwilder/whoami
ports:
- containerPort: 8000 # 容器的端口
---
apiVersion: apps/v1
kind: Service
metadata:
name: whoami-service
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: whoami
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: whoami-ingress
spec:
rules: # 定义规则
- host: whoami.qy.com # 定义访问域名
http:
paths:
- path: / # 定义路径规则, /表示没有设置任何路径规则
backend:
serviceName: whoami-service # 把请求转发给service资源,这个service就是我们前面运行的service
servicePort: 80 # service的端口
kubectl get pods
手动注入sidecar
istioctl kube-inject -f first-istio.yaml | kubectl apply -f -
自动注入sidecar
首先自动注入是需要跟命名空间挂钩,所以需要创建一个命名空间,只需要给命名空间开启自动注入,后面创建的资源只要挂载到这个命名空间下,那么这个命名空间下的所有的资源都会自动注入sidecar了
(1)创建命名空间
kubectl create namespace my-istio-ns
(2)给命名空间开启自动注入
kubectl label namespace my-istio-ns istio-injection=enabled
(3)创建资源,指定命名空间即可
查询istio-demo命名空间下面是否存在资源
kubectl get pods -n my-istio-ns
kubectl apply -f first-istio.yaml -n my-istio-ns
sidecar注入总结:
不管是自动注入还是手动注入原理都是在yaml文件里面追加一个代理容器,这个代理容器就是sidecar,这里更推荐自动注入的方式来实现sidecar的注入
(1)执行命令查看istio自带的组件
kubectl get pods -n istio-system
这是istio官方给我们提供的案例,Bookinfo应用中的几个微服务是由不同的语言编写的。这些服务对Istio并无依赖,但是构成了一个有代表性的服务网格的例:它由多个服务、多个语言构成,并且reviews服务具有多个版本。
略