服务网格和Istio
Posted 分享录
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了服务网格和Istio相关的知识,希望对你有一定的参考价值。
架构的发展历史
单机小型机时代
小型机时代由于互联网不发达 流量低,对性能要求不高,使用一个小型机将业务放在一起,链接上数据库,这就是最初的架构模型。
垂直拆分时代
随着网民数量增加,和应用逐渐复杂多样化,开发者对容灾,伸缩和响应能力有了更高的需求。且业务发展迅速,之前的小型机一个业务发布就要所有业务都重新发布的模式是不能接受的,于是为了能快速响应业务变化,需要对业务进行垂直拆分。即:将服务各自独立开来,这样可以更好的支持业务变更和扩展。
集群化负载均衡时代
小型机价格昂贵,维护成本搞,比起使用小型机来部署应用,更优的选择是使用成本更低的pc机,但pc机单机性能太差,于是通过多台pc机部署同一服务,然后使用负载均衡将请求均匀的打在服务上的方式来解决。
硬件层负载均衡可以采用F5
软件层可采用LVS、nginx、Haproxy
服务改造架构时代
随着一个公司的业务不断扩展,我们发现有相当多的基础服务在所有的业务中都有使用,比如用户登陆注册,比如用户邮件短信服务等,这些基础服务时重复的冗余在各个完整业务服务中的,造成了冗余浪费,所以会将基础服务拆解出来,通过服务间的调用(RPC)来解决资源浪费问题。
服务治理时代
随着业务增大,基础服务越来越多,调用链路越来越复杂,这就要求我们需要对服务进行治理
当服务节点过多时我们需要引入对服务进行动态的感知,于是有了注册中心
当服务调用链路很长时我们需要考虑如何实现链路追踪监控
当服务间调用错乱复杂时任何服务挂了都可能影响其他服务所以我们要引入熔断限流降级
流量越来越大为了实现单个服务高可用我们需要引入负载均衡
典型代表:dubbo
分布式微服务时代
2012年提出的概念,重点在于希望一个服务只负责一个独立的功能,任何需求不会因为发布或者维护影响其他服务,可以独立运维部署。
典型代表 spring-cloud 仅负责解决服务通讯和服务治理问题。
服务网格时代
我们检查一下以微服务为代表的springcloud框架是如何解决通讯和治理问题以及有哪些缺陷:
业务代码中加入maven依赖,加上注解,加上配置–打成jar包时也会将这些非业务代码融合进去。
开发人员需要投入精力学习springcloud。
本质时侵入式框架,而微服务是多语言调用,对于java之外的语言体系使用此套框架逻辑时会有大量的转化成本。
微服务拆分的越细,对于单个服务来看时轻量级了,但是对于整体业务的维护来说就越来越复杂了。维护成本高。
找到问题后解决思路也就很清晰了:服务通讯的问题不应该集成在业务代码中,客户端需要调用到服务,这个过程中的网络通信过程要与业务代码尽量无关。
服务通讯问题无非是:服务发现,负载均衡,限流降级熔断等问题。
那这样我们可以将所有的服务通讯问题抽出,使用代理的方式去解决,让业务代码真正的只关系业务,即:A服务无法直接调用B服务,A服务调用B服务应当通过A服务的服务器上的一个独立的代理模块,去调用B服务服务器上对应的代理模块来进行。而这个独立的代理模块融合了服务通讯治理所有问题的通用解决方案。这种模式我们称为边车模式(Sidecar)。
所谓的服务网格即运维只关注服务的之间的通讯网络,而不关注其下代理的业务代码。
优点:
无需侵入代码就能管理服务调用和提供服务治理能力
优秀的跨语言支持。
边车模式(SideCar)
边车模式的探索之路
2014年netflix发布了prana
2015年唯品会发布了localproxy
2016twitter发布了第一个真正意义上的Service mesh框架 Linkerd
Linkerd
在sidecar的基础上增加了更加丰富的的服务治理功能,如数据上报,日志收集,链路监控等。且linkerd可以很好兼容kubernetes提供的所有的功能。
使用Scalar语言进行编写,可在github上查看其源码。
二、Istio基础
Istio概念
由google、ibm、Lyft共同发起的开源service mesh项目
由go语言编写,是目前service mesh最主流的框架(2021/4)
使用istio可以轻松创建带有负载均衡服务,身份验证,监控等功能的网络服务。对业务代码不用改动,服务上包含了sidecar对所有流量进行代理,通过控制平台(运维使用,仅关注sidecar服务网格)进行统一管理。
基础功能
对HTTP RPC WS TCP流量进行自动负载均衡
通过丰富的路由规则,重试,故障切换和故障注入的方式对流量行为进行更细粒度的控制
通过可插入策略层和配置管理API从而支持访问控制和限流功能(速率和配额)
包含集群维度入口和出口信息自动进行流量统计,日志记录和链路追踪。
实现了强身份验证授权的服务间通讯
云原生
istio基于云原生开发
云原生组织(CNCF)致力于让云计算具有普遍性和可持续性,云原生开源技术栈将应用程序部署为微服务,将每个部分打包到自己的容器中,并动态编排这些容器以优化资源利用率
发展历程
微服务–>kubernetes–>linkerd–>envoy–>Istio
解决的问题
统一基础平台:Kubernetes
日志监控:Prometheus
代理&负载均衡:Envoy
域名发现:CoreDNS
容器运行时:containerd(从Docker中分离出来的一个项目 k8s没使用docker而使用的containerd)
分布式链路追踪:Jaeger
安全软件更新:TUF
统一日志记录:Fluentd
分布式mysql工具集:Vitess
软件包管理工具:Helm
。。还有其他正在孵化的项目
国内的Service mesh项目
蚂蚁金服 soft mesh
前身是soft rpc 封装了http通讯协议,Duhbbo RPC, SOFA RPC,兼容Envoy
腾讯云 Tencent service mesh
基于Springcloud sidecar组件完成 集成了Zuul proxy,Ribbon和Hystrix治理组件
华为云 CSE Mesher
mesher(sidecar)自己研发了一套服务治理集成
包含服务注册发现,负载均衡,熔断,路由,链路追踪
Istio特征
连接
网格内部流量调用进行监控管理,保障微服务部署测试升级的等操作
调用问题
网格内部服务连接路由,A服务调用如何识别调用B服务
如何应对网络故障或服务故障,B服务宕机了A服务如何访问
如何处理不同服务不同版本的关系,A服务版本1应当连接B服务的哪个版本
如何对出站连接进行控制 B服务调用了外部云服务
如何接收入站连接 用户如何访问到服务A
流量控制问题
服务注册发现
负载均衡
路由规则
以上Istio都通过以下手段经进行了解决(与微服务无二,仅是将其搬到了sidecar中)
路由规则
服务发现
负载均衡
限流
监控
通信加密
集群
安全
网格内部服务之间的调用提供认证,提高安全性
问题
不同语言不同平台间访问问题
集群内部服务和服务间的调用该如何防止其他服务进行监听
仅有提供了有效身份的客户端才能访问指定服务
Istio提供了网格间的通讯保障
服务通讯加密
服务身份认证
服务访问控制
通过数字证书和密钥来对安全进行保障(类似于https)
策略
在控制面版中进行定制策略并在服务中实施
调用频率的限制
服务访问控制
流量控制
Istiot通过动态插拔动态扩展的方式提供了策略控制能力
使得资源在消费者中合理分配
主要使用了Mixer组件作为策略执行者 Envoy代理每次调用都要经过Mixer同意
观察
服务间调用进行追踪策略,获取服务状态信息
Istio提供监控和链路追踪功能
主机监控
cpu
内存
网卡
服务健康监控
调用成功率
调用时间
调用链
传输链
Istio与服务治理
服务治理的三种形式
第一种:应用程序中包含治理程序
自己写代码来实现治理逻辑,将治理的功能写在业务代码中
治理代码冗余到了所有服务中
治理代码与业务代码耦合
第二种:治理逻辑独立的代码
将服务代码抽出单独称为框架进行统一管理(Spring-cloud)
框架组件也需要和业务代码进行共同编译,仅解决了无需单独开发问题
治理框架语言受限制,跨语言能力差
服务治理框架升级困难,需要让所有服务都升级
第三种:治理逻辑独立的进程
也就是边车模式,将治理逻辑彻底从业务代码中剥离,单独称为一个独立的进程
Istio与Kubernetes
kubernetes是用于管理容器化工作负载的可移植可扩展的开源平台,面向基础设施,将计算,网络,存储等资源进行整合,为容器提供最佳运行环境。
kubernetes并不把服务的无状态微服务化作为可运行的约束条件
kubernetes解决了服务间互通的问题
Pod是kubernete的最小单位,一个pod中包含多个业务容器(和一个pod的pause容器,负责管理pod状态)
kubernetes本身不提供服务治理能力,而Istio就是帮助kubernetes实现服务治理功能
而对于Istio来说 Kubernetes可以帮Istio实现数据平面,统一服务发现,基于CRD规则扩展自定义资源。
数据平面
利用了pod可以运行多个容器的特点来实现数据平面功能,让一个pod中运行一个sidecar和一个(多个)业务容器
统一服务发现
Istio的服务注册发现机制是基于Kubernetes的域名访问机制(Ingress)实现的
Ingress会不断从Kubernetes API Server获得Pod信息,Ingress就获得了Pod内部的服务信息,从而知道应该发给哪个服务
基于CRD规则扩展自定义资源
Istio基于CRD规则扩展自定义资源,而资源数据通过K8S的api server保存到etcd(键值对数据库)里。
三、Istio架构与组件
Istio整体架构
主要分为两个方面,数据平面和控制平面
数据平面是由一组envoy只能代理组成,被部署为sidecar,这些代理通过一个通用的策略和控制中心传递信息和控制微服务间的通讯
控制平面用于进行管理并配置代理来进行流量路由,此外配置mixer执行策略和收集数据
Pilot:控制中心,提供服务发现和路由规则
Mixer:策略控制,限流熔断等
Citadel:安全组件,保障服务间通讯安全
Envoy:代理,处理服务流量
自动注入
sidecar注入插件
会修改应用程序的描述信息(ymal)注入sidecar
描述信息就是创建pod的样板文件
具体时在deployment中ngnix容器后追加一个sidecar容器
流量拦截
服务发现和负载均衡
POD-1调用POD-2 POD-1时如何发现需要调用的POD-2,其中的负载均衡如何做的。
POD-1的sidecar(envoy)会调用控制平面Pilot的服务发现接口来获取目标服务的实例列表(类似于eureka)
POD-1获取了多个版本的多个实例,同样POD-1也会通过调用控制平面的Pilot获取负载均衡配置,依据配置策略来选择实例(包含版本控制,负载均衡策略)
流量治理和访问安全
与发现负载均衡类似,sidecar获取到了流量规则,通信时按照规则进行。
规则为DestinationRule,是一种自定义的CRD,可以通过kubectl get DestinationRule 来获取查看(纳入kubectl管理)。
在通讯过程中会进行通信加密,证书和密钥统一由控制平面维护
服务监控
通信双方的envoy会连接到控制平面的mixer进行数据上报,mixer会通过adapter(适配器)将数据发送给不同的监控的后端。
通讯本身并不受影响 pod-1对pod-2发送请求后会额外上报数据 pod-2在接收到请求后会额外上报数据。(但是还是需要占用机器的网络带宽 会降低一定的吞吐量)
策略执行
控制服务间的访问,判断这个请求是拒绝还是应该发送,策略控制的配置来源于mixer,sidecar需要调用mixer获取策略
Pilot组件
服务发现和流量控制,pilot包含了服务注册和路由规则下发,是服务端的master
注册发现
Pilot本身不提供服务注册功能,仅提供了API接口来对接已经实现注册中心功能的框架,我不实现服务注册,由其他注册中心(如eureka)提供功能进行调用。通过api接口获得其他注册中心提供的实例信息后pilot会对其进行统一的抽象转换,用以提供envoy获取实例的方法。从而实现任意跨平台发现调用。
路由规则下发
pilot负责将各种规则转化成envoy可以识别的规则下发给数据平面
mixer
mixer在istio架构中不是必须的,分为两个模块policy和telemetry。
policy负责向envoy提供准入规则策略控制,黑白名单,速率限制等相关策略。
telemetry则为Envoy提供了数据上报和日志收集服务,用于监控告警和日志查询
citadel组件
也不是istio必须的,且需要其他组件配合使用,当使用citadel时会进行额外的动作.
一句话说就是负责管理各个服务的密钥和证书
整体流程如下
Pod启动时,citadel会下发密钥和证书给envoy存储,以便安全通讯
Pilot服务发现和策略规则会以envoy api的方式暴露给envoy容器
envoy已经存储了密钥和证书,envoy间传输是安全的
mixer会检查envoy代理的请求并收集envoy的数据用于数据上报
galley组件
不是istio必须的,主要负责配置管理,验证配置信息的格式和内容的正确性,给其他istio组件提供支持(pilot和mixer)
好处:
配置统一管理,方便问题排查
增加配置的复用度,相同的配置不用存多份
配置间互相隔离且组件访问配置增加了权限控制
依托于mcp协议,其提供了一套配置订阅和分发的api,mcp协议中包含了 source,sink,resource三个角色。
source是配置的提供者 也就是galley组件
sink是配置的消费端,也就是mixer和pilot
resource是配置文件(yaml)
sidecar-injector组件
负责自动注入sidecar
注入有两种方式,使用sidecar命令(istioctl)手动注入或者通过kubernetes自动注入(需要配置istio-injection=true)
envoy组件
数据平面的轻量级代理,用c++开发 效率极高,为代理业务提供了动态服务发现,负载均衡,TLS,HTTP/2,gRPC代理,熔断器,健康检查,流量拆分,灰度发布,故障注入等功能
sidecar中包含了pilotAgent和Envoy两个进程 PilotAgent用于生成envoy配置,启动envoy进程,负责监控envoy运行状态(出错重启), envoy进程负责拦截pod流量,负责从控制平面获取配置和服务发现,上报数据给mixer。
IngressGateway组件
IngressGateway会启动一组端口用于接收网格外部的请求。然后将请求分发给内部的envoy
egressGateway组件
与IngressGateway对应 是统一出口 负责统一调度外部服务的组建
四、使用Istio
快速安装
安装k8s
git clone https://github.com/hummerstudio/k8s-docker-desktop-for-mac.gitbr
找到Docker Engine,配置文件中加入一行国内镜像,以提高拉取镜像的速度
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://dockerhub.azk8s.cn",
"https://reg-mirror.qiniu.com",
"https://hub-mirror.c.163.com"
],
然后执行拉取项目中的./load_images.sh 执行完成后在docker desktop中重启Kubernetes即可。
验证一下本地k8s环境
kubectl cluster-info
kubectl get nodes
kubectl describe node
安装dashbord(非必须可跳过)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yamlbr
如果出现以下异常
The connection to the server raw.githubusercontent.com was refused
则设置host 即可解决
199.232.28.133 raw.githubusercontent.com
启动kube本地代理,让我们可以访问进dashboard
kubectl proxy
注:这个命令会占用控制台 如果想后台运行请执行
nohup kubectl proxy >/dev/null &
然后通过代理查看dashboard
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
发现需要token登录
查看登录token
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep kubernetes-dashboard | awk '{print $1}')
输入即可进入dashboard
Istio安装
官方文档:
https://istio.io/docs/setup/getting-started/
先下载istio
curl -L https://istio.io/downloadIstio | sh -
若执行失败建议直接去github发布页面手动下载
https://github.com/istio/istio/releases
解压后进入istio文件 ,将istio命令export到path中,方便直接使用
export PATH=$PWD/bin:$PATH
执行istio安装
istioctl install --set profile=demo
这里安装有不同的配置档 通过–set profile=demo指定,这里选择demo
为default命名空间设置sidecar自动注入(直接通过lable打标即可)
kubectl label namespace default istio-injection=enabled
到这里安装设置就已经完成了,我们使用bookinfo进行一下测试
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
注:这里当前目录还在istio下 可以看到里面自带了samples文件
检查运行情况
kubectl get svc,pod
检查所有pod是否ready
验证启动是否成功
kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"
返回如下则证明成功启动
<title>Simple Bookstore App</title>
创建 Ingress Gateway 用以管理入口流量,这样我们就可以直接本地访问bookinfo了,同样文件也在sample中 注意执行时的位置
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
检查istio是否有问题,显示No validation issues found when analyzing namespace: default则证明没问题
istioctl analyze
查看getway
kubectl get gateway
定义访问gateway的ip和端口信息,我们直接设置为本地80端口
export GATEWAY_URL=localhost:80
浏览器访问本地查看商品页面
http://localhost/productpage
到此为止我们就成功的使用istio部署了bookinfo项目
删除项目脚本
samples/bookinfo/platform/kube/cleanup.sh
删除istio
istioctl manifest generate --set profile=demo | kubectl delete -f -
删除istio的命名空间
kubectl delete namespace istio-system
删除istio的自动注入sidecar
kubectl label namespace default istio-injection-
K8S相关介绍
概念
Container
容器,是一个镜像容器,一个container是一个镜像实例,与docker类似,但是k8s为了抽象使用不同容器而提出的逻辑,可以在pod中使用docker 也可以是其他容器。
POD
Pod是kubernete的最小单位,一个pod中包含多个业务容器(和一个pod的pause容器,负责管理pod状态)
Pod是K8S塑造出来的"逻辑主机"。
NODE
Pod总是运行在Node之上,一个Node节点能有多个pod,Node是Kubernetes中的一个工作机器,通常是一个物理机或者虚拟机,Pod关联的Node故障了,一个新Pod会被调度到其它可用的Node上。
Node被Master管理,Master的自动调度考虑到每个Node上的可用资源。
Service
服务,多个相同的pod组成一个服务,统一对外提供服务。
StatefulSet
有状态集群,比如一个主从的mysql集群就是有状态集群,需要先启动主再启动从,这就是一种有状态的集群。
Volume
存储卷,pod对外暴露的共享目录,它可以挂载在宿主机上,这样就能让同node上多个pod共享一个目录
Persistent Volume
持久存储卷。之前说的volume是挂载在一个pod上的,多个pod(非同node)要共享一个网络存储,就需要使用持久存储卷,简称为pv。
Namespace
命名空间,提供了一个作用域,如果通过建立service 访问pod 时,如果service 的命名空间不指定正确,那么就无法通过标签关联到pod。pod, service, rc, volume 都可以在创建的时候指定其namespace
Persistent Volume Claim
持久存储卷声明。他是为了声明pv而存在的,一个持久存储,先申请空间,再申明,才能给pod挂载volume,简称为pvc。
Label
标签。我们可以给大部分对象概念打上标签,然后可以通过selector进行集群内标签选择对象概念,并进行后续操作。
Secret
私密凭证。密码保存在pod中其实是不利于分发的。k8s支持我们创建secret对象,并将这个对象打到pod的volume中,pod中的服务就以文件访问的形式获取密钥。
Master
k8s的主控组件,是一个node对象。即master节点,master节点上有三个docker进程,分别是kube-apiserver,kube-controller-manager ,kube-scheduler。
我们也可以通过使用kubectl proxy 在 master 上来创建一个代理,从而外部可以访问这个 k8s 集群。
kube-apiserver
apiserver 是提供 k8s 的 rest api 服务的进程,提供了k8s各类资源对象(pod,rc,Service等)的增删改查及watch等HTTP Rest接口。
kube-controller-manager
用来管理所有的 controller 的。controller有:
Replication Controller:用于控制pod集群的控制器,可以制定各种规则来让它控制一个service中的多个pod的创建和消亡, 简称为rc
Node Controller: 实时获取Node的相关信息,实现管理和监控集群中的各个Node节点的相关控制功能
ResourceQuota Controller: 确保指定的资源对象在任何时候都不会超量占用系统物理资源
NameSpace Controller: 定时通过API Server读取这些Namespace信息
ServiceAccount Controller: 监听Service变化,如果是一个LoadBalancer类型的Service,则确保外部的云平台上对该Service对应的LoadBalancer实例被相应地创建、删除及更新路由转发表
Token Controller
Service Controller
EndPoint Controller : Service 和选择 Pod 的对应关系。
kube-scheduler
负责 Pod 调度,接收 Controller Manager 创建的新的Pod,为其选择一个合适的Node,并且在Node上创建Pod。
Deployment
RC可以保证在任意时间运行Pod的副本数量,能够保证Pod总是可用的,随着Kubernetes的高速发展,官方已经推荐我们使用RS(ReplicaSet)和Deployment来代替RC了,RS和RC功能基本一致, 只不过RC只支持等号的selector 而RS更加强大。
Deployment为Pod和Replica Set提供声明式更新,你只需要在 Deployment 中描述您想要的目标状态是什么,Deployment controller 就会帮您将 Pod 和ReplicaSet 的实际状态改变到您的目标状态。您可以定义一个全新的 Deployment 来创建 ReplicaSet 或者删除已有的 Deployment 并创建一个新的来替换。
CRD
Custom Resource Definition 用户自定义资源,即允许用户添加一个跟Pod、Node类似的资源类型。
基本指令
kubectl命令,k8s操作指令,常用命令如下
查看基础信息
kubectl version 查看版本 由于版本信息时json串,想直观看到版本加上 --short=true
kubectl cluster-info 查看集群信息
创建资源对象
kubectl apply -f **.yaml 声明式对象配置管理方式(也适用于更新等)
查看资源对象
kubectl get ns 查看命名空间
kubectl get pods,services 不指定命名空间则默认为default 执行命名空间可以加上-n {namespace} 想查询所有空间的信息加上–all-namespaces
kubectl get pod -l “key=value,key=value” (-l 标签选择器(多个的话是与逻辑)) 同时支持namespace相关选项
kubectl describe pod {pod_name} 查看pod状态描述
kubectl logs {pod_name} -f -c {container_name} (-f 持续监控,-c如果pod中只有一个容器不用加)
操作资源对象
kubectl label pods/{pod_name} key=value 添加标签,如果是修改的话需要后面添加–overwrite
kubectl label nodes {node_name} key=value 给工作节点添加标签,后续可以使用nodeSelector来指定pod被调度到指定的工作节点上运行
kubectl label namespace {namespace} key=value 给命名空间添加标签
删除资源对象
kubectl delete [pods/services/deployments/…] {name}
kubectl delete -f *.yml 可以通过你当时部署的yaml文件来删除
Istio能力介绍
bookinfo项目介绍
Istio官方提供的案例,bookinfo中的几个微服务是由不同语言编写的,且这些项目对istio并无依赖,构成一个代表性的例子。且reviews有多个版本。
Productpage
接受外界请求
将请求分发到detail和reviews微服务上
Details
包含了书籍的信息
Reviews
包含了书籍相关的评论
调用ratings服务
v1版本不会调用ratings服务,V2版本会显示灰色的星星,V3版本会显示红色星星
Ratings
评论相关的评级信息
流量管理
Istio的流量管理主要通过虚拟服务和目标规则确定的
虚拟服务(Virtual Service) 和目标规则(Destination Rule) 是 Istio 流量路由功能的关键拼图
目标规则
首先我们查看一下现有的流量规则信息
首先配置bookinfo项目的规则信息
kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml
查看当前规则信息
kubectl get destinationrule
查看一下默认给的规则信息里到底配置了什么
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: productpage
spec:
host: productpage
subsets:
name: v1
labels:
version: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
subsets:
name: v1
labels:
version: v1
name: v2
labels:
version: v2
name: v3
labels:
version: v3
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: ratings
spec:
host: ratings
subsets:
name: v1
labels:
version: v1
name: v2
labels:
version: v2
name: v2-mysql
labels:
version: v2-mysql
name: v2-mysql-vm
labels:
version: v2-mysql-vm
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: details
spec:
host: details
subsets:
name: v1
labels:
version: v1
name: v2
labels:
version: v2
---
从上我们可以看出几个点 kind为DestinationRule(目标规则)就是istio在k8s上依赖于CRD自定义的资源类型,metadata.name为资源的名称,spec.host为对应资源的主机(k8s由于有coredns组建,所以主机可以进行域名解析)subsets为该资源下的配置信息。通过这个规则我们暂时看不到任何流量控制信息,多次请求测试一下bookinfo的product页面,发现是轮巡调用Reviews到(第一次没有rating 第二次为灰色 第三次为红色),目标规则主要的作用是可以使用目标规则来指定命名的服务子集,例如按版本为所有给定服务的实例分组。然后可以在虚拟服务的路由规则中使用这些服务子集来控制到服务不同实例的流量。
虚拟服务
现在我们想要将productpage的流量,全部打到v3版本上去,sample中已经提供了对应的rule脚本。virtual-service-reviews-v3.yaml 我们先测试一下,执行应用该规则的命令
kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-v3.yaml
测试一下页面,发现确实流量全部打到了v3上,我们查看一下该yaml文件,看到底是如何配置的
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
reviews
http:
route:
destination:
host: reviews
subset: v3
这里我们看了另一个kind类型 “VirtualService” 虚拟服务,他将reviews资源变为一个虚拟服务,并且为其下服务设定了一个路由,解析主机reviews,将其http的流量全部打到v3上,通过这种方式来通过版本进行流量控制。
我们再看一下基于权重的流量控制,先将版本控制的规则删除
kubectl delete -f samples/bookinfo/networking/virtual-service-reviews-v3.yaml
istio也提供了一些给予权重的demo,我们打开virtual-service-reviews-50-v3.yaml,
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
reviews
http:
route:
destination:
host: reviews
subset: v1
weight: 50
destination:
host: reviews
subset: v3
weight: 50
可以看到通过配置weight 可以轻松将一半流量打到v1版本 另一半打到v3版本,具体可以apply测试,随后记得删除规则。
我们还可以通过用户自定义的方式来控制流量
打开virtual-service-reviews-jason-v2-v3.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
reviews
http:
match:
headers:
:
exact: jason
route:
destination:
host: reviews
subset: v2
route:
destination:
host: reviews
subset: v3
看到可以依据head字段进行匹配,如果end-user中存在jason 则访问v2版本 否则访问v3版本。
网关
除了服务间调用的流量控制外,我们还需要对整体入站出站流量进行规则限制,这就是网关,可以看到在上文配置完服务后我们启动了一个网关用于代理整个bookinfo的入口。
使用网关为网格来管理入站和出站流量,可以让您指定要进入或离开网格的流量。网关配置被用于运行在网格边界的独立 Envoy 代理,而不是服务工作负载的 sidecar 代理。
如果你熟悉k8s,那你一定知道k8s上有个IngressGateWay用于负责整个k8s入口路由,那为什么Istio还需要有单独的网关服务呢?
与 Kubernetes Ingress API 这种控制进入系统流量的其他机制不同,Istio 网关让您充分利用流量路由的强大能力和灵活性。您可以这么做的原因是 Istio 的网关资源可以配置 4-6 层的负载均衡属性,如对外暴露的端口、TLS 设置等。作为替代应用层流量路由(L7)到相同的 API 资源,您绑定了一个常规的 Istio 虚拟服务到网关。这让您可以像管理网格中其他数据平面的流量一样去管理网关流量。
简单来说就是可以在更细粒度去控制而不是在集群整体入口上。
Istio 提供了一些预先配置好的网关代理部署(istio-ingressgateway 和 istio-egressgateway),负责整体进出口流量,除此之外,我们在部署bookinfo时可以看到部署过单独的bookinfo网关,我们检查一下部署文件samples/bookinfo/networking/bookinfo-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
port:
number: 80
name: http
protocol: HTTP
hosts:
"*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
"*"
gateways:
bookinfo-gateway
http:
match:
uri:
exact: /productpage
uri:
prefix: /static
uri:
exact: /login
uri:
exact: /logout
uri:
prefix: /api/v1/products
route:
destination:
host: productpage
port:
number: 9080
我们看到网关配置有两部分组成,第一部分是定义了一个网关,绑定了http 80端口,使用了istio默认的ingressgateway控制(ex:我们也可以在网关上添加一些tls校验)
但是仅定义了网关是不会生效的,我们需要将其与一个虚拟服务绑定,这就是第二个部分,然后我们就可以为入口流量配置带有路由规则的虚拟服务。
服务入口
当我们需要调用外部服务时,不可能对外部服务进行定制化开发,这时候我们就可以使用服务入口,使用服务入口(Service Entry) 来添加一个入口到 Istio 内部维护的服务注册中心。添加了服务入口后,Envoy 代理可以向服务发送流量,就好像它是网格内部的服务一样。配置服务入口允许您管理运行在网格外的服务的流量。
服务入口配置示例:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: svc-entry
spec:
hosts:
ext-svc.example.com
ports:
number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS
这样我们就将ext-svc.example.com纳入了istio管理,在此之上我们依旧可以使用可以配置虚拟服务和目标规则对该服务入口进行管理。
Sidecar
默认情况下,Istio 让每个 Envoy 代理都可以访问来自和它关联的工作负载的所有端口的请求,然后转发到对应的工作负载。但是你可能希望在较庞大的应用程序中限制这样的 sidecar 可达性,这时候我们就可以使用Sidecar配置去做下面的事情:
微调 Envoy 代理接受的端口和协议集。
限制 Envoy 代理可以访问的服务集合。
这里有Sidecar的部署示例
apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
name: default
namespace: bookinfo
spec:
egress:
hosts:
"./*"
"istio-system/*"
通过配置制定bookinfo中服务队外调用的范围。
故障注入
我们可以通过主动将故障注入来进行服务测试
istio同样提供了脚本供我们学习,查看virtual-service-ratings-test-delay.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
ratings
http:
match:
headers:
:
exact: jason
fault:
delay:
percentage:
value: 100.0
fixedDelay: 7s
route:
destination:
host: ratings
subset: v1
route:
destination:
host: ratings
subset: v1
这段配置中 我们可以看到有个fault子项,他定义了如果满足match条件后 100%的概率将调用请求延迟7s。
故障注入还有另一个demo,virtual-service-ratings-test-abort.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
ratings
http:
match:
headers:
:
exact: jason
fault:
abort:
percentage:
value: 100.0
httpStatus: 500
route:
destination:
host: ratings
subset: v1
route:
destination:
host: ratings
subset: v1
在fault定义了 满足match条件后 100%的概率直接返回500错误
扩展性
Istio在1.6版本后利用WebAssembly沙盒技术,让Proxy-Wasm 沙盒 API 取代了 Mixer 作为 Istio 主要的扩展机制。
过滤器服务提供商接口 用于为过滤器构建 Proxy-Wasm 插件。
沙盒 在 Envoy 中嵌入 V8 Wasm 运行时。
主机 API 用于处理请求头,尾和元数据。
调出 API 针对 gRPC 和 HTTP 请求。
统计和记录 API 用于度量统计和监控。
即对envoy代理过程的扩展,具体扩展代码不在此研究。
安全性
Istio 身份
身份是任何安全基础架构的基本概念,我们可以打开bookinfo的部署文件samples/bookinfo/platform/kube/bookinfo.yaml 可以看到每一个服务,除了服务(Service)和部署(Deployment)外,还有一个kind为ServiceAccount的类型,标明了每一个服务的名称,在服务器端,服务器可以根据授权策略确定客户端可以访问哪些信息,审计谁在什么时间访问了什么。
公钥基础设施 (PKI)
每个 Envoy 代理都运行着一个 istio-agent 负责证书和密钥的供应, istio-agent 是sidecar 容器中的 pilot-agent 进程的一部分功能,单独拎出来定义方便说明。
Istio 供应身份是通过 secret discovery service(SDS)来实现的,流程如下:
CA 提供 gRPC 服务以接受证书签名请求(CSRs)。
Envoy 通过其SDS API 发送证书和密钥请求。
在收到 SDS 请求后,istio-agent 创建私钥和 CSR,然后将 CSR 及其凭据发送到 Istio CA 进行签名。
CA 验证 CSR 中携带的凭据并签署 CSR 以生成证书。
Istio-agent 通过 Envoy SDS API 将私钥和从 Istio CA 收到的证书发送给 Envoy。
上述 CSR 过程会周期性地重复,以处理证书和密钥轮换。
认证
Istio 提供两种类型的认证:
Peer authentication:用于服务到服务的认证,以验证进行连接的客户端。Istio 提供双向 TLS 作为传输认证的全栈解决方案,无需更改服务代码就可以启用它。这个解决方案:
为每个服务提供强大的身份,表示其角色,以实现跨群集和云的互操作性。
保护服务到服务的通信。
提供密钥管理系统,以自动进行密钥和证书的生成,分发和轮换。
Request authentication:用于最终用户认证,以验证附加到请求的凭据。Istio 使用 JSON Web Token(JWT)验证启用请求级认证,并使用自定义认证实现或任何 OpenID Connect 的认证实现(例如下面列举的)来简化的开发人员体验。
ORY Hydra
Keycloak
Auth0
Firebase Auth
Google Auth
在所有情况下,Istio 都通过自定义 Kubernetes API 将认证策略存储在 Istio config store。Istiod 使每个代理保持最新状态,并在适当时提供密钥。
安全命名:服务器身份(Server identities)被编码在证书里,但服务名称(service names)通过服务发现或 DNS 被检索。安全命名信息将服务器身份映射到服务名称。身份 A 到服务名称 B 的映射表示“授权 A 运行服务 B“。控制平面监视 apiserver,生成安全命名映射,并将其安全地分发到 PEPs。
认证架构:您可以使用 peer 和 request 认证策略为在 Istio 网格中接收请求的工作负载指定认证要求。网格运维人员使用 .yaml 文件来指定策略。部署后,策略将保存在 Istio 配置存储中。Istio 控制器监视配置存储。
当有任何的策略变更,新策略都会转换为适当的配置,告知 PEP 如何执行所需的认证机制。控制平面可以获取公共密钥,并将其附加到配置中以进行 JWT 验证。或者,Istiod 提供了 Istio 系统管理的密钥和证书的路径,并将它们安装到应用程序 pod 用于双向 TLS。
Istio 异步发送配置到目标端点。代理收到配置后,新的认证要求会立即生效。发送请求的客户端服务负责遵循必要的认证机制。对于 peer authentication,应用程序负责获取 JWT 凭证并将其附加到请求。对于双向 TLS,Istio 会自动将两个 PEPs 之间的所有流量升级为双向 TLS。如果认证策略禁用了双向 TLS 模式,则 Istio 将继续在 PEPs 之间使用纯文本。如果要覆盖此行为,请使用 destination rules显式对禁用双向 TLS 模式。
认证策略:正如认证架构中所说的,认证策略是对服务收到的请求生效的。要在双向 TLS 中指定客户端认证策略,需要在 DetinationRule 中设置 TLSSettings。
和其他的 Istio 配置一样,可以用 .yaml 文件的形式来编写认证策略。部署策略使用 kubectl。下面例子中的认证策略要求:与带有 app:reviews 标签的工作负载的传输层认证,必须使用双向 TLS:
apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
name: "example-peer-policy"
namespace: "foo"
spec:
selector:
matchLabels:
app: reviews
mtls:
mode: STRICT
认证策略还有更丰富的使用姿势,详情请见官方文档,这里仅作演示不多赘述。
授权
Istio 的授权功能为网格中的工作负载提供网格、命名空间和工作负载级别的访问控制,具有以下优点:
工作负载间和最终用户到工作负载的授权。
一个简单的 API:它包括一个单独的并且很容易使用和维护的 AuthorizationPolicy CRD。
灵活的语义:运维人员可以在 Istio 属性上定义自定义条件,并使用 DENY 和 ALLOW 动作。
高性能:Istio 授权是在 Envoy 本地强制执行的。
高兼容性:原生支持 HTTP、HTTPS 和 HTTP2,以及任意普通 TCP 协议。
授权架构:每个 Envoy 代理都运行一个授权引擎,该引擎在运行时授权请求。当请求到达代理时,授权引擎根据当前授权策略评估请求上下文,并返回授权结果 ALLOW 或 DENY。运维人员使用 .yaml 文件指定 Istio 授权策略。
以下示例显示了一个授权策略,该策略允许两个源(服务帐号 cluster.local/ns/default/sa/sleep 和命名空间 dev),在使用有效的 JWT 令牌发送请求时,可以访问命名空间 foo 中的带有标签 app: httpbin 和 version: v1 的工作负载。
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: httpbin
namespace: foo
spec:
selector:
matchLabels:
app: httpbin
version: v1
action: ALLOW
rules:
from:
source:
principals: ["cluster.local/ns/default/sa/sleep"]
source:
namespaces: ["dev"]
to:
operation:
methods: ["GET"]
when:
key: request.auth.claims[iss]
values: ["https://accounts.google.com"]
授权策略还有更丰富的使用姿势,详情请见官方文档,这里仅作演示不多赘述。
可观察性
Istio 为网格内所有的服务通信生成详细的遥测数据。这种遥测技术提供了服务行为的可观察性,使运维人员能够排查故障、维护和优化应用程序,而不会给服务的开发人员带来任何额外的负担。
Istio 生成以下类型的遥测数据,以提供对整个服务网格的可观察性:
指标。Istio 基于 4 个监控的黄金标识(延迟、流量、错误、饱和)生成了一系列服务指标。Istio 还为网格控制平面提供了更详细的指标。除此以外还提供了一组默认的基于这些指标的网格监控仪表板。
分布式追踪。Istio 为每个服务生成分布式追踪 span,运维人员可以理解网格内服务的依赖和调用流程。
访问日志。当流量流入网格中的服务时,Istio 可以生成每个请求的完整记录,包括源和目标的元数据。此信息使运维人员能够将服务行为的审查控制到单个工作负载实例的级别。
------------END-----------
更多原创文章请扫描上面(微信内长按可识别)二维码访问我的个人网站(https://www.xubingtao.cn),或者打开我的微信小程序:可以评论以及在线客服反馈问题,其他平台小程序和APP请访问:https://www.xubingtao.cn/?p=1675。祝大家生活愉快!
以上是关于服务网格和Istio的主要内容,如果未能解决你的问题,请参考以下文章