Istio网络治理工具
一、Istio基础
1、什么是istio
官方文档:https://istio.io/latest/docs
官方解释:
An open platform to connect, secure, control and observe services.
翻译过来,就是”连接、安全加固、控制和观察服务的开放平台“。开放平台就是指它本身是开源的,服务对应的是微服务,也可以粗略地理解为单个应用。
- 连接(Connect):智能控制服务之间的调用流量,能够实现灰度升级、AB 测试和蓝绿部署等功能
- 安全加固(Secure):自动为服务之间的调用提供认证、授权和加密。
- 控制(Control):应用用户定义的 policy,保证资源在消费者中公平分配。
- 观察(Observe):查看服务运行期间的各种数据,比如日志、监控和 tracing,了解服务的运行情况。
Istio是ServiceMesh的产品化落地,可以通过在现有的服务器新增部署边车代理(sidecar proxy),应用程序不用改代码,或者只需要改很少的代码,就能实现如下基础功能:
1、帮助微服务之间建立连接,帮助研发团队更好的管理与监控微服务,并使得系统架构更加安全;
2、帮助微服务分层解耦,解耦后的proxy层能够更加专注于提供基础架构能力,例如:
- 服务发现(discovery);
- 负载均衡(load balancing);
- 故障恢复(failure recovery);
- 服务度量(metrics);
- 服务监控(monitoring);
- A/B测试(A/B testing);
- 灰度发布(canary rollouts);
- 限流限速(rate limiting);
- 访问控制(access control);
- 身份认证(end-to-end authentication)。
1.1、服务注册与发现

RPC:RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务
1.2、负载均衡
把前端的请求分发到后台多个服务器
1.3、故障恢复
出现故障具备自行恢复的能力
1.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 指标。
1.5、灰度发布

灰度发布也叫金丝雀发布,在灰度发布开始后,先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进行线上测试,启动的这个新版本应用,就是我们的金丝雀。
如果没有问题,那么可以将少量的用户流量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做各种数据对比,就是所谓的A/B测试。
当确认新版本运行良好后,再逐步将更多的流量导入到新版本上,在此期间,还可以不断地调整新旧两个版本的运行的服务器副本数量,以使得新版本能够承受越来越大的流量压力。直到将100%的流量都切换到新版本上,最后关闭剩下的老版本服务,完成灰度发布。
如果在灰度发布过程中(灰度期)发现了新版本有问题,就应该立即将流量切回老版本上,这样,就会将负面影响控制在最小范围内。
2、Istio核心特性
1、流控(traffic management)
断路器(circuit breakers)、超时、重试、多路由规则、AB测试、灰度发布、按照百分比分配流量等。
2、安全(security)
加密、身份认证、服务到服务的权限控制、K8S里容器到容器的权限控制等。
3、可观察(observability)
追踪、监控、数据收集,通过控制后台全面了解上行下行流量,服务链路情况,服务运行情况,系统性能情况,国内微服务架构体系,这一块做得比较缺乏。
4、平台无关系(platform support)
K8s,物理机,自己的虚机都没问题。
5、集成与定制(integration and customization)
可定制化扩展功能。
2.1、断路器
互动1:举个生活中的例子解释断路器
当电路发生故障或异常时,伴随着电流不断升高,并且升高的电流有可能能损坏电路中的某些重要器件,也有可能烧毁电路甚至造成火灾。若电路中正确地安置了保险丝,那么保险丝就会在电流异常升高到一定的高度和热度的时候,自身熔断切断电流,从而起到保护电路安全运行的作用。
断路器也称为服务熔断,在多个服务调用的时候,服务A依赖服务B,服务B依赖服务C,如果服务C响应时间过长或者不可用,则会让服务B占用太多系统资源,而服务A也依赖服B,同时也在占用大量的系统资源,造成系统雪崩的情况出现。
Istio 断路器通过网格中的边车对流量进行拦截判断处理,避免了在代码中侵入控制逻辑,非常方便的就实服务熔断的能力。

在微服务架构中,在高并发情况下,如果请求数量达到一定极限(可以自己设置阈值),超出了设置的阈值,断路器会自动开启服务保护功能,然后通过服务降级的方式返回一个友好的提示给客户端。
假设当10个请求中,有10%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到10s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。
互动2:服务降级(提高用户体验效果)
比如电商平台,在针对618、双11的时候会有一些秒杀场景,秒杀的时候请求量大,可能会返回报错标志“当前请求人数多,请稍后重试”等,如果使用服务降级,无法提供服务的时候,消费者会调用降级的操作,返回服务不可用等信息,或者返回提前准备好的静态页面写好的信息。
2.2、超时
什么时候需要用到超时?
在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性。
通过例子来理解

nginx 服务设置了超时时间为3秒,如果超出这个时间就不在等待,返回超时错误
httpd 服务设置了响应时间延迟5秒,任何请求都需要等待5秒后才能返回
client 通过访问 nginx 服务去反向代理 httpd 服务,由于 httpd 服务需要5秒后才能返回,但nginx 服务只等待3秒,所以客户端会提示超时错误。
2.3、重试
istio 重试机制就是如果调用服务失败,Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务。
举个例子:

客户端调用 nginx,nginx 将请求转发给 tomcat。tomcat 通过故障注入而中止对外服务,nginx 设置如果访问 tomcat 失败则会重试 3 次。
2.4、多路由规则
- HTTP重定向(HTTPRedirect)
- HTTP重写(HTTPRewrite)
- HTTP重试(HTTPRetry)
- HTTP故障注入(HTTPFaultInjection)
- HTTP跨域资源共享(CorsPolicy)
3、Istio架构
istio服务网格从逻辑上分为数据平面和控制平面。

1、数据平面由一组以 Sidecar 方式部署的智能代理(Envoy+Polit-agent)组成。
这些代理承载并控制微服务之间的所有网络通信,管理入口和出口流量,类似于一线员工。
Sidecar 一般和业务容器绑定在一起(在 Kubernets 中以自动注入的方式注入到到业务 pod 中),来劫持业务应用容器的流量,并接受控制面组件的控制,同时会向控制面输出日志、跟踪及监控数据。Envoy 和 pilot-agent 打在同一个镜像中,即 sidecar Proxy。
2、控制平面负责管理和配置代理来路由流量。
istio1.5+中使用了一个全新的部署模式,重建了控制平面,将原有的多个组件整合为一个单体结构 istiod,这个组件是控制平面的核心,管理 Istio 的所有功能,主要包括 Pilot、Mixer、Citadel 等服务组件。
istiod是新版本中最大的变化,以一个单体组件替代了原有的架构,降低了复杂度和维护难度,但原有的多组件并不是被完全移除,而是在重构后以模块的形式整合在一起组成了istiod。
结合下图我们来理解Istio的各组件的功能及相互之间的协作方式。

- 自动注入: 在创建应用程序时自动注入 Sidecar代理 Envoy 程序。在 Kubernetes 中创建 Pod 时,Kube-apiserver 调用控制面组件的 Sidecar-Injector 服务,自动修改应用程序的描述信息并注入 Sidecar。真正创建 Pod 时,在业务容器的Pod中同时创建Sidecar容器。
- 流量拦截: 在Pod初始化时设置 iptables 规则,基于配置的 iptables 规则拦截业务容器的 Inbound 流量和 Outbound 流量到 Sidecar 上。而应用程序感知不到 Sidecar 的存在,还以原本的方式 进行互相访问。上图中,流出 frontend 服务的流量会被 frontend 服务侧的 Envoy 拦截,而当流量到达 forecast 容器时,Inbound 流量被 forecast 服务侧的 Envoy 拦截。
- 服务发现: 服务发起方的 Envoy 调用控制面组件 Pilot 的服务发现接口获取目标服务的实例列表。上图中,frontend 服务侧的 Envoy 通过 Pilot 的服务发现接口得到forecast服务各个实例的地址。
- 负载均衡:服务发起方的Envoy根据配置的负载均衡策略选择服务实例,并连接对应的实例地址。上图中,数据面的各个Envoy从Pilot中获取forecast服务的负载均衡配置,并执行负载均衡动作。
- 流量治理: Envoy 从 Pilot 中获取配置的流量规则,在拦截到 Inbound 流量和Outbound 流量时执行治理逻辑。上图中, frontend 服务侧的 Envoy 从 Pilot 中获取流量治理规则,并根据该流量治理规则将不同特征的流量分发到forecast服务的v1或v2版本。
- 访问安全:在服务间访问时通过双方的Envoy进行双向认证和通道加密,并基于服务的身份进行授权管理。上图中,Pilot下发安全相关配置,在frontend服务和 forecast 服务的Envoy上自动加载证书和密钥来实现双向认证,其中的证书和密钥由另一个管理面组件 Citadel维护。
- 服务监测: 在服务间通信时,通信双方的Envoy都会连接管理面组件Mixer上报访问数据,并通过Mixer将数据转发给对应的监控后端。上图中,frontend服务对forecast服务的访问监控指标、日志和调用链都可以通过这种方式收集到对应的监控后端。
- 策略执行: 在进行服务访问时,通过Mixer连接后端服务来控制服务间的访问,判断对访问是放行还是拒绝。上图中,Mixer 后端可以对接一个限流服务对从frontend服务到forecast服务的访问进行速率控制等操作。
- 外部访问: 在网格的入口处有一个Envoy扮演入口网关的角 色。上图中,外部服务通过Gateway访问入口服务 frontend,对 frontend服务的负载均衡和一些流量治理策略都在这个Gateway上执行。
问题1:为什么代理会叫sidecar proxy?

看了上图就容易懂了,sidecar和proxy相生相伴,就像摩托车(motor)与旁边的车厢(sidecar)。未来,sidecar和proxy就指微服务进程解耦成两个进程之后,提供基础能力的那个代理进程。
4、Istio组件
# Istio服务组件有很多,从上面的流程中基本能看出每个组件如何协作的,下面具体讲解每个组件的具体用途和功能。
[root@master1 ~]# kubectl get svc -n istio-system |awk '{print $1}'
istio-egressgateway
istio-ingressgateway
istiod
4.1、Pilot
Pilot 是 Istio 的主要控制组件,下发指令控制客户端。
在整个系统中,Pilot 完成以下任务:
- 从 Kubernetes 或者其他平台的注册中心获取服务信息,完成服务发现过程。
- 读取 Istio 的各项控制配置,在进行转换之后,将其发给数据面进行实施。

Pilot 将配置内容下发给数据面的 Envoy,Envoy 根据 Pilot 指令,将路由、服务、监听、集群等定义信息转换为本地配置,完成控制行为的落地。
- Pilot为Envoy提供服务发现
- 提供流量管理功能(例如,A/B 测试、金丝雀发布等)以及弹性功能(超时、重试、熔断器等);
- 生成envoy配置
- 启动envoy
- 监控并管理envoy的运行状况,比如envoy出错时,
pilot-agent负责重启envoy,或者envoy配置变更后reload envoy
4.2、Envoy
# Envoy是什么?
Envoy是用 C++ 开发的高性能代理,用于协调服务网格中所有服务的入站和出站流量。
# Envoy有许多强大的功能,例如:
动态服务发现
负载均衡
TLS终端
HTTP/2与gRPC代理
断路器
健康检查
流量拆分
灰度发布
故障注入
# Istio中Envoy与服务什么关系?
为了便于理解Istio中Envoy与服务的关系,下图为Envoy的拓扑图,如图所示:

Envoy和Service A同属于一个Pod,共享网络和命名空间,Envoy代理进出Pod A的流量,并将流量按照外部请求的规则作用于Service A中。
# Pilot-agent是什么?
Envoy不直接跟k8s交互,通过 pilot-agent管理的
Pilot-agent 进程根据 K8S APIserver 中的配置信息生成 Envoy 的配置文件,并负责启动 Envoy 进程。
Envoy由Pilot-agent进程启动,启动后,Envoy读取Pilot-agent为它生成的配置文件,然后根据该文件的配置获取到Pilot的地址,通过数据面从pilot拉取动态配置信息,包括路由(route),监听器(listener),服务集群(cluster)和服务端点(endpoint)。
4.3、Citadel
负责处理系统上不同服务之间的TLS通信。 Citadel充当证书颁发机构(CA),并生成证书以允许在数据平面中进行安全的mTLS通信。
Citadel是 Istio 的核心安全组件,提供了自动生 成、分发、轮换与撤销密钥和证书功能。Citadel 一直监听 Kube- apiserver,以 Secret的形式为每个服务都生成证书密钥,并在Pod创建时挂载到Pod上,代理容器使用这些文件来做服务身份认证,进而代 理两端服务实现双向TLS认证、通道加密、访问授权等安全功能。

如图 所示,frontend 服 务对 forecast 服务的访问用到了HTTP方式,通过配置即可对服务增加认证功能,双方的Envoy会建立双向认证的TLS通道,从而在服务间启用双向认证的HTTPS。
4.4、Galley
Galley是istio的配置验证、提取、处理和分发的组件。Galley是提供配置管理的服务。实现原理是通过k8s提供的ValidatingWebhook对配置进行验证。
Galley使Istio可以与Kubernetes之外的其他环境一起工作,因为它可以将不同的配置数据转换为Istio可以理解的通用格式。
4.5、Ingressgateway
Ingressgateway 就是入口处的 Gateway,从网格外访问网格内的服务就是通过这个 Gateway进行的。
istio-ingressgateway是一个 Loadbalancer类型的 Service,不同于其他服务组件只有一两个端 口,istio-ingressgateway 开放了一组端口,这些就是网格内服务的外部访问端口。
如下图所示,网格入口网关 istio-ingressgateway的负载和网格内的 Sidecar是同样的执行流程,也和网格内的其他 Sidecar一样从 Pilot处接收流量规则并执行。

4.6、Sidecar-injector
Sidecar-injector是负责自动注入的组件,只要开启了自动注入,在Pod创建时就会自动调用 istio-sidecar-injector向Pod中注入 Sidecar 容器。
在 Kubernetes环境下,根据自动注入配置,Kube-apiserver在拦截到 Pod创建的请求时,会调用自动注入服务 istio-sidecar-injector 生成 Sidecar 容器的描述并将其插入原 Pod的定义中,这样,在创建的 Pod 内除了包括业务容器,还包括 Sidecar容器,这个注入过程对用户透明。
4.7、其他组件
除了以“istio”为前缀的Istio自有组件,在集群中一般还安装 Jaeger-agent、Jaeger-collector、Jaeger-query、Kiali、Prometheus、Grafana、 Tracing、Zipkin等组件,这些组件提供了 Istio 的调用链、监控等功能,可以选择安装来完成完整的服务监控管理功能。
二、k8s1.23及以上版本安装istio新版微服务
1、部署1.13.1
## 准备安装Istio是要的压缩包
# 官网下载地址:
https://github.com/istio/istio/
# 官方访问相对较慢,我在课件提供了压缩包,大家最好用我的压缩包,这样做实验才不会出问题
# 把压缩包上传到k8s的控制节点master1。手动解压:
[root@master1 ~]# tar zxvf istio-1.13.1.tar.gz
# 切换到istio包所在目录下。tar zxvf istio-1.13.1.tar.gz解压的软件包包名是istio-1.13.1,则:
[root@master1 ~]# cd istio-1.13.1
# 安装目录包含如下内容:
2)samples/目录下,有示例应用程序
3)bin/目录下,包含istioctl的客户端文件。istioctl工具用于手动注入Envoy sidecar代理。
# 将istioctl客户端路径增加到path环境变量中,macOS 或 Linux 系统的增加方式如下:
[root@master1 ~]# export PATH=$PWD/bin:$PATH
# 把istioctl这个可执行文件拷贝到/usr/bin/目录
[root@master1 ~]# cd /root/istio-1.13.1/bin/
[root@master1 ~]# p -ar istioctl /usr/bin/
## 安装istio
# 下载镜像:安装istio需要的镜像默认从官网拉取,但是官网的镜像我们拉取会有问题,可以从课件下载镜像,然后上传到自己k8s集群的各个节点,通过docker load -i手动解压镜像:
[root@master1 ~]# docker load -i examples-bookinfo-details.tar.gz
[root@master1 ~]# docker load -i examples-bookinfo-reviews-v1.tar.gz
[root@master1 ~]# docker load -i examples-bookinfo-productpage.tar.gz
[root@master1 ~]# docker load -i examples-bookinfo-reviews-v2.tar.gz
[root@master1 ~]# docker load -i examples-bookinfo-ratings.tar.gz
[root@master1 ~]# docker load -i examples-bookinfo-reviews-v3.tar.gz
[root@master1 ~]# docker load -i pilot.tar.gz
[root@master1 ~]# docker load -i proxyv2.tar.gz
[root@master1 ~]# docker load -i httpbin.tar.gz
# 安装
#在k8s的控制节点master1操作
[root@master1 ~]# stioctl install --set profile=demo -y
Detected that your cluster does not support third party JWT authentication. Falling back to less secure first party JWT. See https://istio.io/docs/ops/best-practices/security/#configure-third-party-service-account-tokens for details.
- Applying manifest for component Base...
✔ Finished applying manifest for component Base.
- Applying manifest for component Pilot...
✔ Finished applying manifest for component Pilot.
Waiting for resources to become ready...
Waiting for resources to become ready...
- Applying manifest for component EgressGateways...
- Applying manifest for component IngressGateways...
- Applying manifest for component AddonComponents...
✔ Finished applying manifest for component EgressGateways.
✔ Finished applying manifest for component IngressGateways.
✔ Finished applying manifest for component AddonComponents.
✔ Installation complete
# 验证istio是否部署成功
[root@master1 ~]# kubectl get pods -n istio-system
istio-egressgateway-d84f95b69-5gtdc 1/1 Running 0 15h
istio-ingressgateway-75f6d79f48-fhxjj 1/1 Running 0 15h
istiod-c9f6864c4-nrm82 1/1 Running 0 15h
# 卸载istio集群,暂时不执行,记住这个命令即可
[root@master1 ~]# istioctl manifest generate --set profile=demo | kubectl delete -f -
2、部署1.21.1
# 部署新版本istio
[root@123-master test]# https_proxy=192.168.2.7:18080 wget https://github.com/istio/istio/releases/download/1.21.1/istio-1.21.1-linux-amd64.tar.gz
[root@123-master test]# tar zxvf istio-1.21.1-linux-amd64.tar.gz
[root@123-master test]# cd istio-1.21.1
[root@123-master istio-1.21.1]# cd bin/
[root@123-master bin]# ./istioctl install --set profile=demo -y
# 为default名称空间开启注入
[root@123-master istio-1.21.1]# kubectl label ns default istio-injection=enabled
namespace/default labeled
3、使用配置文件安装istio
# 官方建议再生产环境中使用该方式进行安装
cat <<EOF > ./my-config.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
accessLogFile: /dev/stdout
EOF
istioctl install -f my-config.yaml
三、通过Istio最新版部署在线书店bookinfo
1、bookinfo介绍
# 在线书店-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服务具有多个版本。
要在Istio中运行这一应用,无需对应用自身做出任何改变。 只要简单的在 Istio 环境中对服务进行配置和运行,具体一点说就是把 Envoy sidecar 注入到每个服务之中。 最终的部署结果将如下图所示:

所有的微服务都和Envoy sidecar集成在一起,被集成服务所有的出入流量都被envoy sidecar 所劫持,这样就为外部控制准备了所需的 Hook,然后就可以利用Istio控制平面为应用提供服务路由、遥测数据收集以及策略实施等功能。
2、启动服务
- 部署
# 进入istio安装目录。
# istio默认自动注入 sidecar,需要为default命名空间打上标签istio-injection=enabled
[root@master1 ~]# kubectl label namespace default istio-injection=enabled
# 使用kubectl部署应用
[root@master1 ~]# cd istio-1.13.1
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
上面的命令会启动全部的四个服务,其中也包括了 reviews 服务的三个版本(v1、v2 以及 v3)。
# 确认所有的服务和 Pod 都已经正确的定义和启动:
[root@123-master kube]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.10.94.224 <none> 9080/TCP 3m13s
kubernetes ClusterIP 10.10.0.1 <none> 443/TCP 8d
productpage ClusterIP 10.10.40.182 <none> 9080/TCP 3m9s
ratings ClusterIP 10.10.220.128 <none> 9080/TCP 3m13s
reviews ClusterIP 10.10.204.86 <none> 9080/TCP 3m11s
[root@123-master kube]# kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-6b6bb86565-zptkr 2/2 Running 0 101s
productpage-v1-778dd755c8-wxsdr 2/2 Running 0 95s
ratings-v1-6f5f59749c-ksgn8 2/2 Running 0 100s
reviews-v1-85b7d88f6c-mhqd5 2/2 Running 0 98s
reviews-v2-6bd67f7c65-lfrn7 2/2 Running 0 98s
reviews-v3-6cf7bd98dc-qcdgk 2/2 Running 0 98s
# 确认 Bookinfo 应用是否正在运行,在某个Pod中用curl命令对应用发送请求,例如ratings:
[root@123-master kube]# 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>"

- 确认访问端口并自行访问
# 确定 Ingress 的 IP 和端口
现在Bookinfo服务已经启动并运行,你需要使应用程序可以从Kubernetes集群外部访问,例如从浏览器访问,那可以用Istio Gateway来实现这个目标。
# 为应用程序定义gateway网关:
[root@master1 ~]# kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
# 确认网关创建完成:
[root@master1 ~]# kubectl get gateway
NAME AGE
bookinfo-gateway 2m18s
# 确定ingress ip和端口,执行如下指令,明确自身 Kubernetes 集群环境支持外部负载均衡:
[root@master1 ~]# kubectl get svc istio-ingressgateway -n istio-system
# 获取http端口
[root@master1 ~]# kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'
# 获取https端口
[root@master1 ~]# kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}'
# 访问:http://ip:port/productpage
- 课程方式访问
# 如果EXTERNAL-IP值已设置,说明环境正在使用外部负载均衡,可以用其为ingress gateway 提供服务。 如果EXTERNAL-IP值为<none>(或持续显示<pending>), 说明环境没有提供外部负载均衡,无法使用ingress gateway。在这种情况下,你可以使用服务的NodePort访问网关。
# 若自身环境未使用外部负载均衡器,需要通过 node port 访问。可以通过以下命令获取Istio Gateway的地址:
[root@master1 ~]# export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
[root@master1 ~]# export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
# 设置GATEWAY_URL
[root@master1 ~]# INGRESS_HOST=192.168.2.25
# 192.168.2.25是安装istio的机器,即k8s控制节点master1的ip
[root@master1 ~]# export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
[root@master1 ~]# echo $GATEWAY_URL
192.168.2.25:30871
# 确认可以从集群外部访问应用,可以用curl命令来确认是否能够从集群外部访问 Bookinfo 应用程序:
curl -s http://${GATEWAY_URL}/productpage | grep -o "<title>.*</title>"
# 显示如下:

还可以用浏览器打开网址 http://$GATEWAY_URL/productpage,也就是 192.168.2.25:30871/productpage来浏览应用的 Web 页面。如果刷新几次应用的页面,就会看到 productpage 页面中会随机展示 reviews 服务的不同版本的效果(红色、黑色的星形或者没有显示)。

通过istio的ingressgateway访问,官网:
https://istio.io/docs/examples/bookinfo/#determine-the-ingress-ip-and-port
四、通过Istio实现灰度发布
1、什么是灰度发布
灰度发布也叫金丝雀部署 ,是指通过控制流量的比例,实现新老版本的逐步更替。
比如对于服务A 有 version1、 version2 两个版本 , 当前两个版本同时部署,但是version1比例90% ,version2比例10% ,看运行效果,如果效果好逐步调整流量占比 80~20 ,70~30 ·····10~90 ,0,100 ,最终version1版本下线。
灰度发布的特点:
- 新老版本共存
- 可以实时根据反馈动态调整占比
- 理论上不存在服务完全宕机的情况。
- 适合于服务的平滑升级与动态更新。
2、使用Istio实现灰度发布
# 把canary-v2.tar.gz和canary-v1.tar.gz上传到k8s工作节点,手动解压:
[root@master1 huidu]# docker load -i canary-v2.tar.gz
[root@master1 huidu]# docker load -i canary-v1.tar.gz
# 创建金丝雀服务
[root@master1 huidu]# vim 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: 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: canary:v2
ports:
- containerPort: 80
# 更新:
[root@master1 huidu]# kubectl apply -f deployment.yaml
# 创建service
[root@master1 huidu]# vim 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文件
kubectl apply -f service.yaml
# 创建gateway
[root@master1 huidu]# vim 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
[root@master1 huidu]# kubectl apply -f gateway.yaml
gateway.networking.istio.io/canary-gateway created
# 创建virtualservice
[root@master1 huidu]# vim virtualService.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: 95
- destination:
host: canary.default.svc.cluster.local
subset: v2
weight: 5
---
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文件
[root@master1 huidu]# kubectl apply -f virtualService.yaml
virtualservice.networking.istio.io/canary created
destinationrule.networking.istio.io/canary created
# 获取Ingress_port:
[root@master1 huidu]# kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'
31263
# 验证金丝雀发布效果:
[root@master1 huidu]# for i in `seq 1 100`; do curl 192.168.2.20:31263 ; done > 1.txt
[root@master1 huidu]# grep 1 1.txt | wc -l
95
[root@master1 huidu]# grep 2 1.txt | wc -l
5
# 打开1.txt可以看到结果有95次出现v1,5次出现canary-v2,符合我们预先设计的流量走向。
五、Istio核心资源解读
官网:
1、Gateway
在Kubernetes环境中,Ingress controller用于管理进入集群的流量。
在Istio服务网格中 Istio Ingress Gateway 承担相应的角色,它使用新的配置模型(Gateway 和 VirtualServices)完成流量管理的功能。通过下图做一个总的描述。

1、用户向某端口发出请求
2、负载均衡器监听端口,并将请求转发到集群中的某个节点上。Istio Ingress Gateway Service 会监听集群节点端口的请求
3、Istio Ingress Gateway Service 将请求交给 Istio Ingress Gateway Pod 处理。
IngressGateway Pod 通过 Gateway 和 VirtualService 配置规则处理请求。其中,Gateway 用来配置端口、协议和证书;VirtualService 用来配置一些路由信息(找到请求对应处理的服务App Service)
4、Istio Ingress Gateway Pod将请求转给App Service
5、最终的请求会交给App Service 关联的App Deployment处理
[root@master1 ~]# 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:
- "*"
# 网关是一个运行在网格边缘的负载均衡器,用于接收传入或传出的HTTP/TCP连接。主要工作是接受外部请求,把请求转发到内部服务。网格边缘的Ingress 流量,会通过对应的 Istio IngressGateway Controller 进入到集群内部。
# 在上面这个yaml里我们配置了一个监听80端口的入口网关,它会将80端口的http流量导入到集群内对应的Virtual Service上。
# 注意:*表示通配符,通过任何域名都可以访问
hosts:
- "*"
2、VirtualService
VirtualService 是 Istio 流量治理的一个核心配置,可以说是 Istio 流量治理中最重要、最复杂的。
VirtualService 在形式上表示一个虚拟服务,将满足条件的流量都转发到对应的服务后端,这个服务后端可以是一个服务,也可以是在 DestinationRule 中定义的服务的子集。
2.1、VirtualService说明
[root@master1 ~]# 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
# 这个虚拟服务会收到上一个gateway中所有80端口来的http流量。
如在虚拟机配置hosts文件
192.168.2.25 hello.com.cn
这样就可以在虚拟机通过域名hello.com.cn访问istio内部的服务了
hosts说明:
- hosts:虚拟主机名称,如果在 Kubernetes 集群中,则这个主机名可以是service服务名。
- hosts字段列出了virtual service的虚拟主机。它是客户端向服务发送请求时使用的一个或多个地址,通过该字段提供的地址访问virtual service,进而访问后端服务。在集群内部(网格内)使用时通常与kubernetes的Service同名;当需要在集群外部(网格外)访问时,该字段为gateway请求的地址,即与gateway的hosts字段相同。
- virtual service的主机名可以是IP地址、DNS名称,也可以是短名称(例如Kubernetes服务短名称),该名称会被隐式或显式解析为全限定域名(FQDN),具体取决于istio依赖的平台。
- 可以使用前缀通配符(“*”)为所有匹配的服务创建一组路由规则。
- virtual service的hosts不一定是Istio服务注册表的一部分,它们只是虚拟目的地,允许用户为网格无法路由到的虚拟主机建立流量模型。
- virtual service的hosts短域名在解析为完整的域名时,补齐的namespace是VirtualService所在的命名空间,而非Service所在的命名空间。如上例的hosts会被解析为:reviews.default.svc.cluster.local。
2.2、Virtualservice配置路由规则:
路由规则的功能是:
- 满足http.match条件的流量都被路由到http.route.destination,执行重定向(HTTPRedirect)、重写(HTTPRewrite)、重试(HTTPRetry)、故障注入(HTTPFaultInjection)、跨站(CorsPolicy)策略等。
- HTTPRoute不仅可以做路由匹配,还可以做一些写操作来修改请求本身。
# 如下:
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指定的v2子集。
2.3、路由规则优先级
在上面例子中,不满足第一个路由规则的流量均流向一个默认的目标,该目标在第二条规则中指定。因此,第二条规则没有 match 条件,直接将流量导向 v3 子集。
2.4、多路由规则解读
详细配置可参考: https://istio.io/latest/zh/docs/reference/config/networking/virtual-service/#HTTPMatchRequest
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 把请求路由到特定的目标地址。
2、Gateway:流量来源网关。
3、路由:
路由的 destination 字段指定了匹配条件的流量的实际地址。
与 virtual service 的主机不同,该host必须是存在于 istio 的服务注册表(如 kubernetes services,consul services 等)中的真实目的地或由 ServiceEntries 声明的hosts,否则 Envoy 不知道应该将流量发送到哪里。
它可以是一个带代理的网格服务或使用service entry添加的非网格服务。
在kubernetes作为平台的情况下,host表示名为 kubernetes 的 service 名称:
- destination:
host: canary.default.svc.cluster.local
subset: v1
weight: 90
3、DestinationRule
destination rule是 istio流量路由功能的重要组成部分。
一个 virtual service可以看作是如何将流量分发给特定的目的地,然后调用 destination rule来配置分发到该目的地的流量。
destination rule在 virtual service的路由规则之后起作用(即在 virtual service的 math->route-destination之后起作用,此时流量已经分发到真实的service上),应用于真实的目的地。
可以使用 destination rule 来指定命名的服务子集,例如根据版本对服务的实例进行分组,然后通过 virtual service 的路由规则中的服务子集将控制流量分发到不同服务的实例中。
[root@node1 ~]# cat DestinationRule.yaml
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进入的路由地址,可以看到,上面导入到了目标规则为v1和v2的子集。
# v1子集对应的是具有如下标签的pod:
selector:
matchLabels:
app: v1
# 流量控制流程:
Gateway -> VirtaulService -> TCP/HTTP Router -> DestinationWeight -> Subset:Port
六、Istio核心功能
1、熔断
官网: https://istio.io/latest/zh/docs/tasks/traffic-management/circuit-breaking/
断路器是创建弹性微服务应用程序的重要模式。断路器使应用程序可以适应网络故障和延迟等网络不良影响。
测试断路器:
- 在k8s集群创建后端服务
[root@master1 ~]# cd istio-1.10.1
[root@master1 istio-1.10.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上传到node1节点,手动解压:
[root@node1 ~]# docker load -i httpbin.tar.gz
[root@master1 istio-1.10.1]# kubectl apply -f samples/httpbin/httpbin.yaml
# 该httpbin应用程序充当后端服务。
- 配置断路器
#创建一个目标规则,在调用httpbin服务时应用断路器设置:
[root@master1 istio-1.10.1]# vim destination.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%
[root@master1 istio-1.10.1]# 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
[root@master1 istio-1.10.1]# kubectl apply -f destination.yaml
destinationrule.networking.istio.io/httpbin created
- 添加客户端访问httpbin服务
# 创建一个客户端以将流量发送给httpbin服务。该客户端是一个简单的负载测试客户端,Fortio可以控制连接数,并发数和HTTP调用延迟。使用此客户端来“跳闸”在 DestinationRule 中设置的断路器策略。
#通过执行下面的命令部署fortio客户端:
#把fortio.tar.gz上传到node1节点,手动解压:
[root@node1 ~]# docker load -i fortio.tar.gz
[root@master1 istio-1.10.1]# kubectl apply -f samples/httpbin/sample-client/fortio-deploy.yaml
#通过kubectl执行下面的命令,使用fortio客户端工具调用httpbin:
[root@master1 httpbin]# kubectl get pods
NAME READY STATUS RESTARTS AGE
fortio-deploy-7dcd84c469-s6t6l 2/2 Running 0 3m38s
httpbin-85d76b4bb6-h2dnp 2/2 Running 0 20m
[root@master1 httpbin]# kubectl exec fortio-deploy-7dcd84c469-s6t6l -c fortio -- /usr/bin/fortio curl http://httpbin:8000/get
HTTP/1.1 200 OK
server: envoy
date: Mon, 09 Oct 2023 10:21:13 GMT
content-type: application/json
content-length: 594
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 76
{
"args": {},
"headers": {
"Host": "httpbin:8000",
"User-Agent": "fortio.org/fortio-1.17.1",
"X-B3-Parentspanid": "d32778d46a1fee1f",
"X-B3-Sampled": "1",
"X-B3-Spanid": "a04f32012cf477ab",
"X-B3-Traceid": "a4b789be3d13728bd32778d46a1fee1f",
"X-Envoy-Attempt-Count": "1",
"X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=f079f3926a3cb6606921444a92da606c4685900d99e6ef189a22e5d145adb32a;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default"
},
"origin": "127.0.0.6",
"url": "http://httpbin:8000/get"
}
- 触发断路器
# 在DestinationRule设置中,指定了maxConnections: 1和 http1MaxPendingRequests: 1。这些规则表明,如果超过一个以上的连接并发请求,则istio-proxy在为进一步的请求和连接打开路由时,应该会看到下面的情况 。
# 以两个并发连接(-c 2)和发送20个请求(-n 20)调用服务:
[root@master1 istio-1.10.1]# kubectl exec -it fortio-deploy-576dbdfbc4-z28m7 -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
#显示如下:
02:31:00 I logger.go:127> Log level is now 3 Warning (was 2 Info)
Fortio 1.11.3 running at 0 queries per second, 6->6 procs, for 20 calls: http://httpbin:8000/get
Starting at max qps with 2 thread(s) [gomax 6] for exactly 20 calls (10 per thread + 0)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
02:31:00 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
Ended after 69.506935ms : 20 calls. qps=287.74
Aggregated Function Time : count 20 avg 0.0054352091 +/- 0.01077 min 0.000474314 max 0.04968864 sum 0.108704183
# range, mid point, percentile, count
>= 0.000474314 <= 0.001 , 0.000737157 , 35.00, 7
> 0.001 <= 0.002 , 0.0015 , 50.00, 3
> 0.002 <= 0.003 , 0.0025 , 65.00, 3
> 0.004 <= 0.005 , 0.0045 , 75.00, 2
> 0.005 <= 0.006 , 0.0055 , 85.00, 2
> 0.007 <= 0.008 , 0.0075 , 90.00, 1
> 0.016 <= 0.018 , 0.017 , 95.00, 1
> 0.045 <= 0.0496886 , 0.0473443 , 100.00, 1
# target 50% 0.002
# target 75% 0.005
# target 90% 0.008
# target 99% 0.0487509
# target 99.9% 0.0495949
Sockets used: 16 (for perfect keepalive, would be 2)
Jitter: false
Code 200 : 4 (20.0 %)
Code 503 : 16 (80.0 %)
#只有20%成功了,其余的都断开了
Response Header Sizes : count 20 avg 46 +/- 92 min 0 max 230 sum 920
Response Body/Total Sizes : count 20 avg 292.8 +/- 279.6 min 153 max 852 sum 5856
All done 20 calls (plus 0 warmup) 5.435 ms avg, 287.7 qps
[root@master1 httpbin]# kubectl exec fortio-deploy-7dcd84c469-s6t6l -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
10:22:35 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)
10:22:35 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
10:22:35 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
Ended after 97.884025ms : 20 calls. qps=204.32
Aggregated Function Time : count 20 avg 0.0095852017 +/- 0.009237 min 0.000674836 max 0.040231039 sum 0.191704034
# range, mid point, percentile, count
>= 0.000674836 <= 0.001 , 0.000837418 , 5.00, 1
> 0.004 <= 0.005 , 0.0045 , 40.00, 7
> 0.005 <= 0.006 , 0.0055 , 50.00, 2
> 0.006 <= 0.007 , 0.0065 , 70.00, 4
> 0.007 <= 0.008 , 0.0075 , 75.00, 1
> 0.009 <= 0.01 , 0.0095 , 80.00, 1
> 0.018 <= 0.02 , 0.019 , 85.00, 1
> 0.02 <= 0.025 , 0.0225 , 90.00, 1
> 0.025 <= 0.03 , 0.0275 , 95.00, 1
> 0.04 <= 0.040231 , 0.0401155 , 100.00, 1
# target 50% 0.006
# target 75% 0.008
# target 90% 0.025
# target 99% 0.0401848
# target 99.9% 0.0402264
Sockets used: 4 (for perfect keepalive, would be 2)
Jitter: false
Code 200 : 18 (90.0 %)
Code 503 : 2 (10.0 %)
Response Header Sizes : count 20 avg 207.1 +/- 69.03 min 0 max 231 sum 4142
Response Body/Total Sizes : count 20 avg 765.8 +/- 174.9 min 241 max 825 sum 15316
All done 20 calls (plus 0 warmup) 9.585 ms avg, 204.3 qps
[root@master1 httpbin]# kubectl exec fortio-deploy-7dcd84c469-s6t6l -c fortio -- /usr/bin/fortio load -c 3 -qps 0 -n 30 -loglevel Warning http://httpbin:8000/get
10:24:09 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 30 calls: http://httpbin:8000/get
Starting at max qps with 3 thread(s) [gomax 4] for exactly 30 calls (10 per thread + 0)
10:24:09 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [2] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [2] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [2] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [2] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [2] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [2] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [2] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [2] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [2] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [1] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
10:24:09 W http_client.go:806> [0] Non ok http code 503 (HTTP/1.1 503)
Ended after 106.844043ms : 30 calls. qps=280.78
Aggregated Function Time : count 30 avg 0.010462978 +/- 0.01859 min 0.000745308 max 0.090351021 sum 0.313889341
# range, mid point, percentile, count
>= 0.000745308 <= 0.001 , 0.000872654 , 6.67, 2
> 0.001 <= 0.002 , 0.0015 , 46.67, 12
> 0.002 <= 0.003 , 0.0025 , 70.00, 7
> 0.004 <= 0.005 , 0.0045 , 73.33, 1
> 0.006 <= 0.007 , 0.0065 , 76.67, 1
> 0.02 <= 0.025 , 0.0225 , 86.67, 3
> 0.025 <= 0.03 , 0.0275 , 90.00, 1
> 0.035 <= 0.04 , 0.0375 , 96.67, 2
> 0.09 <= 0.090351 , 0.0901755 , 100.00, 1
# target 50% 0.00214286
# target 75% 0.0065
# target 90% 0.03
# target 99% 0.0902457
# target 99.9% 0.0903405
Sockets used: 28 (for perfect keepalive, would be 3)
Jitter: false
Code 200 : 2 (6.7 %)
Code 503 : 28 (93.3 %)
Response Header Sizes : count 30 avg 15.4 +/- 57.62 min 0 max 231 sum 462
Response Body/Total Sizes : count 30 avg 200.73333 +/- 167.6 min 153 max 825 sum 6022
All done 30 calls (plus 0 warmup) 10.463 ms avg, 280.8 qps
2、超时
在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性,Istio 使用虚拟服务来优雅实现超时处理。
下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat。nginx 服务设置了超时时间为2秒,如果超出这个时间就不在等待,返回超时错误。tomcat服务设置了响应时间延迟10秒,任何请求都需要等待10秒后才能返回。client 通过访问 nginx 服务去反向代理 tomcat服务,由于 tomcat服务需要10秒后才能返回,但nginx 服务只等待2秒,所以客户端会提示超时错误。
# 把busybox.tar.gz、 nginx.tar.gz、 tomcat-app.tar.gz上传到node1节点,手动解压:
[root@node1 ~]# docker load -i nginx.tar.gz
[root@node1 ~]# docker load -i busybox.tar.gz
[root@node1 ~]# docker load -i tomcat-app.tar.gz
[root@master1 ~]# mkdir /root/timeout
[root@master1 ~]# cd /root/timeout/
[root@master1 timeout]# cat nginx-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
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:1.14-alpine
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
[root@master1 timeout]# 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
[root@master1 timeout]# 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资源清单重点知识讲解
第一:故障注入:
http:
- fault:
delay:
percentage:
value: 100
fixedDelay: 10s
该设置说明每次调用 tomcat-svc 的 k8s service,都会延迟10s才会调用。
第二:调用超时:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
timeout: 2s
该设置说明调用 nginx-svc 的 k8s service,请求超时时间是 2s。
#部署tomcat、nginx服务
需要对nginx-deployment.yaml资源文件进行 Istio 注入,将 nginx、tomcat 都放入到网格中。可以采用手工注入 Istio 方式。
[root@master1 timeout]# kubectl apply -f nginx-deployment.yaml
执行成功后,通过 kubectl get pods 查看 Istio 注入情况:
[root@master1 timeout]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-tomcat-7dd6f74846-48g9f 2/2 Running 0 6m36s
tomcat-86ddb8f5c9-h6jdl 2/2 Running 0 53s
#部署nginx和tomcat的service
[root@master1 timeout]# kubectl apply -f nginx-tomcat-svc.yaml
#部署虚拟服务
[root@master1 timeout]# kubectl apply -f virtual-tomcat.yaml
#设置超时时间
[root@master1 timeout]# kubectl exec -it nginx-tomcat-7dd6f74846-48g9f -- sh
# apt-get update
# apt-get install vim -y
/ # vim /etc/nginx/conf.d/default.conf

proxy_pass http://tomcat-svc:8080;
proxy_http_version 1.1;
编辑完后,再执行如下语句验证配置和让配置生效:
/ # nginx -t
/ # nginx -s reload
这样,整个样例配置和部署都完成了。
#验证超时
登录client,执行如下语句:
[root@master1 timeout]# 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.06s
user 0m 0.00s
sys 0m 0.00s
/ # 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
^C
# 每隔2秒,由于 nginx 服务的超时时间到了而 tomcat未有响应,则提示返回超时错误。
# 验证故障注入效果,执行如下语句:
/ # time wget -q -O - http://tomcat-svc:8080
<!DOCTYPE html>
real 0m 10.02s
user 0m 0.00s
sys 0m 0.00s
# 执行之后10s才会有结果
3、重试及故障注入
Istio 重试机制就是如果调用服务失败,Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务,除非我们启动 Istio 重试机制。
下面例子模拟客户端调用 nginx,nginx 将请求转发给 tomcat。tomcat 通过故障注入而中止对外服务,nginx 设置如果访问 tomcat 失败则会重试 3 次。
[root@master1 attemp]# cd /root/timeout/
[root@master1 timeout]# kubectl delete -f .
[root@master1 timeout]# kubectl apply -f nginx-deployment.yaml
[root@master1 timeout]# kubectl apply -f nginx-tomcat-svc.yaml
[root@master1 ~]# 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
[root@master1 timeout]# cat 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
[root@master1 timeout]# kubectl apply -f virtual-attempt.yaml
# 虚拟服务资源清单解读:
# 第一:故障注入。该虚拟服务的作用对象就是 tomcat-svc。使用此故障注入后,在网格中该 tomcat 就是不可用的。
abort:
percentage:
value: 100
httpStatus: 503
# abort是模拟tomcat服务始终不可用,该设置说明每次调用 tomcat-svc 的 k8s service,100%都会返回错误状态码503。
# 第二:调用超时:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
reties:
attempts: 3
perTryTimeout: 2s
# 该设置说明调用 nginx-svc 的 k8s service,在初始调用失败后最多重试 3 次来连接到服务子集,每个重试都有 2 秒的超时。
[root@master1 timeout]# kubectl exec -it nginx-tomcat-7dd6f74846-rdqqf -- /bin/sh
# apt-get update
# apt-get install vim -y
/ # vi /etc/nginx/conf.d/default.conf

proxy_pass http://tomcat-svc:8080;
proxy_http_version 1.1;
/ # nginx -t
/ # nginx -s reload
#验证重试是否生效
[root@master1 retry]# kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh
If you don't see a command prompt, try pressing enter.
/ # wget -q -O - http://nginx-svc
wget: server returned error: HTTP/1.1 503 Service Unavailable
/ # wget -q -O - http://nginx-svc
wget: server returned error: HTTP/1.1 503 Service Unavailable
[root@master1 ~]# kubectl logs -f nginx-7649c6ff85-5bl2h
127.0.0.6 - - [09/Oct/2023:13:16:50 +0000] "GET / HTTP/1.1" 503 18 "-" "Wget" "-"
127.0.0.6 - - [09/Oct/2023:13:16:50 +0000] "GET / HTTP/1.1" 503 18 "-" "Wget" "-"
127.0.0.6 - - [09/Oct/2023:13:16:50 +0000] "GET / HTTP/1.1" 503 18 "-" "Wget" "-"
127.0.0.6 - - [09/Oct/2023:13:16:50 +0000] "GET / HTTP/1.1" 503 18 "-" "Wget" "-"
127.0.0.6 - - [09/Oct/2023:13:17:00 +0000] "GET / HTTP/1.1" 503 18 "-" "Wget" "-"
127.0.0.6 - - [09/Oct/2023:13:17:00 +0000] "GET / HTTP/1.1" 503 18 "-" "Wget" "-"
127.0.0.6 - - [09/Oct/2023:13:17:00 +0000] "GET / HTTP/1.1" 503 18 "-" "Wget" "-"
127.0.0.6 - - [09/Oct/2023:13:17:00 +0000] "GET / HTTP/1.1" 503 18 "-" "Wget" "-"
# 由上可知,重试设置生效。
七、分布式追踪系统-jaeger
1、什么是分布式追踪?
分布式追踪最早由谷歌的Dapper普及开来,它本质上是具有在微服务的整个生命周期中追踪请求的能力。分布式追踪(Distributed Tracing)主要用于记录整个请求链的信息。
2、为什么要分布式追踪?
当业务微服务化后,一次业务请求,可能会涉及到多个微服务,分布式跟踪可以对跨多个分布式服务网格的1个请求进行追踪分析,并通过可视化的方式深入地了解请求的延迟,序列化和并发,充分地了解服务流量实况,从而快速地排查和定位问题。在微服务应用中,一个完整的业务往往需要调用多个服务才能完成,服务之间就产生了交互。当出现故障时,如何找到问题的根源非常重要。追踪系统可以清晰地展示出请求的整个调用链以及每一步的耗时,方便查找问题所在。
3、分布式追踪系统-jaeger
Jaeger是一个开源的分布式追踪系统,它可以在复杂的分布式系统中进行监控和故障排查。Jaeger的主要功能包括分布式请求监控、性能调优、故障分析和服务依赖分析等。
- Jaeger组件介绍:
# jaeger-agent:
负责发送的进程,对spans进行处理并发送给collector,监听spans的UDP 发送。这层作为基础组件部署在主机上,Agent将Client Library和Collector解耦,为ClientLibrary屏蔽了路由和发现Collector的细节。
# jaeger-collector:
收集追踪 spans,并通过管道对追踪数据进行处理。当前的管道支持追踪的验证、索引、转换,最后存储数据
# jaeger-query:
从存储中检索追踪信息并通过 UI 展示
# data store:
追踪信息的存储
4、使用
[root@master1 timeout]# kubectl get svc -n istio-system | grep jaeger
jaeger-agent ClusterIP None <none> 5775/UDP,6831/UDP,6832/UDP 55d
jaeger-collector ClusterIP 10.99.194.57 <none> 14267/TCP,14268/TCP,14250/TCP 55d
jaeger-collector-headless ClusterIP None <none> 14250/TCP 55d
jaeger-query ClusterIP 10.107.192.115 <none> 16686/TCP
修改jaeger-query的type类型为nodePort
kubectl edit svc jaeger-query -n istio-system
把type: ClusterIP变成type: NodePort
[root@master1 timeout]# kubectl get svc -n istio-system | grep jaeger-query
jaeger-query NodePort 10.107.192.115 <none> 16686:31450/TCP
# 在浏览器访问:
192.168.40.180:31450
5、查看追踪数据
在Jaeger左侧版面的Service下拉列表中选择v1.default,单击Find Traces按钮,会看到如下图所示:


单击右侧的URL进入详细页,可以看到具体的服务调用情况,并且能够了解每个服务的耗时。

6、追踪上下文传递
Istio 利用 Envoy 的分布式追踪 功能提供了开箱即用的追踪集成。确切地说,Istio 提供了安装各种追踪后端服务的选项,并且通过配置代理来自动发送追踪 span 到追踪后端服务。尽管 Istio 代理能够自动发送 span,但是他们需要一些附加线索才能将整个追踪链路关联到一起。所以当代理发送 span 信息的时候,应用需要附加适当的 HTTP 请求头信息,这样才能够把多个 span 正确的关联到同一个追踪上。
要做到这一点,应用程序从传入请求到任何传出的请求中需要包含以下请求头参数:
x-request-id
x-b3-traceid
x-b3-spanid
x-b3-parentspanid
x-b3-sampled
x-b3-flags
x-ot-span-context
八、分布式追踪系统-kiali
1、简介
Kiali是Istio服务网格的可视化工具,它主要的功能是用可视化的界面来观察微服务系统以及服务之间的关系。Kiali功能如下。
1)服务拓扑图:这是Kiali最主要的功能,提供了一个总的服务视图,可以实时地显示命名空间下服务之间的调用和层级关系,以及负载情况。·
2)服务列表视图:展示了系统中所有的服务,以及它们的健康状况和出错率。· 工作负载视图:展示服务的负载情况。
3)Istio配置视图:展示了所有的Istio配置对象。
Kiali的架构比较简单,如下图,它分为前端和后端两部分。后端以容器的方式运行在应用平台,负责获取和处理数据,并发送给前端;前端是一个典型的Web应用,由React和TypeScript实现,负责展示后端发送过来的数据。对Kiali来说Istio是必须存在的系统,它类似于Kiali的宿主。虽然它们可以分开部署,但没有了Istio,Kiali是不能工作的。

2、使用
[root@master1 ~]#kubectl get svc -n istio-system | grep kiali
kiali ClusterIP 10.106.61.5 <none> 20001/TCP
# 修改kiali的type类型为nodePort
[root@master1 ~]#kubectl edit svc kiali -n istio-system
#把type: ClusterIP变成type: NodePort
[root@master1 ~]#kubectl get svc -n istio-system | grep kiali
kiali NodePort 10.106.61.5 <none> 20001:32514/TCP
# 在浏览器访问192.168.40.180:32514

Username:admin
Password: admin
输入用户名和密码之后出现如下界面:

Kiali是一个非常强大的可视化工具,可以让用户清晰和直观地了解到Istio服务网格中的服务以及服务之间的关系。除了服务拓扑图外,它还提供了健康检查、指标数据显示和配置验证等功能。强烈推荐把Kiali作为必选项添加到服务网格中,来帮助监控和观测网格中服务的工作情况。
评论区