企业级实战模块十:服务网格Istio

企业级实战模块十:服务网格Istio 1 Istio介绍 1 1 Istio介绍 官方文档:https: istio io docs concepts wh

企业级实战模块十:服务网格Istio

1 Istio介绍

1.1 Istio介绍

官方文档:https://istio.io/docs/concepts/what-is-istio/ 中文官方文档:https://istio.io/zh/docs/concepts/what-is-istio/ Github地址:https://github.com/istio/istio/releases

官当解释:

An open platform to connect, secure, control and observe services.

翻译过来,就是连接、安全加固、控制和观察服务的开放平台 。 开放平台就是指它本身是开源的,服务对应的是微服务,也可以粗略地理解为单个应用。

image-20211105165622533

  • 连接( Connect ):智能控制服务之间的调用流量,能够实现灰度升级、 AB 测试和 蓝绿 部署等功能

  • 安全加固( Secure ):自动为服务之间的调用提供认证、授权和加密。

  • 控制( Control ):应用用户定义的 policy ,保证资源在消费者中公平分配。

  • 观察( Observe ):查看服务运行期间的各种数据,比如日志、监控和 tracing ,了解服务的运行情况。

Istio是 ServiceMesh 的产品化落地, 可以通过在现有 的 服务器新增部署边车代理 (sidecar-proxy),应用程序不用改代码 或者只需要改很少的代码,就能实现 如下 基础功能

  • 帮助微服务之间建立连接,帮助研发团队更好的管理与监控微服务,并使得系统架构更加安全

  • 帮助微服务分层解耦,解耦后的 proxy 层能够更加专注于提供基础架构能力,例如:

    • 服务发现 (discovery)

    • 负载均衡 (load balancing)

    • 故障恢复 (failure recovery)

    • 服务度量 (metrics)

    • 服务监控 (monitoring)

    • A/B 测试 (A/B testing)

    • 灰度发布 (canary limiting)

    • 限流限速 (rate limiting)

    • 访问控制 (access control)

    • 身份认证 (end-to-end authentication)

1)服务注册和发现

image-20211105170312288

RPC:RPC Remote Procedure Call )远程过程调用,简单的理解是一个节点请求另一个节点提供的服务

2)负载均衡

把前端的请求分发到后台多个服务器

3)故障恢复

出现故障具备自恢复的能力

4)服务度量

对于HTTP HTTP/2 和 GRPC 流量, Istio 生成以下指标:

  • 请求计数( istio_requests_total ):这是一个用于累加每个由 Istio 代理所处理请求的COUNTER 指标。

  • 请求持续时间( istio_request_duration_seconds ):这是一个用于测量请求的持续时间的

  • DISTRIBUTION指标。

  • 请求大小( istio_request_bytes ):这是一个用于测量 HTTP 请求 body 大小的 DISTRIBUTION指标。

  • 响应大小( istio_response_bytes ):这是一个用于测量 HTTP 响应 body 大小的 DISTRIBUTION指标。

对于TCP 流量, Istio 生成以下指标:

  • Tcp 发送字节数( istio_tcp_sent_bytes_total ):这是一个用于测量在 TCP 连接下响应期间发送的总字节数的 COUNTER 指标。

  • Tcp 接收字 节数( istio_tcp_received_bytes_total ):这是一个用于测量在 TCP 连接下请求期间接收的总字节数的 COUNTER 指标。

  • Tcp 打开连接数( istio_tcp_connections_opened_total ):这是一个用于累加每个打开连接的COUNTER 指标。

  • Tcp 关闭连接数 (istio_tcp_connections_closed_total) : 这是一个用于累加每个关闭连接的COUNTER 指标。

5)灰度发布

灰度发布也叫金丝雀发布,起源是,矿井工人发现,金丝雀对瓦斯气体很敏感,矿工会在下井之 前,先放一只金丝雀到井中,如果金丝雀不叫了,就代表瓦斯浓度高。

image-20211105170517669

在灰度发布开始后,先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进行线上测试,启动的这个新版本应用,就是我们的金丝雀。如果没有问题,那么可以将少量的用户流量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做各种数据对比,就是所谓的 A/B 测试。

当确认新版本运行良好后,再逐步将更多的流量导入到新版本 上,在此期间,还可以不断地调整新旧两个版本的运行的服务器副本数量,以使得新版本能够承受越来越大的流量压力。直到将 100% 的流量都切换到新版本上,最后关闭剩下的老版本服务,完成灰度发布。

如果在灰度发布过程中(灰度期)发现了新版本有问题,就应该立即将流量切回老版本上,这样,就会将负面影响控制在最小范围内。

1.2 Istio核心特性

  • 流控 (traffic management) 断路器(circuit breakers)、超时、重试、多路由规则、 AB 测试、灰度发布、按照百分比分配流量等。

  • 安全 (security) 加密、身份认证、服务到服务的权限控制、K8S 里容器到容器的权限控制等。

  • 可观察 (observability) 追踪、监控、数据收集,通过控制后台全面了解上行下行流量,服务链路情况,服务运行情况,系统性能情况,国内微服务架构体系,这一块做得比较缺乏。

  • 平台无关系 (platform support) K8s,物理机,自己的虚机都没问题。

  • 集成与定制 (integration and customization) 可定制化扩展功能。

1)断路器

示例1:举个生活中的例子 解释断路器

当电路发生故障或异常时,伴随着电流不断升高,并且升高的电流有可能能损坏电路中的某些重要器件,也有可能烧毁电路甚至造成火灾。若电路中正确地安置了保险丝,那么保险丝就会在电流异常升高到一定的高度和热度的时候,自身熔断切断电流,从而起到保护电路安全运行的作用。

断路器也称为 服务熔断,在多个服务调用的时候,服务 A 依赖服务 B ,服务 B 依赖服务 C ,如果服务C 响应时间过长或者不可用,则会让服务 B 占用太多系统资源,而服务 A 也依赖服 B ,同时也在占用大量的系统资源,造成系统雪崩的情况出现。 Istio 断路器通过网格中的边车对流量进行拦截判断处理,避免了在代码中侵入控制逻辑,非常方便的就实服务熔断的能力。

image-20211105171951038

在微服务架构中,在高并发情况下,如果请求数量达到一定极限(可以自己设置阈值),超出了设置的阈值,断路器会自动开启服务保护功能,然后通过服务降级的方式返回一个友好的提示给客户端。假设当10个请求中,有10%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到10s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。

示例2:服务降级(提高用户体验效果)

比如电商平台,在针对618、双11的时候会有一些秒杀场景,秒杀的时候请求量大,可能会返回报错标志“当前请求人数多,请稍后重试”等,如果使用服务降级,无法提供服务的时候,消费者会调用降级的操作,返回服务不可用等信息,或者返回提前准备好的静态页面写好的信息。

2)超时

什么时候需要用到超时?

在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性。

示例:

image-20211105171808202

  • nginx服务设置了超时时间为 3 秒,如果超出这个时间就不在等待,返回超时错误

  • httpd服务设置了响应时间延迟 5 秒,任何请求都需要等待 5 秒后才能返回

  • client通过访问 nginx 服务去反向代理 httpd 服务,由于 httpd 服务需要 5 秒后才能返回,但nginx 服务只等待 3 秒,所以客户端会提示超时错误。

3)重试

istio 重试机制就是如果调用服务失败, Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务 。

示例:

image-20211105171726508

客户端调用nginx,nginx 将请求转发给 tomcat 。 tomcat 通过故障注入而中止对外服务, nginx设置如果访问 tomcat 失败则会重试 3 次。

4)多路由规则

  • HTTP 重定向(HTTPRedirect)

  • HTTP 重写(HTTPRewrite)

  • HTTP 重试(HTTPRetry)

  • HTTP 故障注入(HTTPFaultInjection)

  • HTTP 跨域资源共享(CorsPolicy)

2 Istio架构

istio服务网格从逻辑上分为数据平面和控制平面。

image-20211105172222239

数据平面由一组以Sidecar方式部署的智能代理(Envoy+Polit-agent)组成。这些代理承载并控制微服务之间的所有网络通信,管理入口和出口流量,类似于一线员工。 Sidecar 一般和业务容器绑定在一起(在Kubernets中以自动注入的方式注入到到业务pod中),来劫持业务应用容器的流量,并接受控制面组件的控制,同时会向控制面输出日志、跟踪及监控数据。

Envoy 和 pilot-agent 打在同一个镜像中,即sidecar Proxy。

控制平面负责管理和配置代理来路由流量。istio1.5+中使用了一个全新的部署模式,重建了控制平面,将原有的多个组件整合为一个单体结构istiod,这个组件是控制平面的核心,管理Istio的所有功能,主要包括Pilot、Mixer、Citadel等服务组件。

istiod是新版本中最大的变化,以一个单体组件替代了原有的架构,降低了复杂度和维护难度,但原有的多组件并不是被完全移除,而是在重构后以模块的形式整合在一起组成了istiod。

结合下图我们来理解Istio的各组件的功能及相互之间的协作方式。

image-20211105172229417

1)自动注入:在创建应用程序时自动注入 Sidecar代理Envoy程序。在 Kubernetes中创建 Pod时,Kube-apiserver调用控制面组件的 Sidecar-Injector服务,自动修改应用程序的描述信息并注入Sidecar。在真正创建Pod时,在创建业务容器的Pod中同时创建Sidecar容器。

2)流量拦截:在Pod初始化时设置iptables 规则,基于配置的iptables规则拦截业务容器的Inbound流量和Outbound流量到Sidecar上。而应用程序感知不到Sidecar的存在,还以原本的方式 进行互相访问。上图中,流出frontend服务的流量会被 frontend服务侧的 Envoy拦截,而当流量到达forecast容器时,Inbound流量被forecast 服务侧的Envoy拦截。

3)服务发现:服务发起方的 Envoy 调用控制面组件 Pilot 的服务发现接口获取目标服务的实例列表。上图中,frontend 服务侧的 Envoy 通过 Pilot 的服务发现接口得到forecast服务各个实例的地址。

4)负载均衡:服务发起方的Envoy根据配置的负载均衡策略选择服务实例,并连接对应的实例地址。上图中,数据面的各个Envoy从Pilot中获取forecast服务的负载均衡配置,并执行负载均衡动作。

5)流量治理:Envoy 从 Pilot 中获取配置的流量规则,在拦截到 Inbound 流量和Outbound 流量时执行治理逻辑。上图中, frontend 服务侧的 Envoy 从 Pilot 中获取流量治理规则,并根据该流量治理规则将不同特征的流量分发到forecast服务的v1或v2版本。

6)访问安全:在服务间访问时通过双方的Envoy进行双向认证和通道加密,并基于服务的身份进行授权管理。上图中,Pilot下发安全相关配置,在frontend服务和forecast服务的Envoy上自动加载证书和密钥来实现双向认证,其中的证书和密钥由另一个管理面组件 Citadel维护。

7)服务监测:在服务间通信时,通信双方的Envoy都会连接管理面组件Mixer上报访问数据,并通过Mixer将数据转发给对应的监控后端。上图中,frontend服务对forecast服务的访问监控指标、日志和调用链都可以通过这种方式收集到对应的监控后端。

8)策略执行:在进行服务访问时,通过Mixer连接后端服务来控制服务间的访问,判断对访问是放行还是拒绝。上图中,Mixer 后端可以对接一个限流服务对从frontend服务到forecast服务的访问进行速率控制等操作。

9)外部访问:在网格的入口处有一个Envoy扮演入口网关的角 色。上图中,外部服务通过Gateway访问入口服务 frontend,对 frontend服务的负载均衡和一些流量治理策略都在这个Gateway上执行。

3 Istio组件详解

Istio服务组件 有很多 ,从上面的流程中基本能看出每个组件如何协作的,下面具体讲解每个组件的具体用途和功能。

3.1Pilot

Pilot是 Istio 的主要控制组件,下发指令控制客户端。在整个系统中, Pilot 完成以下任务:

  • 从 Kubernetes 或者其他平台的注册中心获取服务信息,完成服务发现过程。

  • 读取 Istio 的各项控制配置,在进行转换之后,将其发给数据面进行实施。

image-20211105175636351

Pilot 将配置内容下发给数据面的 Envoy,Envoy 根据 Pilot 指令,将路由、服务、监听、集群等定义信息转换为本地配置,完成控制行为的落地。

  • Pilot为Envoy提供服务发现

  • 提供流量管理功能(例如,A/B 测试、金丝雀发布等)以及弹性功能(超时、重试、熔断器等);

  • 生成envoy配置

  • 启动envoy

  • 监控并管理envoy的运行状况,比如envoy出错时pilot-agent负责重启envoy,或者envoy配置变更后reload envoy

3.2 Envoy

Envoy是用 C++ 开发的高性能代理,用于协调服务网格中所有服务的入站和出站流量。

Envoy有许多强大的功能,例如:

  • 动态服务发现

  • 负载均衡

  • TLS终端

  • HTTP/2与gRPC代理

  • 断路器

  • 健康检查

  • 流量拆分

  • 灰度发布

  • 故障注入

1)Istio中 Envoy 与服务关系

为了便于理解Istio 中 Envoy 与服务的关系,下图为 Envoy 的拓扑图,如图所示:

image-20211105175838290

Envoy和 Service A 同属于一个 Pod ,共享网络和命名空间 Envoy 代理进出 Pod A 的流量,并将流量按照外部请求的规则作用于 Service A 中。

2)Pilot-agent介绍

  • Envoy不直接跟k8s交互,通过 pilot-agent管理的

  • Pilot-agent进程根据K8S APIserver中的配置信息生成Envoy的配置文件,并负责启动Envoy进程。

  • Envoy由Pilot-agent进程启动,启动后,Envoy读取Pilot-agent为它生成的配置文件,然后根据该文件的配置获取到Pilot的地址,通过数据面从pilot拉取动态配置信息,包括路由(route),监听器(listener),服务集群(cluster)和服务端点(endpoint)。

3.3 Citadel

负责处理系统上不同服务之间的TLS通信。 Citadel充当证书颁发机构(CA),并生成证书以允许在数据平面中进行安全的mTLS通信。

Citadel是 Istio的核心安全组件,提供了自动生 成、分发、轮换与撤销密钥和证书功能。Citadel一直监听 Kube- apiserver,以 Secret的形式为每个服务都生成证书密钥,并在Pod创建时挂载到Pod上,代理容器使用这些文件来做服务身份认证,进而代 理两端服务实现双向TLS认证、通道加密、访问授权等安全功能。如图 所示,frontend 服 务对 forecast 服务的访问用到了HTTP方式,通过配置即可对服务增加认证功能,双方的Envoy会建立双向认证的TLS通道,从而在服务间启用双向认证的HTTPS。

image-20211105180018022

 

3.4 Galley

Galley是istio的配置验证、提取、处理和分发的组件。Galley是提供配置管理的服务。实现原理是通过k8s提供的ValidatingWebhook对配置进行验证。

Galley使Istio可以与Kubernetes之外的其他环境一起工作,因为它可以将不同的配置数据转换为Istio可以理解的通用格式。

3.5 Ingressgateway

Ingressgateway 就是入口处的 Gateway,从网格外访问网格内的服务就是通过这个Gateway进行的。istio-ingressgateway是一个Loadbalancer类型的Service,不同于其他服务组件只有一两个端 口,istio-ingressgateway 开放了一组端口。

这些就是网格内服务的外部访问端口。如下图所示,网格入口网关istio-ingressgateway的负载和网格内的Sidecar是同样的执行流程,也和网格内的其他 Sidecar一样从 Pilot处接收流量规则并执行。

image-20211105180100096

3.6 Sidecar injector

Sidecar-injector是负责自动注入的组件,只要开启了自动注 入,在Pod创建时就会自动调用istio-sidecar-injector向Pod中注入Sidecar 容器。

在 Kubernetes环境下,根据自动注入配置,Kube-apiserver在拦截到 Pod创建的请求时,会调用自动注入服务 istio-sidecar-injector 生成 Sidecar 容器的描述并将其插入原 Pod的定义中,这样,在创建的 Pod 内除了包括业务容器,还包括 Sidecar容器,这个注入过程对用户透明。

3.7 其他组件

除了以”istio“ 为前缀的 Istio 自有组件,在集群中一般还安装 Jaeger agent 、 Jaeger-collector 、 Jaeger-query 、 Kiali 、 Prometheus 、 Grafana 、 Tracing 、 Zipkin 等组件,这些组件提供了 Istio 的调用链、监控等功能,可以选择安装来完成完整的服务监控管理功能。

4 在Kubernetes集群中安装Istio

4.1 准备部署环境

1)下载

cd /root/ && wget https://github.com/istio/istio/releases/download/1.11.4/istio-1.11.4-linux-amd64.tar.gz

2)解压

 tar -zxvf istio-1.11.4-linux-amd64.tar.gz && mv istio-1.11.4 /usr/local/kubernetes/ 

3)添加环境变量

export PATH=/usr/local/kubernetes/istio-1.11.4/bin:$PATH

4)移动客户端文件

cp -ar /usr/local/kubernetes/istio-1.11.4/bin/istioctl /usr/local/bin/

4.2 安装Istio

1)执行安装

istioctl install --set profile=demo -y

注意:执行安装过程中出现失败情况,一般都是由于网络拉取不到镜像 拉取到镜像后服务无法启动,一般是和K8S环境有关,建议使用kubeadm方式安装实验

image-20211108092131766

2)查看部署情况

kubectl get pods -n istio-system -o wide

3)卸载Istio集群(需要时才操作)

istioctl manifest generate --set profile=demo | kubectl delete -f -

5 Istio部署演示demo-bookinfo

5.1 功能介绍

该应用由四个单独的微服务构成,这个应用模仿在线书店的一个分类,显示一本书的信息,页面上会显示一本书的描述,书籍的细节(ISBN、页数等),以及关于这本书的一些评论。

Bookinfo应用分为四个单独的微服务

  • productpage这个微服务会调用details和reviews两个微服务,用来生成页面;

  • details这个微服务中包含了书籍的信息;

  • reviews这个微服务中包含了书籍相关的评论,它还会调用ratings微服务;

  • ratings这个微服务中包含了由书籍评价组成的评级信息。

reviews微服务有3个版本

  • v1版本不会调用ratings服务;

  • v2版本会调用ratings服务,并使用1到5个黑色星形图标来显示评分信息;

  • v3版本会调用ratings服务,并使用1到5个红色星形图标来显示评分信息。

image-20211108093128704

Bookinfo应用中的几个微服务是由不同的语言编写的。这些服务对istio并无依赖,但是构成了一个有代表性的服务网格的例子:它由多个服务、多个语言构成,并且reviews服务具有多个版本。

5.2 部署应用

要在Istio中运行这一应用,无需对应用自身做出任何改变。 只要简单的在 Istio 环境中对服务进行配置和运行,具体一点说就是把 Envoy sidecar 注入到每个服务之中。 最终的部署结果将如下图所示:

image-20211108093212071

所有的微服务都和Envoy sidecar集成在一起,被集成服务所有的出入流量都被envoy sidecar 所劫持,这样就为外部控制准备了所需的 Hook,然后就可以利用Istio控制平面为应用提供服务路由、遥测数据收集以及策略实施等功能。

1)创建标签绑定命名空间

kubectl label namespace default istio-injection=enabled

image-20211108094013262

2)部署应用

因为属于istio的demo实例,所以在istio文件夹中可以找到对应的yaml文件

kubectl apply -f /usr/local/kubernetes/istio-1.11.4/samples/bookinfo/platform/kube/bookinfo.yaml 

查看部署情况

kubectl get deploy,pods,svc -o wide

image-20211108095047806

确认 Bookinfo 应用是否正在运行,在某个Pod中用curl命令对应用发送请求,例如ratings:

kubectl exec -it $(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}') -c ratings -- curl productpage:9080/productpage | grep -o "<title>.*</title>"

image-20211108095836670

3)部署网关

kubectl apply -f /usr/local/kubernetes/istio-1.11.4/samples/bookinfo/networking/bookinfo-gateway.yaml

查询网关

kubectl get virtualservices,gateway

image-20211108100959946

4)查询ingress IP和端口

执行如下指令,明确自身 Kubernetes 集群环境支持外部负载均衡:

kubectl get svc istio-ingressgateway -n istio-system

image-20211108104834575

如果EXTERNAL-IP值已设置,说明环境正在使用外部负载均衡,可以用其为ingress gateway 提供服务。 如果EXTERNAL-IP值为<none>(或持续显示<pending>), 说明环境没有提供外部负载均衡,无法使用ingress gateway。在这种情况下,可以使用服务的NodePort访问网关。

5)访问测试

http://NodeIP:port/productpage

image-20211108105116774

6)扩展外部IP-extertal-IP

修改svc配置

kubectl edit svc istio-ingressgateway -n istio-system

增加以下字段

image-20211108105905305

查看istio-ingressgateway的svc

kubectl get svc istio-ingressgateway -n istio-system

image-20211108110007060

访问测试

http://NodeIP/productpage

image-20211108110047546

5.3 卸载应用

可以使用下面的命令来完成应用的删除和清理了:

  • 删除路由规则,并销毁应用的 Pod

sh /usr/local/kubernetes/istio-1.11.4/samples/bookinfo/platform/kube/cleanup.sh
  • 确认应用已经关闭

kubectl get virtualservices,destinationrules,gateway,pods,svc

6 Istio实现灰度发布

6.1 灰度发布介绍

灰度发布也叫金丝雀部署,是指通过控制流量的比例,实现新老版本的逐步更替。比如对于服务 A 有 version1 、 version2 两个版本 当前两个版本同时部署,但是 version1 比例90% version2 比例 10% ,看运行效果,如果效果好逐步调整流量占比 80 20 7030 ·····10 90 0 100 ,最终 version1 版本下线。

灰度发布的特点

  • 新老版本共存

  • 可以实时根据反馈动态调整占比

  • 理论上不存在服务完全宕机的情况

  • 适合于服务的平滑升级与动态更新

6.2 实现灰度发布

1)创建演示环境

mkdir -p /opt/k8s-cfg/istio/

1)创建Deploy文件

cat <<EOF> /opt/k8s-cfg/istio/canary-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: appv1
labels:
app: v1
spec:
replicas: 1
selector:
matchLabels:
app: v1
apply: canary
template:
metadata:
labels:
app: v1
apply: canary
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: appv2
labels:
app: v2
spec:
replicas: 1
selector:
matchLabels:
app: v2
apply: canary
template:
metadata:
labels:
app: v2
apply: canary
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
EOF

kubectl apply -f /opt/k8s-cfg/istio/canary-deploy.yaml

登录到容器内修改下index.html访问文件,以便后续测试

kubectl exec -it appv1-6bcc5579f7-9smts -c nginx -- /bin/bash

echo v1 > /usr/share/nginx/html/index.html

cat /usr/share/nginx/html/index.html

image-20211108114918298

2)创建Service文件

cat <<EOF> /opt/k8s-cfg/istio/canary-service.yaml
apiVersion: v1
kind: Service
metadata:
name: canary
labels:
apply: canary
spec:
selector:
apply: canary
ports:
- protocol: TCP
port: 80
targetPort: 80
EOF

kubectl apply -f /opt/k8s-cfg/istio/canary-service.yaml

3)创建Gateway

cat <<EOF> /opt/k8s-cfg/istio/canary-gateway.yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: canary-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
EOF

kubectl apply -f /opt/k8s-cfg/istio/canary-gateway.yaml

4)创建Virtualservice

cat <<EOF> /opt/k8s-cfg/istio/canary-virtual.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: canary
spec:
hosts:
- "*"
gateways:
- canary-gateway
http:
- route:
- destination:
host: canary.default.svc.cluster.local
subset: v1
weight: 90
- destination:
host: canary.default.svc.cluster.local
subset: v2
weight: 10
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: canary
spec:
host: canary.default.svc.cluster.local
subsets:
- name: v1
labels:
app: v1
- name: v2
labels:
app: v2
EOF

kubectl apply -f /opt/k8s-cfg/istio/canary-virtual.yaml

5)查看部署情况

kubectl get virtualservices,destinationrules,gateway,pods,svc

image-20211108114104566

6)查看演示效果

查看istio-ingressgateway的svc

kubectl get svc istio-ingressgateway -n istio-system

image-20211108110007060

for i in `seq 1 100`; do curl 192.168.5.3:31817 ;done > 1.txt

image-20211108115214980

 

7 Istio核心资源解读

7.1 Gateway

在Kubernetes 环境中, Ingress controller 用于管理进入集群的流量。在 Istio 服务网格中 Istio Ingress Gateway 承担相应的角色,它使用新的配置模型( Gateway 和 VirtualServices )完成流量管理的功能。通过下图做一个总的描述。

image-20211108115758247

  • 用户向某端口发出请求

  • 负载均衡器监听端口,并将请求转发到集群中的某个节点上。 Istio Ingress Gateway Service会监听集群节点端口的请求

  • Istio Ingress Gateway Service 将请求交给 Istio Ingress Gateway Pod 处理。IngressGateway Pod 通过 Gateway 和 VirtualService 配置规则处理请求。其中, Gateway 用来配置端口、协议和证书; VirtualService 用来配置一些路由信息(找到请求对应处理的服务 App Service

  • Istio Ingress Gateway Pod 将请求转给 App Service

  • 最终的请求会交给 App Service 关联的 App Deployment 处理

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: canary-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
EOF

网关是一个运行在网格边缘的负载均衡器,用于接收传入或传出的 HTTP/TCP 连接。 主要工作是接受外部请求, 把请求 转发到内部服务 。 网格边缘的 Ingress 流量,会通过对应的 Istio IngressGateway Controller 进入 到集群内部 。

在上面 这个 yaml 里我们配置了一个监听 80 端口的入口网关,它会将 80 端口的 http 流量导入到集群内对应的 Virtual Service 上 。

注意:

    hosts:
- "*"

表示通配符, 通过任何域名都可以访问

7.2 VirtualService

VirtualService是 Istio 流量治理的一个核心配置,可以说是 Istio 流量治理中最重要、最复杂的。VirtualService 在形式上表示一个虚拟服务,将满足条件的流量都转发到对应的服务后端,这个服务后端可以是一个服务,也可以是在 DestinationRule 中定义的服务的子集。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: canary
spec:
hosts:
- "*"
gateways:
- canary-gateway
http:
- route:
- destination:
host: canary.default.svc.cluster.local
subset: v1
weight: 90
- destination:
host: canary.default.svc.cluster.local
subset: v2
weight: 10

这个虚拟服务会收到上一个gateway 中所有 80 端口来的 http 流量。

VirtualService主要由以下部分组成:

  • hosts

  • Gateway

  • 路由

hosts字段列出了 virtual service 的 虚拟 主机。它是客户端向服务发送请求时使用的一个或多个地址,通过该字段提供的地址访问 virtual service ,进而访问后端服务。在集群内部 网格内 使用时通常与 kubernetes 的 Service 同 名 ;当需要在集群外部 网格外 访问时,该字段为 gateway 请求的地址,即与 gateway 的 hosts 字段相同。

hosts:
- reviews

virtual service的主机名可以是 IP 地址、 DNS 名称,也可以是短名称 (例如 Kubernetes 服务短名称),该名称会被隐式或显式解析为全限定域名(FQDN),具体取决于 istio 依赖的平台。可以使用前缀通配符("*")为所有匹配的服务创建一组路由规则。 virtual service 的 hosts 不一定是 Istio 服务注册表的一部分,它们只是虚拟目的地,允许用户为网格无法路由到的虚拟主机建立流量模型。

virtual service 的 hosts 短域名在解析为完整的域名时,补齐的 namespace 是 VirtualService 所在的命名空间,而非 Service 所在的命名空间。如上例的 hosts 会被解析为:reviews.default.svc.cluster.l ocal 。

hosts:
- "*"
# *表示通配符,任何域名都可以

7.3 virtualservice 配置路由规则

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v3

在http 字段包含了虚拟服务的路由规则,用来描述匹配条件和路由行为,它们把 HTTP/1.1 、HTTP2 和 gRPC 等流量发送到 hosts 字段指定的目标 。

示例中的第一个路由规则有一个条件,以match 字段开始 。 此路由 接收 来自 ”jason“ 用户的所有请求 ,把请求发送到 destination 指定 的 v 2 子集 。

1)路由规则优先级:

在上面例子中,不满足第一个路由规则的流量均流向一个默认的目标,该目标在第二条规则中指定。因此,第二条规则没有 match 条件,直接将流量导向 v3 子集。

2)多路由规则解读:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- bookinfo.com
http:
- match:
- uri:
prefix: /reviews
route:
- destination:
host: reviews
- match:
- uri:
prefix: /ratings
route:
- destination:
host: ratings

路由规则是将特定流量子集路由到指定目标地址的工具。可以在流量端口、header 字段、 URI 等内容上设置匹配条件。例如, 上面 这个 虚拟服务让用户发送请求到两个独立的服务: ratings 和reviews 相当于访问 http://bookinfo.com/ ratings 和 http://bookinfo.com/reviews 虚拟服务规则根据请求的 URI 把请求路由到特定的目标地址。

路由的destination 字段指定了匹配条件的流量的实际地址。与 virtual service 的主机不同,该host 必须是存在于 istio 的服务注册表 如 kubernetes services consul services 等 中的真实目的地或由 ServiceEntries 声明的 hosts ,否则 Envoy 不知道应该将流量发送到哪里。它可以是一个带代理的网格服务或使用 s ervice entry 添加的非网格服务。在 kubernetes 作为平台的情况下, host 表示名为kubernetes 的 service 名称:

- destination:
host: canary.default.svc.cluster.local
subset: v1
weight: 90

7.4 DestinationRule

destinationrule 是 istio 流量路由功能的重要组成部分。一个 virtual service 可以看作是如何将流量分发给特定的目的地,然后调用 destination rule 来配置分发到该目的地的流量。 destinationrule 在 virtual service 的路由规则之后起作用 即在 virtual service 的 math -->route destination 之后起作用,此时流量已经分发到真实的service 上 ),应用于真实的目的地。

可以使用destination rule 来指定命名的服务子集,例如根据版本对 服务的实例进行分组,然后通过 virtual service 的路由规则中的服务子集将控制流量分发到不同服务的实例中。

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: canary
spec:
host: canary.default.svc.cluster.local
subsets:
- name: v1
labels:
app: v1
- name: v2
labels:
app: v2

在虚拟服务中使用Hosts 配置默认绑定的路由地址,用 http.route 字段,设置 http 进入的路由地址,可以看到, 上面 导入到了目标规则为 v 1 和 v 2 的子集 。

v1 子集对应的是 具有如下标签的 pod

selector:
matchLabels:
app: v1

流量控制流程:

Gateway-->VirtaulService -->TCP/HTTP Router -->DestinationWeight -->Subset:Port

8 Istio核心功能演示

8.1 断路器

官网介绍:https://istio.io/latest/zh/docs/tasks/traffic-management/circuit-breaking/

断路器是创建弹性微服务应用程序的重要模式。断路器使应用程序可以适应网络故障和延迟等网络不良影响。

1)创建熔断器后端服务器

kubectl apply -f /usr/local/kubernetes/istio-1.11.4/samples/httpbin/httpbin.yaml 

查看

kubectl get pods,svc,sa

image-20211108133947473

2)创建DestinationRule规则

cat <<EOF> httpbin-DR.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin
trafficPolicy:
connectionPool:
# 连接池( TCP | HTTP )配置,例如:连接数、并发请求等
tcp:
maxConnections: 1
# TCP 连接池中的最大连接请求数,当超过这个值,会返回 503 代码 。如两个请求过来,就会有一个请求返回 503
http:
http1MaxPendingRequests: 1
# 连接到目标主机的最大挂起请求数 ,也就是待处理请求数 。 这里的目标指的是 virtualservice 路由规则中配置的destination 。
maxRequestsPerConnection: 1
# 连接池中每个连接最多处理 1 个请求后就关闭,并根据需要重新创建连接池中的连接
outlierDetection:
# 异常检测配置,传统意义上的熔断配置,即对规定时间内服务错误数的监测
consecutiveGatewayErrors: 1
# 连续错误数 1 ,即连续返回 502-504 状态码的 Http 请求错误数
interval: 1s
# 错误异常的扫描间隔 1s ,即在 interval 1s )内连续发生 consecutiveGatewayErrors 1 )个错误,则触发服务熔断
baseEjectionTime: 3m
# 基本驱逐时间 3 分钟,实际驱逐时间为 baseEjectionTime* 驱逐次数
maxEjectionPercent: 100
# 最大驱逐百分比 100%
EOF

kubectl apply -f httpbin-DR.yaml

查看

kubectl get destinationrule

image-20211108134610197

3)添加客户端访问 httpbin 服务

创建一个客户端以将流量发送给httpbin 服务。该客户端是一个简单的负载测试客户端, Fortio 可以控制连接数,并发数和 HTTP 调用延迟。使用此客户端来 跳闸 在 DestinationRule 中设置的断路器策略。

kubectl apply -f /usr/local/kubernetes/istio-1.11.4/samples/httpbin/sample-client/fortio-deploy.yaml

image-20211108135112113

测试访问:

kubectl exec  -it fortio-deploy-5bb66f84-xtwsn -c fortio -- /usr/bin/fortio curl http://httpbin:8000/get

image-20211108140245176

4)触发断路器

在DestinationRule 设置中,指定了 maxConnect ions: 1 和 http1MaxPendingRequests: 1 。这些规则表明,如果超过一个以上的连接并发请求,则 istio proxy 在为进一步的请求和连接打开路由时,应该会看到下面的情况 。

以两个并发连接(-c 2 )和发送 20 个请求(-n 20 )调用服务

kubectl exec -it fortio-deploy-5bb66f84-xtwsn -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get

image-20211108141343037

8.2 超时

在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性 Istio 使用虚拟服务来优雅实现超时处理。

下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat 。 nginx 服务设置了超时时间为 2秒,如果超出这个时间就不在等待,返回超时错误 。 tomcat 服务设置了响应时间延迟 10 秒,任何请求都需要等待 10 秒后才能返回 。 client 通过访问 nginx 服务去反向代理 tomcat 服务,由于 tomcat 服务需要 10 秒后才能返回,但 nginx 服务只等待 2 秒,所以客户端会提示超时错误 。

1)创建演示环境

mkdir -p /opt/k8s-cfg/istio/timeout

2)创建后端服务

cat <<EOF> /opt/k8s-cfg/istio/timeout/nginx-tomcat-deploy.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-tomcat
labels:
server: nginx
app: web
spec:
replicas: 1
selector:
matchLabels:
server: nginx
app: web
template:
metadata:
name: nginx
labels:
server: nginx
app: web
spec:
containers:
- name: nginx
image: nginx:latest
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat
labels:
server: tomcat
app: web
spec:
replicas: 1
selector:
matchLabels:
server: tomcat
app: web
template:
metadata:
name: tomcat
labels:
server: tomcat
app: web
spec:
containers:
- name: tomcat
image: docker.io/kubeguide/tomcat-app:v1
EOF

kubectl apply -f /opt/k8s-cfg/istio/timeout/nginx-tomcat-deploy.yaml
cat <<EOF> /opt/k8s-cfg/istio/timeout/nginx-tomcat-svc.yaml
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
server: nginx
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
selector:
server: tomcat
ports:
- name: http
port: 8080
targetPort: 8080
protocol: TCP
EOF

kubectl apply -f /opt/k8s-cfg/istio/timeout/nginx-tomcat-svc.yaml
kubectl get pods,svc -o wide

image-20211108143015130

3)创建VirtualService路由规则

cat <<EOF> /opt/k8s-cfg/istio/timeout/virtual-nginx-tomcat.yaml
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: nginx-vs
spec:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
timeout: 2s
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: tomcat-vs
spec:
hosts:
- tomcat-svc
http:
- fault:
delay:
percentage:
value: 100
fixedDelay: 10s
route:
- destination:
host: tomcat-svc
EOF

kubectl apply -f /opt/k8s-cfg/istio/timeout/virtual-nginx-tomcat.yaml

4 )设置反向代理

登录到pod容器内

kubectl exec -it nginx-tomcat-c9d66cc79-hk6sp -c nginx -- /bin/bash
# 安装vim编辑器
apt-get update
apt-get -y install vim
vim /etc/nginx/conf.d/default.conf 

proxy_pass http://tomcat-svc:8080;
proxy_http_version 1.1;

image-20211108151100778

# 更新配置文件
nginx -s reload

5)验证超时

创建测试容器

kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh

time wget -q -O - http://nginx-svc

while true;do wget -q -O - http://nginx-svc; done

image-20211108152143749

每隔2 秒,由于 nginx 服务的超时时间到了而 tomcat 未有响应,则提示返回超时错误。

image-20211108152227100

验证故障注入效果,执行如下语句:

image-20211108152427795

 

 

以下您可能有感兴趣的文章: