第9章-Istio微服务
9.1 微服务基本介绍
9.2 微服务架构发展进程
9.3 Istio 概念、架构、组件详细介绍
9.4 在 k8s 平台安装 Istio
9.5 在 k8s 集群部署 bookinfo 在线书店,开启 istio 功能
9.6 通过 Istio 实现灰度发布
9.7 istio 核心功能演示
9.1 微服务基本介绍
微服务是一种软件架构模式,它将大型的单一应用程序拆分成一组小型、独立的服务。每个服务都专注于执行一个特定的业务功能,并通过轻量级的通信机制进行相互协作。
我们可以将大型的单一应用程序比喻为一座大厦,而微服务则是这座大厦中的许多独立的房间。每个房间代表一个微服务,拥有自己独立的功能和责任。这些微服务之间通过简单的方式进行通信,就像房间之间的门一样。
微服务的好处在于它们的独立性和可扩展性。由于每个微服务都相对较小且专注于一个特定的任务, 开发团队可以更加灵活地独立开发、部署和扩展这些服务。此外,微服务可以使用不同的技术栈和编程语言,因为它们之间是通过通用的接口进行通信。
总而言之,微服务是一种将大型应用程序拆分为小型、独立服务的架构模式,通过简单的通信机制使这些服务相互协作。它们提供了灵活性、可扩展性和模块化的好处,有助于构建可靠、可维护和高效的软件系统。
9.2 微服务架构发展进程
1、单体应用阶段:最初阶段,应用程序作为一个单一的、整体的实体进行开发和部署。所有的功能和业务逻辑都集中在一个应用程序中,这种架构简单直接,但随着应用程序的不断增长和复杂性的提高, 会面临扩展和维护困难的挑战。
2、服务拆分阶段:为了应对单体应用的扩展和维护困难,开始将应用程序拆分为一些较小的、独立的服务。这些服务通常按照业务功能或领域进行划分,每个服务具有自己的数据库和业务逻辑。这种拆分可以提高开发团队的独立性和效率,但服务之间的通信方式可能比较复杂。
3、微服务阶段:在微服务阶段,应用程序被进一步拆分为更小粒度的微服务。每个微服务都是一个独立的、自治的服务单元,具有清晰的职责和接口。微服务之间通过轻量级的通信机制(如 HTTP、消息队列等)进行交互。这种架构模式提供了更大的灵活性和可扩展性,使团队能够更独立地开发、部署和维护服务。
4、服务治理阶段:随着微服务数量的增加,服务之间的管理和协调变得更加复杂。在服务治理阶
段,引入了一些工具和技术来帮助管理微服务,如服务注册与发现、负载均衡、故障恢复和监控等。这些工具和技术有助于提高系统的可靠性、可用性和可维护性。
5、云原生阶段:随着云计算和容器技术的发展,微服务架构进一步演化为云原生架构。云原生架构借助容器化技术(如 Docker)和容器编排系统(如 Kubernetes),实现了更高级别的自动化、弹性和可观测性。它还鼓励采用持续交付和 DevOps 实践,使软件开发和部署更加快速和可靠。
9.3 Istio 概念、架构、组件详细介绍
9.3.1 Istio 基本介绍
Istio 是一个开源的服务网格平台,它提供了一组功能丰富的服务网格组件,用于处理微服务之间的流量路由、负载均衡、故障恢复、认证授权、监控和日志等任务。
以下是一些关键特性和组件,可以帮助更好地理解 Istio:
1、代理模型:Istio 通过在每个微服务的容器之间插入一个智能代理(Envoy)来管理服务间的通信。这些代理具有丰富的功能,可以拦截和修改流量,提供负载均衡和故障恢复机制,并与 Istio 控制平面进行通信。
2、流量管理:Istio 允许你定义细粒度的流量路由规则,可以基于请求的属性(如请求头、路径等) 将请求导向不同的微服务版本或实例。它还支持灰度发布、A/B 测试和金丝雀部署等流量控制策略。
3、安全性:Istio 提供了强大的安全功能,包括服务间的认证、授权和加密通信。它可以集成现有的身份验证和授权解决方案,如 JWT、OAuth 和自定义策略。此外,Istio 还提供了流量的加密和解密功能,以保护敏感数据的传输。
4、可观测性:Istio 通过收集、聚合和可视化服务间的指标、日志和分布式追踪数据,提供全面的可观测性。它整合了流行的监控和日志系统,如 Prometheus、Grafana 和 Jaeger,使你能够实时监控和调试微服务的性能和健康状态。
5、策略和控制:Istio 的控制平面允许你定义和执行各种策略,例如流量管理策略、安全策略和配额策略。你可以通过 Istio 的配置和规则来实现服务级别的访问控制、限流和审计等。
Istio 还有其他功能和扩展,如故障注入、自动缩放、跨多集群的支持等,使你能够更好地管理和监控微服务架构。通过使用 Istio,你可以减轻微服务架构中的许多常见管理挑战,提高系统的弹性和可靠性。
9.3.2 Istio 核心特性
流量治理(traffic management)
断路器(circuit breakers)、超时、重试、多路由规则、AB 测试、灰度发布、按照百分比分配流量等。
1) 断路器
互动 1:举个生活中的例子解释断路器
当电路发生故障或异常时,伴随着电流不断升高,并且升高的电流有可能能损坏电路中的某些重要器件,也有可能烧毁电路甚至造成火灾。若电路中正确地安置了保险丝,那么保险丝就会在电流异常升高到一定的高度和热度的时候,自身熔断切断电流,从而起到保护电路安全运行的作用。
断路器也称为服务熔断,在多个服务调用的时候,服务 A 依赖服务 B,服务 B 依赖服务 C,如果服务 C 响应时间过长或者不可用,则会让服务 B 占用太多系统资源,而服务 A 也依赖服 B,同时也在占用大量的系统资源,造成系统雪崩的情况出现。 Istio 断路器通过网格中的边车对流量进行拦截判断处理,避免了在代码中侵入控制逻辑,非常方便的就实服务熔断的能力。
在微服务架构中,在高并发情况下,如果请求数量达到一定极限(可以自己设置阈值),超出了设置的阈值,断路器会自动开启服务保护功能,然后通过服务降级的方式返回一个友好的提示给客户端。假设当 10 个请求中,有 10%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到 10s 钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。
互动 2:服务降级(提高用户体验效果)
比如电商平台,在针对 618、双 11 的时候会有一些秒杀场景,秒杀的时候请求量大,可能会返回报错标志“当前请求人数多,请稍后重试”等,如果使用服务降级,无法提供服务的时候,消费者会调用降级的操作,返回服务不可用等信息,或者返回提前准备好的静态页面写好的信息。
2) 超时
什么时候需要用到超时?
在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性。
通过例子来理解
nginx 服务设置了超时时间为 3 秒,如果超出这个时间就不在等待,返回超时错误
httpd 服务设置了响应时间延迟 5 秒,任何请求都需要等待 5 秒后才能返回
client 通过访问 nginx 服务去反向代理 httpd 服务,由于 httpd 服务需要 5 秒后才能返回,但nginx 服务只等待 3 秒,所以客户端会提示超时错误。
3) 重试
istio 重试机制就是如果调用服务失败,Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务。举个例子:
客户端调用 nginx,nginx 将请求转发给 tomcat。tomcat 通过故障注入而中止对外服务,nginx 设置如果访问 tomcat 失败则会重试 3 次。
4) 按照流量百分比代理
9.3.3 Istio 架构
istio 服务网格从逻辑上分为数据平面和控制平面
1、数据平面由部署为 Sidecar 的一组智能代理(Envoy+Polit-agent)组成。这些代理承载并控制微服务之间的所有网络通信,管理入口和出口流量,类似于一线员工。
2、控制平面管理并配置代理来进行流量路由。
3、istio1.5+中使用了一个全新的部署模式,重建了控制平面,将原有的多个组件整合为一个单体结构istiod,这个组件是控制平面的核心,负责处理配置、证书分发、sidecar 注入等各种功能。istiod 是新本中最大的变化,以一个单体组件替代了原有的架构,在降低复杂度和维护难度的同时,也让易用性得到提升。需要注意的一点是,原有的多组件并不是被完全移除,而是在重构后以模块的形式整合在一起组成了 istiod。
数据平面:
Envoy 和 pilot-agent 打在同一个镜像中,即 Proxy。
9.4 在k8s 平台安装 Istio
9.4.1 准备安装 Istio 要的压缩包
官网下载地址:https://github.com/istio/istio
1、把压缩包上传到 k8s 的控制节点,手动解压:
2、切换到 istio 包所在目录下
Istio-1.13.1.tar.gz 解压的软件包包名是 istio-1.13.1,则:
安装目录包含如下内容:
1) samples/目录下,有示例应用程序
2) bin/目录下,包含 istioctl 的客户端文件。istioctl 工具用于手动注入 Envoy sidecar 代理。
3、把 istioctl 这个可执行文件拷贝到/usr/bin/目录
9.4.2 安装 istio
1. 下载镜像:
上传镜像:
docker load -i examples-bookinfo-details.tar.gz
docker load -i examples-bookinfo-reviews-v1.tar.gz
docker load -i examples-bookinfo-productpage.tar.gz
docker load -i examples-bookinfo-reviews-v2.tar.gz
docker load -i examples-bookinfo-ratings.tar.gz
docker load -i examples-bookinfo-reviews-v3.tar.gz
docker load -i pilot.tar.gz
docker load -i proxyv2.tar.gz docker load -i httpbin.tar.gz
2. 安装
在 k8s 的控制节点 操作
看到如下,说明 istio 初始化完成:
✔ Istio core installed
✔ Istiod installed ✔ Ingress gateways installed ✔ Egress gateways installed ✔ Installation complete
3. 验证 istio 是否部署成功
$ kubectl get pod -n istio-system
NAME READY STATUS RESTARTS AGE
istio-egressgateway-76c96658fd-7smgj 1/1 Running 0 95s
istio-ingressgateway-569d7bfb4-hzfct 1/1 Running 0 95s
istiod-74c64d89cb-lfpkl 1/1 Running 0 100s
4. 卸载 istio 集群,暂时不执行,记住这个命令即可
9.5 在k8s 集群部署 bookinfo 在线书店,开启istio 功能
9.5.1 在线书店功能介绍
在线书店-bookinfo,该应用由四个单独的微服务构成,这个应用模仿在线书店的一个分类,显示一本书的信息,页面上会显示一本书的描述,书籍的细节(ISBN、页数等),以及关于这本书的一些评论。
Bookinfo 应用分为四个单独的微服务
1) productpage 这个微服务会调用 details 和 reviews 两个微服务,用来生成页面;
2) details 这个微服务中包含了书籍的信息;
3) reviews 这个微服务中包含了书籍相关的评论,它还会调用 ratings 微服务;
4) ratings 这个微服务中包含了由书籍评价组成的评级信息。
reviews 微服务有 3 个版本
1) v1 版本不会调用 ratings 服务;
2) v2 版本会调用 ratings 服务,并使用 1 到 5 个黑色星形图标来显示评分信息;
3) v3 版本会调用 ratings 服务,并使用 1 到 5 个红色星形图标来显示评分信息。
下图展示了这个应用的端到端架构
Bookinfo 应用中的几个微服务是由不同的语言编写的。这些服务对 istio 并无依赖,但是构成了一个有代表性的服务网格的例子:它由多个服务、多个语言构成,并且 reviews 服务具有多个版本。
9.5.2 部署应用
要在 Istio 中运行这一应用,无需对应用自身做出任何改变。 只要简单的在 Istio 环境中对服务进行配置和运行,具体一点说就是把 Envoy sidecar 注入到每个 pod 之中。 最终的部署结果将如下图所示:
所有的微服务都和 Envoy sidecar 集成在一起,被集成服务所有的出入流量都被 envoy sidecar 所劫持,这样就为外部控制准备了所需的 Hook,然后就可以利用 Istio 控制平面为应用提供服务路由、遥测数据收集以及策略实施等功能。
9.5.3 启动应用服务
1. 进入 istio 安装目录。
2. istio 默认自动注入 sidecar
**需要为 default 命名空间打上标签 istio-injection=enabled **
3. 使用 kubectl 部署应用
修改镜像:
上面的命令会启动全部的四个服务,其中也包括了 reviews 服务的三个版本(v1、v2 以及 v3)。
4.确认所有的服务和 Pod 都已经正确的定义和启动:
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.102.79.217 <none> 9080/TCP 6m17s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 21d
productpage ClusterIP 10.109.97.72 <none> 9080/TCP 6m16s
ratings ClusterIP 10.107.246.55 <none> 9080/TCP 6m17s
reviews ClusterIP 10.102.248.105 <none> 9080/TCP 6m16s
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
details-v1-567754d5d9-ztlwv 2/2 Running 0 8m6s
productpage-v1-857fcc5584-g4s4r 2/2 Running 0 8m6s
ratings-v1-94cb45f77-dbsnx 2/2 Running 0 8m6s
reviews-v1-6f9d875c6c-z7f4x 2/2 Running 0 8m6s
reviews-v2-7c77fcc7f7-kg7h9 2/2 Running 0 8m6s
reviews-v3-f4949cfcf-lz25h 2/2 Running 0 8m6s
拓展:解决k8s中命名空间无法删除的问题
想要去删除k8s中的一个指定命名空间,刚开始使用命令
使用以上两种命令均无法成功删除命名空间,只会使命名空间的状态为Terminating状态
使用以下方法成功删除
1)使用命令
编辑temp.json,删除以下部分:
2)使用kubectl代理,执行命名
并开启一个新终端,访问测试
3)使用http接口进行删除
curl -k -H "Content-Type: application/json" -X PUT --data-binary @temp.json http://127.0.0.1:8080/api/v1/namespaces/qatest/finalize
5. 确认 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>"
显示如下:
6. 确定 Ingress 的 IP 和端口
现在 Bookinfo 服务已经启动并运行,你需要使应用程序可以从 Kubernetes 集群外部访问,例如从浏览器访问,那可以用 Istio Gateway 来实现这个目标。
1) 为应用程序定义 Ingress 网关:
2) 确认网关创建完成:
3)确定 ingress ip 和端口
执行如下指令,明确自身 Kubernetes 集群环境支持外部负载均衡:
如果 EXTERNAL-IP 值已设置,说明环境正在使用外部负载均衡,可以用其为 ingress gateway 提供服务。 如果 EXTERNAL-IP 值为
若自身环境未使用外部负载均衡器,需要通过 node port 访问。执行如下命令。设置 ingress 端口:
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
## 仅查看端口
$ kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'
30554
$ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
## 仅查看端口
$ kubectl -n istio-system get service istio-ingressgateway -o jsonpath=ec.ports[?(@.name=="https")].nodePort}'
30968
4)设置 GATEWAY_URL
[root@k8s-master01 istio-1.13.1]# INGRESS_HOST=192.168.2.201
#192.168.2.201是安装 istio 的机器,即 k8s 控制节点的 ip
$ export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
$ echo $GATEWAY_URL ## 显示如下:
192.168.2.201:30554
确认可以从集群外部访问应用
可以用 curl 命令来确认是否能够从集群外部访问 Bookinfo 应用程序:
显示如下:
还可以用浏览器打开网址
http://$GATEWAY_URL/productpage,也就是 192.168.2.201:30554/productpage来浏览应用的 Web 页面。
如果刷新几次应用的页面,就会看到productpage 页面中会随机展示 reviews 服务的不同版本的效果(红色、黑色的星形或者没有显示)。
9.5.4 卸载 bookinfo 服务
暂时先不要卸载
可以使用下面的命令来完成应用的删除和清理了:
1.删除路由规则,并销毁应用的 Pod
2.确认应用已经关停
$ kubectl get virtualservices #-- there should be no virtual services
$ kubectl get destinationrules #-- there should be no destination rules
$ kubectl get gateway #-- there should be no gateway
$ kubectl get pods #-- the Bookinfo pods should be deleted
9.6 通过 Istio 实现灰度发布
9.6.1 什么是灰度发布?
灰度发布也叫金丝雀部署 ,是指通过控制流量的比例,实现新老版本的逐步更替。
比如对于服务 A 有 version1、 version2 两个版本 , 当前两个版本同时部署,但是 version1 比例90% ,version2 比例 10% ,看运行效果,如果效果好逐步调整流量占比 80~20 ,70~30 ·····10~90 ,0,100 ,最终 version1 版本下线。
灰度发布的特点:
1) 新老板共存
2) 可以实时根据反馈动态调整占比
3) 理论上不存在服务完全宕机的情况。
4) 适合于服务的平滑升级与动态更新。
9.6.2 使用 istio 进行金丝雀发布
工作节点上传镜像并导入:
创建金丝雀服务
$ cat deployment.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: xuegod/canary:v1
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: xuegod/canary:v2
ports:
- containerPort: 80
更新:
创建 service
$ cat service.yaml
apiVersion: v1
kind: Service
metadata:
name: canary
labels:
apply: canary
spec:
selector:
apply: canary
ports:
- protocol: TCP
port: 80
targetPort: 80
更新 service.yaml 文件
查询canary svc,测试访问
$ kubectl get svc |grep canary |awk -F " " '{print $3}'
$ curl $(kubectl get svc |grep canary |awk -F " " '{print $3}')
创建 gateway
$ cat 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:
- "*"
更新 gateway.yaml
创建 virtualservice
$ cat 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
更新 virtual.yaml 文件
获取 Ingress_port:
$ kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'
30554
显示结果是 30554
验证金丝雀发布效果:
[root@k8s-master01 huidu]# for i in `seq 1 1000`;do curl 192.168.2.201:30554;done > 1.txt
[root@k8s-master01 huidu]# cat 1.txt |grep v1|wc -l
915
[root@k8s-master01 huidu]# cat 1.txt |grep v2|wc -l
85
打开 1.txt 可以看到结果有 约90% 次出现 v1,%10 次出现 canary-v2,符合我们预先设计的流量走向。
9.7 istio 核心功能演示
9.7.1 断路器
官网:https://istio.io/latest/zh/docs/tasks/traffic-management/circuit-breaking/
断路器是创建弹性微服务应用程序的重要模式。断路器使应用程序可以适应网络故障和延迟等网络不良影响。
测试断路器:
1、在 k8s 集群创建后端服务
$ cd istio-1.13.1
$ cat samples/httpbin/httpbin.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
serviceAccountName: httpbin
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
把 httpbin.tar.gz 上传到 工作 节点,手动解压:
$ docker load -i httpbin.tar.gz
$ kubectl apply -f samples/httpbin/httpbin.yaml
## 该 httpbin 应用程序充当后端服务。
2、配置断路器
以免大量请求超出服务处理上线,整个服务崩掉
创建一个目标规则,在调用 httpbin 服务时应用断路器设置:
$ vim destination.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin
trafficPolicy:
connectionPool:
tcp:
maxConnections: 1
http:
http1MaxPendingRequests: 1
maxRequestsPerConnection: 1
outlierDetection:
consecutiveGatewayErrors: 1
interval: 1s
baseEjectionTime: 3m
maxEjectionPercent: 100
### destination.yaml 解释
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin
trafficPolicy:
connectionPool:
## 连接池(TCP | HTTP)配置,例如:连接数、并发请求等tcp:
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%
3、添加客户端访问 httpbin 服务
创建一个客户端以将流量发送给 httpbin 服务。该客户端是一个简单的负载测试客户端,Fortio 可以控制连接数,并发数和 HTTP 调用延迟。使用此客户端来“跳闸”在 DestinationRule 中设置的断路器策略。
部署 fortio 客户端:
把 fortio.tar.gz 上传到 工作节点 节点,手动解压:
使用 fortio 客户端工具调用 httpbin:
[root@k8s-master01 istio-1.13.1]# kubectl get pod
NAME READY STATUS RESTARTS AGE
appv1-746865b8c4-sdvfs 2/2 Running 0 12m
appv2-66995c8c5b-lwhvq 2/2 Running 0 12m
details-v1-567754d5d9-hrvxj 2/2 Running 0 33s
fortio-deploy-7dcd84c469-2ptkg 2/2 Running 0 82s
httpbin-85d76b4bb6-b7476 2/2 Running 0 3m53s
productpage-v1-857fcc5584-qhsm4 2/2 Running 0 33s
ratings-v1-94cb45f77-tq2zd 2/2 Running 0 33s
reviews-v1-6f9d875c6c-m6r8h 2/2 Running 0 33s
reviews-v2-7c77fcc7f7-7px88 2/2 Running 0 33s
reviews-v3-f4949cfcf-wf64n 2/2 Running 0 33s
kubectl exec $(kubectl get pod |grep fortio |awk -F " " '{print $1}') -c fortio -- /usr/bin/fortio curl http://httpbin:8000/get
显示如下:
HTTP/1.1 200 OK
server: envoy
date: Thu, 14 Sep 2023 13:31:39 GMT
content-type: application/json
content-length: 594
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 2
{
"args": {},
"headers": {
"Host": "httpbin:8000",
"User-Agent": "fortio.org/fortio-1.17.1",
"X-B3-Parentspanid": "a0377da700bb7298",
"X-B3-Sampled": "1",
"X-B3-Spanid": "b9ed59aad9587016",
"X-B3-Traceid": "ed7a15421d31226ea0377da700bb7298",
"X-Envoy-Attempt-Count": "1",
"X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=1b7a933fd482b13c77ba522812f61497451fd586d381fe525e1bd597729eebb8;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default"
},
"origin": "127.0.0.6",
"url": "http://httpbin:8000/get"
}
4、触发断路器
在 DestinationRule 设置中,指定了 maxConnections: 1 和 http1MaxPendingRequests: 1。这些规则表明,如果超过一个以上的连接并发请求,则 istio-proxy 在为进一步的请求和连接打开路由时,应该会看到下面的情况 。
以两个并发连接(-c 2)和发送 20 个请求(-n 20)调用服务:
$ kubectl exec -it fortio-deploy-7dcd84c469-2ptkg -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
显示如下:
13:32:53 I logger.go:127> Log level is now 3 Warning (was 2 Info)
Fortio 1.17.1 running at 0 queries per second, 4->4 procs, for 20 calls: http://httpbin:8000/get
Starting at max qps with 2 thread(s) [gomax 4] for exactly 20 calls (10 per thread + 0)
13:32:53 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
13:32:53 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
Ended after 8.154699ms : 20 calls. qps=2452.6
Aggregated Function Time : count 20 avg 0.00076311425 +/- 0.0002641 min 0.000375541 max 0.001333243 sum 0.015262285
## range, mid point, percentile, count
>= 0.000375541 <= 0.001 , 0.000687771 , 85.00, 17
> 0.001 <= 0.00133324 , 0.00116662 , 100.00, 3
## target 50% 0.000726799
## target 75% 0.000921943
## target 90% 0.00111108
## target 99% 0.00131103
## target 99.9% 0.00133102
Sockets used: 20 (for perfect keepalive, would be 2)
Jitter: false
Code 503 : 20 (100.0 %)
Response Header Sizes : count 20 avg 0 +/- 0 min 0 max 0 sum 0
Response Body/Total Sizes : count 20 avg 153 +/- 0 min 153 max 153 sum 3060
All done 20 calls (plus 0 warmup) 0.763 ms avg, 2452.6 qps
只有 20%成功了,其余的都断开了
Response Header Sizes : count 20 avg 0 +/- 0 min 0 max 0 sum 0
Response Body/Total Sizes : count 20 avg 153 +/- 0 min 153 max 153 sum 3060
All done 20 calls (plus 0 warmup) 0.763 ms avg, 2452.6 qps
9.7.2 超时
在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性,Istio 使用虚拟服务来优雅实现超时处理。
下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat。nginx 服务设置了超时时间为 2 秒,如果超出这个时间就不在等待,返回超时错误。tomcat 服务设置了响应时间延迟 10 秒,任何请求都需要等待 10 秒后才能返回。client 通过访问 nginx 服务去反向代理 tomcat 服务,由于 tomcat 服务需要 10 秒后才能返回,但 nginx 服务只等待 2 秒,所以客户端会提示超时错误。
1、上传镜像,yaml文件
把 busybox.tar.gz、 nginx.tar.gz、 tomcat-app.tar.gz 上传到 工作 节点
控制节点创建目录
nginx-deployment.yaml
$ cat nginx-deployment.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
imagePullPolicy: IfNotPresent
---
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
imagePullPolicy: IfNotPresent
nginx-tomcat-svc.yaml
$ cat 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
virtual-tomcat.yaml
$ cat virtual-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
virtual-tomcat.yaml 资源清单重点知识讲解
第一:故障注入:
该设置说明每次调用 tomcat-svc 的 k8s service,都会延迟 10s 才会调用。
第二:调用超时:
该设置说明调用 nginx-svc 的 k8s service,请求超时时间是 2s。
2、部署 tomcat、nginx 服务
需要对 nginx-deployment.yaml 资源文件进行 Istio 注入,将 nginx、tomcat 都放入到网格中。可以采用手工注入 Istio 方式。
查看 Istio 注入情况:
[root@k8s-master01 timeout]# kubectl get pod |grep tomcat
nginx-tomcat-d4d765748-ttfsj 2/2 Running 0 40s
tomcat-8484c667bf-xsg45 2/2 Running 0 40s
3、部署 nginx 和 tomcat 的 service
4、部署虚拟服务
5、设置超时时间
## cat > /etc/nginx/conf.d/default.conf << EOF
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
proxy_pass http://tomcat-svc:8080;
proxy_http_version 1.1;
}
#error_page 404 /404.html;
## redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
## proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
## proxy_pass http://127.0.0.1;
#}
## pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
## root html;
## fastcgi_pass 127.0.0.1:9000;
## fastcgi_index index.php;
## fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
## include fastcgi_params;
#}
## deny access to .htaccess files, if Apache's document root
## concurs with nginx's one
#
#location ~ /\.ht {
## deny all;
#}
}
EOF
编辑完后,再执行如下语句验证配置和让配置生效:
这样,整个样例配置和部署都完成了。
6、验证超时
登录 client,执行如下语句:
$ kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh
$ time wget -q -O - http://nginx-svc
wget: server returned error: HTTP/1.1 504 Gateway Timeout
Command exited with non-zero status 1
real 0m 2.00s
user 0m 0.00s
sys 0m 0.00s
$ while true; do wget -q -O - http://nginx-svc; done
wget: server returned error: HTTP/1.1 504 Gateway Timeout
wget: server returned error: HTTP/1.1 504 Gateway Timeout
wget: server returned error: HTTP/1.1 504 Gateway Timeout
wget: server returned error: HTTP/1.1 504 Gateway Timeout
wget: server returned error: HTTP/1.1 504 Gateway Timeout
每隔 2 秒,由于 nginx 服务的超时时间到了而 tomcat 未有响应,则提示返回超时错误。验证故障注入效果,执行如下语句:
9.7.3 故障注入和重试
Istio 重试机制就是如果调用服务失败,Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务,除非我们启动 Istio 重试机制。
下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat。tomcat 通过故障注入而中止对外服务,nginx 设置如果访问 tomcat 失败则会重试 3 次。
$ cd /root/timeout/
$ kubectl delete -f .
$ kubectl apply -f nginx-deployment.yaml
$ kubectl apply -f nginx-tomcat-svc.yaml
$ kubectl get pods
| NAME | READY | STATUS | RESTARTS AGE |
|---|---|---|---|
| busybox | 2/2 | Running | 0 55m |
| nginx-7f6496574c-zbtqj | 2/2 | Running | 0 10m |
| tomcat-86ddb8f5c9-dqxcq | 2/2 | Running | 0 35m |
$ vim virtual-attempt.yaml
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: nginx-vs
spec:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
retries:
attempts: 3
perTryTimeout: 2s
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: tomcat-vs
spec:
hosts:
- tomcat-svc
http:
- fault:
abort:
percentage:
value: 100
httpStatus: 503
route:
- destination:
host: tomcat-svc
上诉虚拟服务资源清单解读:
第一:故障注入。
该虚拟服务的作用对象就是 tomcat-svc。使用此故障注入后,在网格中该tomcat 就是不可用的。
abort 是模拟 tomcat 服务始终不可用,该设置说明每次调用 tomcat-svc 的 k8s service, 100%都会返回错误状态码 503。
第二:调用超时:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
retries:
attempts: 3
perTryTimeout: 2s
该设置说明调用 nginx-svc 的 k8s service,在初始调用失败后最多重试 3 次来连接到服务子集,每个重试都有 2 秒的超时。
测试
$ kubectl exec -it nginx-tomcat-7dd6f74846-rdqqf -- /bin/sh
## apt-get update
## apt-get install vim -y
## vi /etc/nginx/conf.d/default.conf
## nginx -t
## nginx -s reload
验证重试是否生效
$ kubectl run busybox --image busybox:1.28 -- restart=Never --rm -it busybox -- sh
## wget -q -O - http://nginx-svc
执行结果如下:
请求三次,请求失败,第四次返回503
由上图可知,重试设置生效。
总结:
9.1 微服务基本介绍
9.2 微服务架构发展进程
9.3 Istio 概念、架构、组件详细介绍
9.4 在 k8s 平台安装 Istio
9.5 在 k8s 集群部署 bookinfo 在线书店,开启 istio 功能
9.6 通过 Istio 实现灰度发布
9.7 istio 核心功能演示













