istio ServiceMesh

什么是ServiceMesh?什么是Istio?

微服务的一种概念,随着微服务的来临,衍生出一系列的问题,比如服务发现、负载均衡、路由、流量控制、服务间通讯的可靠性、微服务的监控等一系列的问题。使用api网关解决了以上的一部分问题,apiserver存在单点问题,实现起来随着后端服务的增多也会越来越臃肿。

Zuul和GateWay区别

Zuul的作用
过滤请求、对过滤器进行动态的加载、编译、运行
验证与安全:识别面向各类资源的验证要求并拒绝那些与要求不符的请求。
审查与监控:在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。动态路由:以动态方式根据需要将请求路由至不同后端集群处。
压力测试:逐渐增加指向集群的负载流量,从而计算性能水平。
负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。静态响应处理:在边缘位置直接建立部分响应,从而避免其流入内部集群。
其核心是一系列的filters,定义了四套标准
PRE:路由之前调用,实现身份验证
ROUTING:将请求路由到微服务
POST,微服务以后执行,响应header
ERROR,错误时执行
Filter有四个方法,分别为
filterType():过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。
fiterOrder:过滤器的执行顺序。当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行。通过数字指定,数字越大,优先级越低。
shouldFiter:判断该过滤器是否需要被执行。直接返回true,则该过滤器对所有请求都会生效。实际运用中我们可以利用该函数来指定过滤器的有效范围。 r
un():过滤器的具体逻辑。
gateway使用了高性能框架Netty,由三部分组成
1、filter过滤器:拦截和修改请求
2、route路由:断言为真,则路由匹配,目标URI会被访问
3、predicate断言:匹配HTTP请求的任何内容

zuul与spring-cloud-gateway的区别
不同点:
gateway吞吐率比zuul高,耗时比zuul少,性能比zuul高倍左右,
gateway对比zuul多依赖了spring-webflux,
zuul仅支持同步,gateway支持异步。
gateway具有更好的扩展性
相同点:
1、底层都是servlet
2、两者均是web网关,处理的是http请求

Servlet 简介

Servlet 是什么?

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

Java Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同工的效果。但是相比于 CGI,Servlet 有以下几点优势:

  • 性能明显更好。
  • Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
  • Servlet 是独立于平台的,因为它们是用 Java 编写的。
  • 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
  • Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。

ServiceMesh两种代表作:

  • 1.linkerd
  • 2.istio

 

 

 

 官方地址istio.io/zh

istio作用

1.连接:只能控制服务之间的流量和api调用,进行一系列的测试,并通过红/黑部署逐渐升级。

2.保护:通过托管身份验证、授权和服务之间的通信加密自动保护服务。

3.控制:应用策略并确保其执行,使用资源在消费者之间公平分配。

4.观测:对一切服务进行多样化、自动化的追踪、监控以及记录日志,以便实时了解正在发生的事件。

 

 istio的架构和原理

 

 每个pod都存在一个istio代理,所有进出流量都要经过网络代理,代理被istio控制中心进行管理。利用pod中共享网络的机制接管每个pod的网络。

istio架构图:

 

通过数据平面和控制平面组成

数据平面由一系列代理组成,这些代理控制微服务的所有网络通讯以及各种策略。在proxy之间支持很多常见的协议,http1.1、http2、crpc,tcp。

控制平面由多个模块组成,管理流量模块、管理路由策略模块、收集监测数据模块、校验配置模块、通信安全模块。

 

istio采用sidecar模式,每个pod中运行一个单独容器进行网络代理,数据存储,监测采集,管理路由等。

istio proxy默认选择的proxy代理组件是开源的envoy,envoy是一个用c++开发的高效代理组件,用于管理所有的服务入口流量及出口流量。envoy内置了很多功能,动态服务发现、负载均衡、多种协议支持,断路器、流量分割、健康检查、模拟故障监控指标。

pilot模块:pilot对envoy进行控制管理,下发各种策略,给sidecar模式运行的envoy提供信息。用户通过pilot配置来调整下发envoy策略。

Galley:校验各种配置是否正确,配置管理主要目的是将所有istio组件与底层平台如kubernetes配置细节隔离开来。

Citadel:为用户到服务,服务到服务之间提供安全通信,把http无感知的升级为https。服务的访问授权,包括基于RBAC的访问控制。

istio解决的问题:

 

 

 

 

 

 部署istio

## 安装istioctl

#### 1. 下载istioctl

`istioctl需要下载到部署了kubectl的节点上`

##### 1.1 github官方下载
```bash
# 下载安装脚本(有时候会出现下载不下来的问题,可以直接使用文档中的脚本文件)
$ curl -sL https://istio.io/downloadIstioctl > download-istioctl.sh

# 执行脚本下载

## 下载指定版本
$ ISTIO_VERSION=1.9.5 sh download-istioctl.sh

## 下载最新版本
$ sh download-istioctl.sh

```

##### 1.2 网盘下载
`由于github的网络不稳定,时常无法访问,课程在准备了现成的二进制文件放在网盘供大家下载`
> 链接: https://pan.baidu.com/s/1akMTf606lVzOWFdhnXOmsQ 提取码: nnw4


#### 2. 解压缩,并设置好环境
把istioctl加入到PATH里面,并测试可用性

```bash
# 解压缩下载的文件后,进入到istio的bin目录中
$ cd istio-1.9.5/bin

# 把当前目录添加到PATH
$ export PATH=$PATH:`pwd`

# 测试
$ istioctl version
client version: 1.9.5
control plane version: 1.9.5
data plane version: 1.9.5 (8 proxies)
安装istio
## 1.2 使用IstioOperator部署istio

#### 1. 初始化
```bash
$ istioctl operator init
```
此命令运行 operator 在 istio-operator 命名空间中创建以下资源:
- operator 自定义资源定义(CRD)
- operator 控制器的 deployment 对象
- 一个用来访问 operator 指标的服务
- Istio operator 运行必须的 RBAC 规则

#### 2. 安装
```bash
# 使用 operator 安装 Istio(demo的profile,该有的不该有的都有了)
$ kubectl create ns istio-system
$ kubectl apply -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: istio-system
  name: example-istiocontrolplane
spec:
  profile: demo
EOF
```

#### 3. 检查安装结果
```bash
# 查看service
$ kubectl get svc -n istio-system
NAME                        TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                                                      AGE
istio-egressgateway         ClusterIP      10.103.243.113   <none>        80/TCP,443/TCP,15443/TCP                                                     17s
istio-ingressgateway        LoadBalancer   10.101.204.227   <pending>     15020:31077/TCP,80:30689/TCP,443:32419/TCP,31400:31411/TCP,15443:30176/TCP   17s
istiod                      ClusterIP      10.96.237.249    <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP,53/UDP,853/TCP                         30s                               
# 查看pod
$ kubectl get pods -n istio-system
NAME                                   READY   STATUS    RESTARTS   AGE
istio-egressgateway-5444c68db8-9h6dz   1/1     Running   0          87s
istio-ingressgateway-5c68cb968-x7qv9   1/1     Running   0          87s
istiod-598984548d-wjq9j                1/1     Running   0          99s
使用IstioOperator部署istio
## 1.3 卸载

删除集群内运行的 IstioOperator CR,该 CR 将卸载正在运行的 Istio :
```bash
$ kubectl delete istiooperators.install.istio.io -n istio-system example-istiocontrolplane
```

等到 Istio 卸载完成。 然后删除 Istio
```bash
$ istioctl operator remove
```

`或`

```bash
$ kubectl delete ns istio-operator --grace-period=0 --force
```

在 Istio 完全移除之前删除 operator 可能会导致 Istio 资源残留。 需要清理 operator 未删除的内容:
```bash
$ istioctl manifest generate | kubectl delete -f -

$ kubectl delete ns istio-system --grace-period=0 --force
卸载

 

部署bookinfo示例应用

bookinfo是为了官方测试演示使用的一个软件,模仿了一个在线书店的评分系统

## BookInfo应用介绍

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

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

- productpage. 这个微服务会调用 details 和 reviews 两个微服务,用来生成页面。
- details. 这个微服务中包含了书籍的信息。
- reviews. 这个微服务中包含了书籍相关的评论。它还会调用 ratings 微服务。
- ratings. 这个微服务中包含了由书籍评价组成的评级信息。

##### reviews 微服务有 3 个版本:

- v1 版本不会调用 ratings 服务。
- v2 版本会调用 ratings 服务,并使用 15 个黑色星形图标来显示评分信息。
- v3 版本会调用 ratings 服务,并使用 15 个红色星形图标来显示评分信息。

下图展示了这个应用的端到端架构。
![avatar](https://git.imooc.com/coding-335/course-docs/raw/master/images/13_bookinfo_1.png)

Bookinfo 是一个异构应用,几个微服务是由不同的语言编写的。这些服务对 Istio 并无依赖,但是构成了一个有代表性的服务网格的例子:它由多个服务、多个语言构成,并且 reviews 服务具有多个版本。
BookInfo应用介绍
## 2. 部署应用
要在 Istio 中运行这一应用,无需对应用自身做出任何改变。 您只要简单的在 Istio 环境中对服务进行配置和运行,具体一点说就是把 Envoy sidecar 注入到每个服务之中。 最终的部署结果将如下图所示:
![avatar](https://git.imooc.com/coding-335/course-docs/raw/master/images/13_bookinfo_2.png)

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

接下来可以根据 Istio 的运行环境,按照下面的讲解完成应用的部署。

#### 2.1 部署
```bash
# 进入 Istio 安装目录。
$ cd istio-1.9.5

# Istio 默认启用自动 Sidecar 注入,为 default 命名空间打上标签 istio-injection=enabled。
$ kubectl label namespace default istio-injection=enabled

# 使用 kubectl 部署简单的服务
$ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
```

#### 2.2 部署结果检查
`在实际部署中,微服务版本的启动过程需要持续一段时间,并不是同时完成的。`

确认所有的服务和 Pod 都已经正确的定义和启动
```bash
# service列表
$ kubectl get services
NAME                       CLUSTER-IP   EXTERNAL-IP   PORT(S)              AGE
details                    10.0.0.31    <none>        9080/TCP             6m
kubernetes                 10.0.0.1     <none>        443/TCP              7d
productpage                10.0.0.120   <none>        9080/TCP             6m
ratings                    10.0.0.15    <none>        9080/TCP             6m
reviews                    10.0.0.170   <none>        9080/TCP             6m

# pod列表
$ kubectl get pods
NAME                                        READY     STATUS    RESTARTS   AGE
details-v1-1520924117-48z17                 2/2       Running   0          6m
productpage-v1-560495357-jk1lz              2/2       Running   0          6m
ratings-v1-734492171-rnr5l                  2/2       Running   0          6m
reviews-v1-874083890-f0qf0                  2/2       Running   0          6m
reviews-v2-1343845940-b34q5                 2/2       Running   0          6m
reviews-v3-1813607990-8ch52                 2/2       Running   0          6m
```

要确认 Bookinfo 应用是否正在运行,请在某个 Pod 中用 curl 命令对应用发送请求,例如 ratings:
```bash
$ 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>"
<title>Simple Bookstore App</title>
```

#### 2.3 部署BookInfo-Gateway
现在 Bookinfo 服务启动并运行中,您需要使应用程序可以从外部访问 Kubernetes 集群,例如使用浏览器。可以用 Istio Gateway 来实现这个目标。

```bash
# 为应用程序定义入口网关
$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml

# 确认网关创建完成
$ kubectl get gateway
NAME               AGE
bookinfo-gateway   32s

# 确认可以从集群外部访问应用
$ curl <INGRESS-IP>:<HTTP2-NODEPORT>/productpage
```
Gateway 配置资源允许外部流量进入 Istio 服务网格,并对边界服务实施流量管理和 Istio 可用的策略特性。

事先,在服务网格中创建一个服务并向外部流量暴露该服务的 HTTP 端点。


#### 2.4 部署附加组件(Kiali 仪表板、 以及 Prometheus、 Grafana、 还有 Jaeger)

```bash
# apply示例中的addons目录中所有文件
$ kubectl apply -f samples/addons
```
`如果在安装插件时出错,再运行一次命令。 有一些和时间相关的问题,再运行就能解决。`
部署bookinfo应用

 

流量管理

istio配置请求路由

## 配置请求路由

Istio Bookinfo 示例包含四个独立的微服务,每个微服务都有多个版本。 其中一个微服务 reviews 的三个不同版本已经部署并同时运行。 为了说明这导致的问题,在浏览器中访问 Bookinfo 应用程序的 /productpage 并刷新几次。 您会注意到,有时书评的输出包含星级评分,有时则不包含。 这是因为没有明确的默认服务版本路由,Istio 将以循环方式请求路由到所有可用版本。

此任务的第一个目标是应用将所有流量路由到微服务的 v1 (版本 1)的规则。第二个目标是根据 HTTP 请求 header 的值路由流量。

#### 1. 将所有流量路由到v1
```bash
# 创建DestinationRule
$ kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml

# 创建VirtualService
$ kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
```
`由置传播是最终一致的,因此请等待于配几秒钟以使 virtual services 生效。`


#### 2. 根据 HTTP 请求 header 的值路由
接下来,您将更改路由配置,以便将来自特定用户的所有流量路由到特定服务版本。在这,来自名为 Jason 的用户的所有流量将被路由到服务 reviews:v2。

```bash
# 创建规则
$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml

# 确认规则已创建
$ kubectl get virtualservice reviews -o yaml
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: v1
```

在 Bookinfo 应用程序的 /productpage 上,以用户 jason 身份登录。刷新浏览器。你看到了什么?星级评分显示在每个评论旁边。  

以其他用户身份登录(选择您想要的任何名称)。刷新浏览器。现在星星消失了。这是因为除了 Jason 之外,所有用户的流量都被路由到 reviews:v1。
配置路由

定义路由规则转发到后端的service及version

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
---
destination-rule-all.yaml

定义后端实际使用service version

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productpage
spec:
  hosts:
  - productpage
  http:
  - route:
    - destination:
        host: productpage
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: details
spec:
  hosts:
  - details
  http:
  - route:
    - destination:
        host: details
        subset: v1
---
virtual-service-all-v1.yaml

根据head路由后指定version v2后端

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: v1
virtual-service-reviews-test-v2.yaml

 

故障注入

## 故障注入

#### 1. 注入故障
为了测试微服务应用程序 Bookinfo 的弹性,我们将为用户 jason 在 reviews:v2 和 ratings 服务之间注入一个 7 秒的延迟。 这个测试将会发现一个故意引入 Bookinfo 应用程序中的 bug。

注意 reviews:v2 服务对 ratings 服务的调用具有 10 秒的硬编码连接超时。 因此,尽管引入了 7 秒的延迟,我们仍然期望端到端的流程是没有任何错误的。

```bash
# 创建故障注入规则以延迟来自测试用户 jason 的流量
$ kubectl apply -f samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml
# 确认规则已经创建:
$ kubectl get virtualservice ratings -o yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
  ...
spec:
  hosts:
  - ratings
  http:
  - fault:
      delay:
        fixedDelay: 7s
        percentage:
          value: 100
    match:
    - headers:
        end-user:
          exact: jason
    route:
    - destination:
        host: ratings
        subset: v1
  - route:
    - destination:
        host: ratings
        subset: v1
```
#### 2. 延迟测试
使用用户 jason 登陆到 /productpage 页面。
你期望 Bookinfo 主页在大约 7 秒钟加载完成并且没有错误。 但是,出现了一个问题:Reviews 部分显示了错误消息:
```text
Error fetching product reviews!
Sorry, product reviews are currently unavailable for this book.
```
查看页面的响应时间:
打开浏览器的 开发工具 菜单,打开 网络 标签,重新加载 productpage 页面。你会看到页面加载实际上用了大约 6s。

你发现了一个 bug。微服务中有硬编码超时,导致 reviews 服务失败。

按照预期,我们引入的 7 秒延迟不会影响到 `reviews` 服务,因为 `reviews` 和 `ratings` 服务间的超时被硬编码为 10 秒。 但是,在 `productpage` 和 `reviews` 服务之间也有一个 3 秒的硬编码的超时,再加 1 次重试,一共 6 秒。 结果,`productpage` 对 `reviews` 的调用在 6 秒后提前超时并抛出错误了。

这种类型的错误可能发生在典型的由不同的团队独立开发不同的微服务的应用中。 Istio 的故障注入规则可以帮助您识别此类异常,而不会影响最终用户。

`请注意,此次故障注入限制为仅影响用户 jason。如果您以任何其他用户身份登录,则不会遇到任何延迟。`

#### 3. 错误修复
这种问题通常会这么解决:

- 增加 productpage 与 reviews 服务之间的超时或降低 reviews 与 ratings 的超时
- 终止并重启修复后的微服务
- 确认 /productpage 页面正常响应且没有任何错误

但是,reviews 服务的 v3 版本已经修复了这个问题。 reviews:v3 服务已将 reviews 与 ratings 的超时时间从 10 秒降低为 2.5 秒,因此它可以兼容(小于)下游的 productpage 的请求。
  
如果您按照流量转移任务所述将所有流量转移到 reviews:v3, 您可以尝试修改延迟规则为任何低于 2.5 秒的数值,例如 2 秒,然后确认端到端的流程没有任何错误。

#### 4. 注入 HTTP abort 故障
测试微服务弹性的另一种方法是引入 HTTP abort 故障。 这个任务将给 ratings 微服务为测试用户 jason 引入一个 HTTP abort。

在这种情况下,我们希望页面能够立即加载,同时显示 Ratings service is currently unavailable 这样的消息。
```bash
# 为用户 jason 创建一个发送 HTTP abort 的故障注入规则:
$ kubectl apply -f samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml

#确认规则已经创建:

$ kubectl get virtualservice ratings -o yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
  ...
spec:
  hosts:
  - ratings
  http:
  - fault:
      abort:
        httpStatus: 500
        percentage:
          value: 100
    match:
    - headers:
        end-user:
          exact: jason
    route:
    - destination:
        host: ratings
        subset: v1
  - route:
    - destination:
        host: ratings
        subset: v1
```


#### 5. 测试中止配置
使用用户 jason 登陆到 /productpage 页面。
您应该能立即看到页面加载并看到 Ratings service is currently unavailable 消息。

如果您注销用户 jason, 您将看到 /productpage 为除 jason 以外的其他用户调用了 reviews:v1(完全不调用 ratings)。 因此,您不会看到任何错误消息。

#### 6. 清理环境
```bash
$ kubectl delete -f samples/bookinfo/networking/virtual-service-all-v1.yaml
```
故障注入

当head为指定值或用户时为其注入延迟7s故障

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    fault:
      delay:
        percentage:
          value: 100.0
        fixedDelay: 7s
    route:
    - destination:
        host: ratings
        subset: v1
  - route:
    - destination:
        host: ratings
        subset: v1
virtual-service-ratings-test-delay.yaml

注入http abort故障

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    fault:
      abort:
        percentage:
          value: 100.0
        httpStatus: 500
    route:
    - destination:
        host: ratings
        subset: v1
  - route:
    - destination:
        host: ratings
        subset: v1
virtual-service-ratings-test-abort.yaml

流量转移

## HTTP流量转移
本任务将向您展示如何逐步将流量从一个版本的微服务迁移到另一个版本。例如,您可以将流量从旧版本迁移到新版本。

一个常见的用例是将流量从一个版本的微服务逐渐迁移到另一个版本。在 Istio 中,您可以通过配置一系列规则来实现此目标, 这些规则将一定百分比的流量路由到一个或另一个服务。

在本任务中,您将会把 50% 的流量发送到 reviews:v1,另外 50% 的流量发送到 reviews:v3。然后,再把 100% 的流量发送到 reviews:v3 来完成迁移。

#### 1. 基于权重的路由

```bash
# 首先,将所有流量路由到各个微服务的 v1 版本
$ kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml

# 把 50% 的流量从 reviews:v1 转移到 reviews:v3
$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml

# 确认规则已被替换:
$ kubectl get virtualservice reviews -o yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
  ...
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 50
    - destination:
        host: reviews
        subset: v3
      weight: 50
```

刷新浏览器中的 /productpage 页面,大约有 50% 的几率会看到页面中出带 红色 星级的评价内容。这是因为 v3 版本的 reviews 访问了带星级评级的 ratings 服务,但 v1 版本却没有。

`在目前的 Envoy sidecar 实现中,可能需要刷新 /productpage 很多次–可能 15 次或更多–才能看到正确的流量分发的效果。您可以通过修改规则将 90% 的流量路由到 v3,这样能看到更多带红色星级的评价。`

如果您认为 reviews:v3 微服务已经稳定,你可以通过应用此 virtual service 规则将 100% 的流量路由到 reviews:v3:

```bash
$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-v3.yaml
```
现在,当您刷新 /productpage 时,您将始终看到带有 红色 星级评分的书评。

#### 2. 清理环境
```bash
$ kubectl delete -f samples/bookinfo/networking/virtual-service-all-v1.yaml
```

## TCP流量转移

本任务展示了如何逐步将 TCP 流量从微服务的一个版本迁移到另一个版本。例如,将 TCP 流量从旧版本迁移到新版本。

在 Istio 中,您可以通过配置一系列规则来实现此目标,这些规则按指定的百分比将流量路由到不同的服务。在此任务 中,将先把 100% 的 TCP 流量分配到 tcp-echo:v1,然后,再通过配置 Istio 路由权重把 20% 的 TCP 流量分 配到 tcp-echo:v2。

#### 1. 部署微服务 tcp-echo 的 v1 版本

```bash
# 为测试 TCP 流量转移创建命名空间
$ kubectl create namespace istio-io-tcp-traffic-shifting

# 将 istio-io-tcp-traffic-shifting namespace 标记为 istio-injection=enabled
$ kubectl label namespace istio-io-tcp-traffic-shifting istio-injection=enabled

# 使用 kubectl 部署服务
$ kubectl apply -f samples/tcp-echo/tcp-echo-services.yaml -n istio-io-tcp-traffic-shifting

```

#### 2. 将目标为 tcp-echo 的 TCP 流量全部路由到 v1 版本

```bash
$ kubectl apply -f samples/tcp-echo/tcp-echo-all-v1.yaml -n istio-io-tcp-traffic-shifting

```

#### 3. 确认 tcp-echo 服务已启动并开始运行
先使用下面命令获取 gateway 的 tcp 端口,并设置INGRESS_HOST
```bash
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="tcp")].nodePort}')

$ export INGRESS_HOST=<your-node-ip>
```

向微服务 tcp-echo 发送 TCP 流量
```bash
$ echo "hello"| nc $INGRESS_HOST $INGRESS_PORT
```
您应该注意到,所有时间戳的前缀都是 one ,这意味着所有流量都被路由到了 tcp-echo 服务的 v1 版本。

#### 4. 将 20% 的流量从 tcp-echo:v1 转移到 tcp-echo:v2
```bash
$ kubectl apply -f samples/tcp-echo/tcp-echo-20-v2.yaml -n istio-io-tcp-traffic-shifting

# 确认规则配置已替换完成
$ kubectl get virtualservice tcp-echo -o yaml -n istio-io-tcp-traffic-shifting
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: tcp-echo
  ...
spec:
  ...
  tcp:
  - match:
    - port: 31400
    route:
    - destination:
        host: tcp-echo
        port:
          number: 9000
        subset: v1
      weight: 80
    - destination:
        host: tcp-echo
        port:
          number: 9000
        subset: v2
      weight: 20
```
向 tcp-echo 服务发送更多 TCP 流量
```bash
$ for i in {1..10}; do \
echo "hello" | nc $INGRESS_HOST $INGRESS_PORT; \
done
```
现在应该发现,有大约 20% 的流量时间戳前缀是 two ,这意味着有 80% 的 TCP 流量路由到了 tcp-echo 服务的 v1 版本,与此同时有 20% 流量路由到了 v2 版本。

#### 5. 清理环境
```bash
$ kubectl delete -f samples/tcp-echo/tcp-echo-all-v1.yaml -n istio-io-tcp-traffic-shifting
$ kubectl delete -f samples/tcp-echo/tcp-echo-services.yaml -n istio-io-tcp-traffic-shifting
$ kubectl delete namespace istio-io-tcp-traffic-shifting
流量转移

把流量按照权重转移到指定版本

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 50
    - destination:
        host: reviews
        subset: v3
      weight: 50
virtual-service-reviews-50-v3.yaml

把流量全部切换到新版本

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v3
virtual-service-reviews-v3.yaml

基于tcp流量转移

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: tcp-echo-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 31400
      name: tcp
      protocol: TCP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: tcp-echo-destination
spec:
  host: tcp-echo
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: tcp-echo
spec:
  hosts:
  - "*"
  gateways:
  - tcp-echo-gateway
  tcp:
  - match:
    - port: 31400
    route:
    - destination:
        host: tcp-echo
        port:
          number: 9000
        subset: v1
部署tcp-getway

按照权重分发流量

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: tcp-echo
spec:
  hosts:
  - "*"
  gateways:
  - tcp-echo-gateway
  tcp:
  - match:
    - port: 31400
    route:
    - destination:
        host: tcp-echo
        port:
          number: 9000
        subset: v1
      weight: 80
    - destination:
        host: tcp-echo
        port:
          number: 9000
        subset: v2
      weight: 
tcp-echo-20-v2.yaml

 

设置请求超时

## 设置请求超时
本任务用于示范如何使用 Istio 在 Envoy 中设置请求超时。

http 请求的超时可以用路由规则的 timeout 字段来指定。 默认情况下,超时是禁用的,本任务中,会把 reviews 服务的超时设置为 1 秒。 为了观察效果,还需要在对 ratings 服务的调用上人为引入 2 秒的延迟。



#### 1. 初始化路由
```bash
# 基础路由
$ kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml

# 将请求路由到 reviews 服务的 v2 版本
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v2
EOF
```

#### 2. 给对 ratings 服务的调用添加 2 秒的延迟
```bash
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - fault:
      delay:
        percent: 100
        fixedDelay: 2s
    route:
    - destination:
        host: ratings
        subset: v1
EOF
```
在浏览器中打开 Bookinfo ,这时可以看到 Bookinfo 应用运行正常(显示了评级的星型符号),但是每次刷新页面,都会有 2 秒的延迟。
 
#### 3. 给对 reviews 服务的调用增加一个半秒的请求超时
 ```bash
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v2
    timeout: 0.5s
EOF
 ```
刷新 Bookinfo 页面。这时候应该看到 1 秒钟就会返回,而不是之前的 2 秒钟,但 reviews 是不可用的。
 
`即使超时配置为半秒,响应仍需要 1 秒,是因为 productpage 服务中存在硬编码重试,因此它在返回之前调用 reviews 服务超时两次。`

#### 4. 清理环境
```bash
$ kubectl delete -f samples/bookinfo/networking/virtual-service-all-v1.yaml
设置请求超时

熔断

## 熔断
熔断,是创建弹性微服务应用程序的重要模式。熔断能够使您的应用程序具备应对来自故障、潜在峰值和其他 未知网络因素影响的能力。

这个任务中,你将配置熔断规则,然后通过模拟压力使熔断器“跳闸”来测试配置。



#### 1. 配置熔断

```bash
# 创建示例服务 httpbin
$ kubectl apply -f samples/httpbin/httpbin.yaml

# 创建一个目标规则,在调用 httpbin 服务时应用熔断设置
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
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
EOF
```

#### 2. 配置测试工具

这里使用一个名为 Fortio 的负载测试客户的,其可以控制连接数、并发数及发送 HTTP 请求的延迟。通过 Fortio 能够有效的触发前面 在 DestinationRule 中设置的熔断策略。
```bash
$ kubectl apply -f samples/httpbin/sample-client/fortio-deploy.yaml

# 登入客户端 Pod 并使用 Fortio 工具调用 httpbin 服务。-curl 参数表明发送一次调用
$ FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
$ kubectl exec -it $FORTIO_POD  -c fortio -- /usr/bin/fortio load -curl  http://httpbin:8000/get
  HTTP/1.1 200 OK
  server: envoy
  date: Mon, 12 Apr 2021 07:24:34 GMT
  content-type: application/json
  content-length: 622
  access-control-allow-origin: *
  access-control-allow-credentials: true
  x-envoy-upstream-service-time: 18
  
  {
    "args": {},
    "headers": {
      "Content-Length": "0",
      "Host": "httpbin:8000",
      "User-Agent": "fortio.org/fortio-1.11.3",
      "X-B3-Parentspanid": "5d9ea8c4778c3dc3",
      "X-B3-Sampled": "1",
      "X-B3-Spanid": "a5966b706e66f444",
      "X-B3-Traceid": "4a7b1172262cb75e5d9ea8c4778c3dc3",
      "X-Envoy-Attempt-Count": "1",
      "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=bdb72a603b6940ca19692857675068cd64b2109b0e9d455bd4f3780fb266f254;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default"
    },
    "origin": "127.0.0.1",
    "url": "http://httpbin:8000/get"
  }
```
可以看到调用后端服务的请求已经成功!接下来,可以测试熔断。

#### 3. 开始测试 - 触发熔断
在 DestinationRule 配置中,您定义了 maxConnections: 1 和 http1MaxPendingRequests: 1。 这些规则意味着,如果并发的连接和请求数超过一个,后续请求或 连接将被阻止。

发送并发数为 2 的连接(-c 2),请求 20 次(-n 20):
```bash
$ kubectl exec -it $FORTIO_POD  -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
0 -n 20 -loglevel Warning http://httpbin:8000/get
07:44:54 I logger.go:127> Log level is now 3 Warning (was 2 Info)
Fortio 1.11.3 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)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
07:44:54 W http_client.go:693> Parsed non ok code 503 (HTTP/1.1 503)
Ended after 120.942815ms : 20 calls. qps=165.37
Aggregated Function Time : count 20 avg 0.010126651 +/- 0.02158 min 0.000702929 max 0.093913849 sum 0.202533027
# range, mid point, percentile, count
>= 0.000702929 <= 0.001 , 0.000851465 , 30.00, 6
> 0.001 <= 0.002 , 0.0015 , 70.00, 8
> 0.002 <= 0.003 , 0.0025 , 75.00, 1
> 0.007 <= 0.008 , 0.0075 , 80.00, 1
> 0.014 <= 0.016 , 0.015 , 85.00, 1
> 0.025 <= 0.03 , 0.0275 , 90.00, 1
> 0.035 <= 0.04 , 0.0375 , 95.00, 1
> 0.09 <= 0.0939138 , 0.0919569 , 100.00, 1
# target 50% 0.0015
# target 75% 0.003
# target 90% 0.03
# target 99% 0.0931311
# target 99.9% 0.0938356
Sockets used: 18 (for perfect keepalive, would be 2)
Jitter: false
Code 200 : 2 (10.0 %)
Code 503 : 18 (90.0 %)
Response Header Sizes : count 20 avg 23.05 +/- 69.15 min 0 max 231 sum 461
Response Body/Total Sizes : count 20 avg 222.95 +/- 209.9 min 153 max 853 sum 4459
All done 20 calls (plus 0 warmup) 10.127 ms avg, 165.4 qps
```

查询 istio-proxy 状态以了解更多熔断详情:
```bash
$ kubectl exec $FORTIO_POD -c istio-proxy -- pilot-agent request GET stats | grep httpbin | grep pending
cluster.outbound|8000||httpbin.default.svc.cluster.local.circuit_breakers.default.rq_pending_open: 0
cluster.outbound|8000||httpbin.default.svc.cluster.local.circuit_breakers.high.rq_pending_open: 0
cluster.outbound|8000||httpbin.default.svc.cluster.local.upstream_rq_pending_active: 0
cluster.outbound|8000||httpbin.default.svc.cluster.local.upstream_rq_pending_failure_eject: 0
cluster.outbound|8000||httpbin.default.svc.cluster.local.upstream_rq_pending_overflow: 22
cluster.outbound|8000||httpbin.default.svc.cluster.local.upstream_rq_pending_total: 31
```

#### 4. 清理环境
```bash
# 清理规则:
$ kubectl delete destinationrule httpbin

# 下线 httpbin 服务和客户端:
$ kubectl delete deploy httpbin fortio-deploy
$ kubectl delete svc httpbin
```
熔断

熔断配置

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: httpbin
spec:
  host: httpbin
  trafficPolicy: #流量策略
    connectionPool: #链接池(本质是限流)
      tcp:
        maxConnections: 1 #最大链接1个
      http:
        http1MaxPendingRequests: 1 #当请求数排队数等于1触发熔断
        maxRequestsPerConnection: 1 #每个链接处理的最大请求数
    outlierDetection: #异常或错误的配置
      consecutiveGatewayErrors: 1 #连续gateway异常 超过1时
      interval: 1s #拒绝访问的时间间隔 在1秒钟连续发生1次异常
      baseEjectionTime: 3m #发生熔断后静默时间
      maxEjectionPercent: 100 #后端负载均衡池拒绝请求的百分比
EOF
熔断策略

流量镜像

此任务演示了 Istio 的流量镜像功能。

流量镜像,也称为影子流量,是一个以尽可能低的风险为生产带来变化的强大的功能。镜像会将实时流量的副本发送到镜像服务。镜像流量发生在主服务的关键请求路径之外。
在此任务中,首先把流量全部路由到 v1 版本的测试服务。然后,执行规则将一部分流量镜像到 v2 版本。

#### 1. 测试环境准备
首先部署两个版本的 httpbin 服务,httpbin 服务已开启访问日志
##### httpbin-v1:
```bash
$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin-v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
      version: v1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      containers:
      - image: docker.io/kennethreitz/httpbin
        imagePullPolicy: IfNotPresent
        name: httpbin
        command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:80", "httpbin:app"]
        ports:
        - containerPort: 80
EOF
```
##### httpbin-v2:
```bash
$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin-v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
      version: v2
  template:
    metadata:
      labels:
        app: httpbin
        version: v2
    spec:
      containers:
      - image: docker.io/kennethreitz/httpbin
        imagePullPolicy: IfNotPresent
        name: httpbin
        command: ["gunicorn", "--access-logfile", "-", "-b", "0.0.0.0:80", "httpbin:app"]
        ports:
        - containerPort: 80
EOF
```
##### httpbin Kubernetes service:
```bash
$ kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  labels:
    app: httpbin
spec:
  ports:
  - name: http
    port: 8000
    targetPort: 80
  selector:
    app: httpbin
EOF
```

#### 启动 sleep 服务(用于curl访问服务)
```bash
$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sleep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sleep
  template:
    metadata:
      labels:
        app: sleep
    spec:
      containers:
      - name: sleep
        image: tutum/curl
        command: ["/bin/sleep","infinity"]
        imagePullPolicy: IfNotPresent
EOF
```

#### 2. 创建默认路由策略
默认情况下,Kubernetes 在 httpbin 服务的两个版本之间进行负载均衡。在此步骤中会更改该行为,把所有流量都路由到 v1。

```bash
# 创建一个默认路由规则,将所有流量路由到服务的 v1:
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin
spec:
  hosts:
    - httpbin
  http:
  - route:
    - destination:
        host: httpbin
        subset: v1
      weight: 100
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: httpbin
spec:
  host: httpbin
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
EOF


# 向服务发送一下流量
$ export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
$ kubectl exec -it $SLEEP_POD -c sleep -- sh -c 'curl  http://httpbin:8000/headers' | python -m json.tool
{
    "headers": {
        "Accept": "*/*",
        "Content-Length": "0",
        "Host": "httpbin:8000",
        "User-Agent": "curl/7.35.0",
        "X-B3-Parentspanid": "1bb463d476fc8132",
        "X-B3-Sampled": "1",
        "X-B3-Spanid": "29179c054a9227aa",
        "X-B3-Traceid": "a7cacbaca2be15671bb463d476fc8132",
        "X-Envoy-Attempt-Count": "1",
        "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/default/sa/default;Hash=bdb120f75cd64d27aaa30c2bf0074da72c580929dc28124bec61b8710f9495b5;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default"
    }
}

# 查看 httpbin 服务 v1 的日志
$ export V1_POD=$(kubectl get pod -l app=httpbin,version=v1 -o jsonpath={.items..metadata.name})
$ kubectl logs -f $V1_POD -c httpbin

# 查看 httpbin 服务 v2 的日志
$ export V2_POD=$(kubectl get pod -l app=httpbin,version=v2 -o jsonpath={.items..metadata.name})
$ kubectl logs -f $V2_POD -c httpbin

```
`思考一下:课程中为什么要用一个sleep pod作为媒介调用 httpbin 服务,而不直接使用系统上的 curl 来调用呢?`


#### 3. 镜像流量到 v2

##### 改变流量规则将流量镜像到 v2:
```bash
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin
spec:
  hosts:
    - httpbin
  http:
  - route:
    - destination:
        host: httpbin
        subset: v1
      weight: 100
    mirror:
      host: httpbin
      subset: v2
    mirrorPercentage:
      value: 100
EOF
```
这个路由规则发送 100% 流量到 v1。最后一段表示你将镜像流量到 httpbin:v2 服务。当流量被镜像时,请求将发送到镜像服务中,并在 headers 中的 Host/Authority 属性值上追加 -shadow。例如 cluster-1 变为 cluster-1-shadow。

此外,重点注意这些被镜像的流量是『 即发即弃』 的,就是说镜像请求的响应会被丢弃。

##### 发送流量
```bash
$ kubectl exec -it $SLEEP_POD -c sleep -- sh -c 'curl  http://httpbin:8000/headers' | python -m json.tool
```
现在就可以看到 v1 和 v2 中都有了访问日志。v2 中的访问日志就是由镜像流量产生的,这些请求的实际目标是 v1。
```bash
$ kubectl logs -f $V1_POD -c httpbin
```

```bash
$ kubectl logs -f $V2_POD -c httpbin
```

#### 4. 环境清理
删除规则
```bash
$ kubectl delete virtualservice httpbin
$ kubectl delete destinationrule httpbin
```
关闭 httpbin 服务和客户端
```bash
$ kubectl delete deploy httpbin-v1 httpbin-v2 sleep
$ kubectl delete svc httpbin
流量镜像

istio可观测性

istio中的Prometheus和Grafana

## 通过prometheus查询指标
本任务介绍如何通过 Prometheus 查询 Istio 度量指标。作为任务的一部分,你将通过 web 界面查询度量指标值。

#### 1. 发送测试流量
```bash
# 验证自身集群中运行着 prometheus 服务。
$ kubectl -n istio-system get svc prometheus

# 初始化VirtualService
kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml

# 向网格发送流量
$ curl http://$GATEWAY_URL/productpage

```
#### 2. 查询指标
先修改prometheus的service为nodeport
```bash
$ kubectl apply -f - << EOF
apiVersion: v1
kind: Service
metadata:
  labels:
    app: prometheus
    chart: prometheus-11.16.2
    component: server
    heritage: Helm
    release: prometheus
  name: prometheus
  namespace: istio-system
spec:
  ports:
  - name: http
    port: 9090
    nodePort: 31090
    protocol: TCP
    targetPort: 9090
  selector:
    app: prometheus
    component: server
    release: prometheus
  type: NodePort
EOF
```
`修改完成后即可通过 http://<node-ip>:31090/ 访问prometheus页面`  

查询请求 productpage 服务的总次数
```text
istio_requests_total{destination_service="productpage.default.svc.cluster.local"}
```
查询请求 reviews 服务 V3 版本的总次数
```text
istio_requests_total{destination_service="reviews.default.svc.cluster.local", destination_version="v3"}
```
查询过去 5 分钟 productpage 服务所有实例的请求频次
```text
rate(istio_requests_total{destination_service=~"productpage.*", response_code="200"}[5m])
```

#### 3. 关于 Prometheus 插件
Mixer 自带一个内嵌的 Prometheus 适配器,对外暴露一个端点,负责提供metrics值服务。Prometheus 插件是一个提前配置好的 Prometheus 服务,旨在通过 Mixer 端点收集对外暴露的metric。插件提供了持久化存储和 Istio metrics查询机制。

##### Prometheus 插件预配抓捕如下端点:
1. istio-telemetry.istio-system:42422: istio-mesh 任务返回所有 Mixer 生成的度量指标。
2. istio-telemetry.istio-system:15014: istio-telemetry 任务返回所有 Mixer 特殊的度量指标。该端点用于监控 Mixer 本身。
3. istio-proxy:15090: envoy-stats 任务返回 Envoy 生成的原始状态。Prometheus 被配置来查找对外暴露了 envoy-prom 端点的 pods。在收集过程中,插件配置过滤掉大量 envoy 度量指标,从而限制插件进程的数据量。
4. istio-pilot.istio-system:15014: pilot 任务返回 Pilot 生成的度量指标。
5. istio-galley.istio-system:15014: galley 任务返回 Galley 生成的度量指标。
6. istio-policy.istio-system:15014: istio-policy 任务返回所有策略相关的度量指标。
7. istio-citadel.istio-system:15014: istio-citadel 任务返回所有 Citadel 生成的度量指标。

## 使用 Grafana 可视化指标
此任务展示了如何设置和使用 Istio Dashboard 监控网格流量。作为此任务的一部分,您将使用 Grafana 的 Istio 附加组件和基于 Web 的界面来查看服务网格流量数据。

#### 1. 访问Grafana
验证 Grafana 服务正在集群中运行。
```bash
$ kubectl -n istio-system get svc grafana
```
修改grafana的svc为nodePort类型
```bash
$ kubectl apply -f - << EOF
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/instance: grafana
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: grafana
    app.kubernetes.io/version: 7.2.1
    helm.sh/chart: grafana-5.8.10
  name: grafana
  namespace: istio-system
spec:
  ports:
  - name: service
    port: 3000
    protocol: TCP
    targetPort: 3000
    nodePort: 31300
  selector:
    app.kubernetes.io/instance: grafana
    app.kubernetes.io/name: grafana
  type: NodePort
EOF
```
一边发送流量一边查看 istio 相关的dashboard


#### 2. 关于Grafana插件

Grafana 插件其实是一个 Grafana 的预配置实例。基础镜像已被修改为同时启动已安装的 Prometheus 数据源和 Istio Dashboard。Istio(特别是 Mixer)的基本安装文件附带了全局(用于每个服务的)指标的默认配置。Istio Dashboard 旨在与默认的 Istio 指标配置和 Prometheus 后端结合使用。
     
##### Istio Dashboard 包括三个主要部分:
     
1. 网格摘要视图:这部分提供网格的全局摘要视图,并显示网格中(HTTP/gRPC 和 TCP)的工作负载。
2. 单独的服务视图:这部分提供关于网格中每个单独的(HTTP/gRPC 和 TCP)服务的请求和响应指标。这部分也提供关于该服务的客户端和服务工作负载的指标。
3. 单独的工作负载视图:这部分提供关于网格中每个单独的(HTTP/gRPC 和 TCP)工作负载的请求和响应指标。这部分也提供关于该工作负载的入站工作负载和出站服务的指标。
Prometheus和Grafana

Envoy的访问日志

## Envoy的访问日志

Envoy 代理提供了一种记录访问日志的功能。Envoy 容器的标准输出能够通过 kubectl logs 命令打印出来。  

`使用demo配置部署的istio自动启用了 Envoy的访问日志,并将其输出到标准输出`  

```bash
# 查看当前运行的pods
$ kubectl get pods

# 选择一个pod查看它的访问日志
$ kubectl logs -f --tail 100 <pod-name> -c istio-proxy

# 刷新几次productpage的页面看看效果
```
Envoy访问日志

分布式追踪介绍

## 分布式追踪介绍
分布式追踪可以让用户对跨多个分布式服务网格的 1 个请求进行追踪分析。
Istio 利用 Envoy 的分布式追踪功能提供了开箱即用的追踪集成。确切地说,Istio 提供了安装各种各种追踪后端服务的选项,并且通过配置代理来自动发送追踪 span 到追踪后端服务。

#### 1、上下文传递
尽管 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

例如,如果你看 Python 的 productpage 服务这个例子,可以看到这个应用程序使用了 OpenTracing 库从 HTTP 请求中提取所需的头信息:
```python
def getForwardHeaders(request):
    headers = {}

    # x-b3-*** headers can be populated using the opentracing span
    span = get_current_span()
    carrier = {}
    tracer.inject(
        span_context=span.context,
        format=Format.HTTP_HEADERS,
        carrier=carrier)

    headers.update(carrier)

    # ...

    incoming_headers = ['x-request-id']

    # ...

    for ihdr in incoming_headers:
        val = request.headers.get(ihdr)
        if val is not None:
            headers[ihdr] = val

    return headers
```
在 reviews 这个应用中(Java)也做了类似的事情:
```java
@GET
@Path("/reviews/{productId}")
public Response bookReviewsById(@PathParam("productId") int productId,
                            @HeaderParam("end-user") String user,
                            @HeaderParam("x-request-id") String xreq,
                            @HeaderParam("x-b3-traceid") String xtraceid,
                            @HeaderParam("x-b3-spanid") String xspanid,
                            @HeaderParam("x-b3-parentspanid") String xparentspanid,
                            @HeaderParam("x-b3-sampled") String xsampled,
                            @HeaderParam("x-b3-flags") String xflags,
                            @HeaderParam("x-ot-span-context") String xotspan) {

  if (ratings_enabled) {
    JsonObject ratingsResponse = getRatings(Integer.toString(productId), user, xreq, xtraceid, xspanid, xparentspanid, xsampled, xflags, xotspan);
```
当你在应用程序中进行下游调用时,请确保包含这些请求头。

#### 2、追踪采样
默认情况下,使用 demo 配置文件安装时,Istio 会捕获所有请求的追踪信息。例如,当使用上面的 Bookinfo 示例应用时,每次访问 /productpage 接口时,你都可以在 dashboard 中看到一条相应的追踪信息。此采样频率适用于测试或低流量网格。对于高流量网格你可以通过下面的两种方法之一来降低追踪采样频率:

在运行中的网格,可以通过编辑 istio-pilot deployment 并通过以下步骤来改变环境变量:

```bash
# 1. 运行下面的命令来打开编辑器并加载 deployment 配置文件:
$ kubectl -n istio-system edit deploy istiod

# 2. 找到 PILOT_TRACE_SAMPLING 环境变量,将 value: 设置成你想要的百分比。
# 在这两种情况下,有效值的范围从 0.0100.0,精度为 0.01
分布式追踪介绍

分布式追踪Jaeger

## 分布式追踪Jaeger

#### Zipkin vs Jaeger
Zipkin早于Jaeger,是Google Dapper的开源版本,由Twitter进一步开发。Zipkin基于Java语言的应用程序,其中包含很多服务,每个服务都实现Zipkin具体的某一个功能,并包括一个用户界面和用于跟踪软件系统框架的界面。Zipkin支持大多数流行的高级语言,包括C#,Java和JavaScript。  
Jaeger由Uber创建,用Go语言编写。它除了Zipkin的功能集外,Jaeger还提供了动态采样,REST API,基于React的UI界面。为了实现这些功能,Jaeger相比Zipkin采取了一种不同的,更分散的方法。  
Jaeger的分布式体系结构使其具有高度可扩展性。Jaeger还具有独特的数据收集方式:与其他尝试收集轨迹和跨度(spans)的系统不同,Jaeger会对监视的数据进行动态采样。这种方法不仅可以处理突然的流量激增,而且可以提高Jaeger的整体性能。  
从github上对比来看,它们的star数差别不大,也就侧面说明了出道更晚的Jaeger更受欢迎。从commits历史看,Zipkin从2021年开始就几乎没有多少更新了。而Jaeger一直处于持续的更新中。

##### 修改jager的service为nodePort
```bash
$ kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  labels:
    app: jaeger
  name: tracing
  namespace: istio-system
spec:
  ports:
  - name: http-query
    port: 80
    nodePort: 30686
    protocol: TCP
    targetPort: 16686
  selector:
    app: jaeger
  type: NodePort
EOF
```

访问jaegerUI:http://$NODE_IP:30686  
访问 http://$GATEWAY_URL/productpage 一次或多次以生成追踪信息
分布式追踪Jaeger

网格可视化

## 网格可视化
此任务向您展示如何可视化 Istio 网格。
您将安装 Kiali 附加组件,并使用基于 Web 的图形用户界面来查看网格和 Istio 配置对象的服务图。 

#### 1、配置 kiali 访问 ui
```bash
# 验证服务是否在您的群集中运行
$ kubectl -n istio-system get svc kiali

# 修改kiali服务未NodePort
$ kubectl apply -f - << EOF
apiVersion: v1
kind: Service
metadata:
  labels:
    app: kiali
    app.kubernetes.io/instance: kiali-server
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: kiali
    app.kubernetes.io/part-of: kiali
    app.kubernetes.io/version: v1.29.0
    helm.sh/chart: kiali-server-1.29.0
    version: v1.29.0
  name: kiali
  namespace: istio-system
spec:
  ports:
  - name: http
    port: 20001
    nodePort: 30001
    protocol: TCP
    targetPort: 20001
  - name: http-metrics
    port: 9090
    protocol: TCP
    targetPort: 9090
  selector:
    app.kubernetes.io/instance: kiali-server
    app.kubernetes.io/name: kiali
  type: NodePort
EOF

```

#### 2、用浏览器通过节点ip+NodePort访问 kiali 体验kiali的全部功能
网格可视化

分布式追踪

Zipkin, Sleuth

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4.4-分布式追踪Jaeger

posted @ 2021-07-19 19:20  大辉哥  阅读(216)  评论(0编辑  收藏  举报