istio流量管理

news2024/10/7 4:29:54

流量管理

image-20231110102205352

目录

image-20231111150752155

文章目录

    • 流量管理
    • 目录
    • 流量管理概述
    • 请求路由
      • 1.路由到版本1
        • ==🚩 实战:路由到版本1-2023.11.11(测试成功)==
      • 2.基于用户身份的路由
        • ==🚩 实战:基于用户身份的路由-2023.11.11(测试成功)==
    • 关于我
    • 最后

流量管理概述

上面我们了解了 GatewayVirtualService 资源对象的作用,以及它们是如何影响 Envoy 的配置的,那么这些资源对象又是如何影响流量的呢?通过 Istio 如何实现流量管理的呢?

Istio 的流量路由规则可以很容易的控制服务之间的流量和 API 调用。Istio 简化了服务级别属性的配置,比如熔断器、超时和重试,并且能轻松的设置重要的任务,如 A/B 测试、金丝雀发布、基于流量百分比切分的分阶段发布等。它还提供了开箱即用的故障恢复特性, 有助于增强应用的健壮性,从而更好地应对被依赖的服务或网络发生故障的情况。

为了在网格中路由,Istio 需要知道所有的 endpoint 在哪以及它们属于哪些服务。为了定位到 service registry(服务注册中心),Istio 会连接到一个服务发现系统。如果在 Kubernetes 集群上安装了 Istio,那么它将自动检测该集群中的服务和 endpoint。

使用此服务注册中心,Envoy 代理可以将流量定向到相关服务。大多数基于微服务的应用程序,每个服务的工作负载都有多个实例来处理流量,称为负载均衡池。默认情况下,Envoy 代理基于轮询调度模型在服务的负载均衡池内分发流量,按顺序将请求发送给池中每个成员, 一旦所有服务实例均接收过一次请求后,就重新回到第一个池成员。

Istio 基本的服务发现和负载均衡能力提供了一个可用的服务网格,但它能做到的远比这多的多。在许多情况下我们可能希望对网格的流量情况进行更细粒度的控制。作为 A/B 测试的一部分,可能想将特定百分比的流量定向到新版本的服务,或者为特定的服务实例子集应用不同的负载均衡策略。可能还想对进出网格的流量应用特殊的规则,或者将网格的外部依赖项添加到服务注册中心。通过使用 Istio 的流量管理 API 将流量配置添加到 Istio,就可以完成所有这些甚至更多的工作。

请求路由

首先我们来实现下最基本的流量请求路由的功能,这里我们将学习如何将请求动态路由到微服务的多个版本。

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

我们首先来将所有流量路由到微服务的 v1 版本,稍后,您将应用规则根据 HTTP 请求 header 的值路由流量。

1.路由到版本1

🚩 实战:路由到版本1-2023.11.11(测试成功)

实验环境:

k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)

[root@master1 ~]#istioctl version
client version: 1.19.3
control plane version: 1.19.3
data plane version: 1.19.3 (8 proxies)

实验软件:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功) --本节测试yaml在此目录里

image-20231105111842627

实验步骤:

image-20231111150558060

graph LR
	A[实战步骤] -->B(1️⃣ 部署VirtualService)
	A[实战步骤] -->C(2️⃣ DestinationRule)
    A[实战步骤] -->D(3️⃣ 验证)

要只路由到一个版本,则需要为微服务设置默认版本的 VirtualService

🍀

应用规则

Istio 使用 VirtualService 来定义路由规则,只需要应用下面的资源对象即可:

$ kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
virtualservice.networking.istio.io/productpage created
virtualservice.networking.istio.io/reviews created
virtualservice.networking.istio.io/ratings created
virtualservice.networking.istio.io/details created

该资源清单中定义了四个 VirtualService 对象,分别是 productpagereviewsratingsdetails,它们分别对应着 Bookinfo 应用中的四个微服务,完整的清单如下所示:

# virtual-service-all-v1.yaml
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
---

我们可以看到这里的 VirtualService 对象中都定义了 subset 字段,这个字段就是用来指定微服务的版本的,这里我们将所有的微服务都指定为 v1 版本,这样所有的流量都会被路由到 v1 版本的微服务中,包括 reviews 服务,这样我们就不会再看到星级评分了。

🍀

但是如果我们现在直接去访问 Bookinfo 应用的话,是不能正常访问的,因为我们压根就还没指定这些 v1 版本的微服务到底在哪里。

image-20231111144249758

🍀

这个时候就需要用到另外一个资源对象 DestinationRule 了,我们需要为每个微服务创建一个 DestinationRule 对象,用来指定这些微服务的实际地址,这样 VirtualService 对象才能将流量路由到这些微服务中。Istio 在 DestinationRule 目标规则中使用 subsets 定义服务的版本,运行以下命令为 Bookinfo 服务创建默认的目标规则即可:

$ kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml
destinationrule.networking.istio.io/productpage created
destinationrule.networking.istio.io/reviews created
destinationrule.networking.istio.io/ratings created
destinationrule.networking.istio.io/details created

该资源清单中定义了四个 DestinationRule 对象,分别是 productpagereviewsratingsdetails 几个服务的目标规则,它们分别对应着 Bookinfo 应用中的四个微服务,完整的清单如下所示:

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

🍀

现在我们就可以正常访问 Bookinfo 应用了,并且无论刷新多少次,页面的评论部分都不会显示评级星标,这是因为我们将 Istio 配置为将 reviews 服务的所有流量路由到版本 reviews:v1,而此版本的服务不访问星级评分服务。

img

这样我们就成功将流量路由到服务的某一个版本上了。

原理分析

🍀

前面章节中我们只定义了一个名为 bookinfoVirtualService 资源对象就可以正常访问了:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: bookinfo
  namespace: default
spec:
  gateways:
    - bookinfo-gateway
  hosts:
    - "*"
  http:
    - match:
        - uri:
            exact: /productpage
        - uri:
            prefix: /static
        - uri:
            exact: /login
        - uri:
            exact: /logout
        - uri:
            prefix: /api/v1/products
      route:
        - destination:
            host: productpage
            port:
              number: 9080

很明显上面这个虚拟服务对象是我们访问 Bookinfo 应用的入口路由规则,所以这个虚拟服务对象实际上是为 istio-ingressgateway 入口网关服务定义的。 它将所有的流量都路由到了 productpage 这个服务上,而 productpage 这个服务又会去调用其他的服务来获取数据,在 productpage 服务中调用其他微服务 其实就是直接通过服务名称来调用的,比如调用 reviews 服务就是直接通过 reviews:9080 这个服务来调用的,我们可以查看 productpage 的代码来验证这一点:

img

🍀

我们可以再次查看 Bookinfo 在网格内的请求架构图:

img

当我们在浏览器中访问 http://<gateway url>/productpage 时,请求将进入网格中的 istio-ingressgateway 服务,然后将请求转发到 productpage 服务。productpage 服务将调用 reviewsdetails 服务来填充页面的内容,然后将其返回给用户。(reviews 服务包括 3 个不同版本的应用,可以通过 version 标签区分)

🍀

现在我们只想将流量路由到 reviews:v1 版本去,按照传统的方法只需要将 reviews 的 Service 对象去强制关联 version: v1 这个标签即可,现在我们所有的服务都被注入了一个 Envoy 的 Sidecar 代理,通过 Envoy 很容易就可以实现这个路由功能,而相应的在 Istio 中我们只需要通过 VirtualServiceDestinationRule 这两个资源对象就可以来实现了。上面我们创建的关于 reviews 服务的这两个对象如下所示:

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: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2
    - name: v3
      labels:
        version: v3

那么这两个对象是如何来影响 Envoy Sidecar 的呢?前面我们已经分析了流量从 istio-ingressgateway 进来后被路由到了 productpage 服务,那么 productpage 又该如何去访问其他微服务呢?同样我们可以使用 istioctl proxy-config 来查看 productpage 服务的 Envoy 配置。

🍀

每个 Envoy Sidecar 都有一个绑定到 0.0.0.0:15001 的监听器,然后利用 IP tables 将 pod 的所有入站和出站流量路由到这里,此监听器会配置一个 useOriginalDst: true,这意味着它将请求交给最符合请求原始目标的监听器。如果找不到任何匹配的虚拟监听器,它会将请求发送给返回 404 的 BlackHoleCluster,我们可以查看下 15001 端口的监听器配置:

[root@master1 istio-1.19.3]#istioctl proxy-config listeners productpage-v1-564d4686f-7vhks --port 15001 -oyaml
- accessLog:
  - filter:
      responseFlagFilter:
        flags:
        - NR
    name: envoy.access_loggers.file
    typedConfig:
      '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
      logFormat:
        textFormatSource:
          inlineString: |
            [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %RESPONSE_CODE_DETAILS% %CONNECTION_TERMINATION_DETAILS% "%UPSTREAM_TRANSPORT_FAILURE_REASON%" %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%" %UPSTREAM_CLUSTER% %UPSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_REMOTE_ADDRESS% %REQUESTED_SERVER_NAME% %ROUTE_NAME%
      path: /dev/stdout
  address:
    socketAddress:
      address: 0.0.0.0
      portValue: 15001
  filterChains:
  - filterChainMatch:
      destinationPort: 15001
    filters:
    - name: istio.stats
      typedConfig:
        '@type': type.googleapis.com/stats.PluginConfig
    - name: envoy.filters.network.tcp_proxy
      typedConfig:
        '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
        cluster: BlackHoleCluster
        statPrefix: BlackHoleCluster
    name: virtualOutbound-blackhole
  - filters:
    - name: istio.stats
      typedConfig:
        '@type': type.googleapis.com/stats.PluginConfig
    - name: envoy.filters.network.tcp_proxy
      typedConfig:
        '@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
        accessLog:
        - name: envoy.access_loggers.file
          typedConfig:
            '@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
            logFormat:
              textFormatSource:
                inlineString: |
                  [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %RESPONSE_CODE_DETAILS% %CONNECTION_TERMINATION_DETAILS% "%UPSTREAM_TRANSPORT_FAILURE_REASON%" %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%" %UPSTREAM_CLUSTER% %UPSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_REMOTE_ADDRESS% %REQUESTED_SERVER_NAME% %ROUTE_NAME%
            path: /dev/stdout
        cluster: PassthroughCluster
        statPrefix: PassthroughCluster
    name: virtualOutbound-catchall-tcp
  name: virtualOutbound
  trafficDirection: OUTBOUND
  useOriginalDst: true

[root@master1 istio-1.19.3]#

🍀

实际上我们的请求是到 9080 端口(productpage 服务绑定 9080 端口)的 HTTP 出站请求,这意味着它被切换到 0.0.0.0:9080 虚拟监听器。所以我们查看下 9080 端口的监听器配置:

# productpage 默认访问其他服务的 9080 端口
$ istioctl proxy-config listeners productpage-v1-564d4686f-wwqqf --port 9080 -oyaml
- address:
    socketAddress:
      address: 0.0.0.0
      portValue: 9080
  # ......
        rds:
          configSource:
            ads: {}
            initialFetchTimeout: 0s
            resourceApiVersion: V3
          routeConfigName: "9080"  # RDS的路由配置名称
  # ......
  name: 0.0.0.0_9080
  trafficDirection: OUTBOUND  # 出流量

可以看到此监听器在其配置的 RDS 中查找名为 9080 的路由配置,我们可以使用 istioctl proxy-config routes 命令来查看这个路由配置的详细信息:

# 查看 9080 这个路由配置
$ istioctl proxy-config routes productpage-v1-564d4686f-wwqqf --name 9080 -oyaml
- name: "9080"
  virtualHosts:
  - domains:
    - details.default.svc.cluster.local
    - details
    - details.default.svc
    - details.default
    - 10.111.83.224
    name: details.default.svc.cluster.local:9080
    routes:
    - decorator:
        operation: details.default.svc.cluster.local:9080/*
      match:
        prefix: /
      metadata:
        filterMetadata:
          istio:
            config: /apis/networking.istio.io/v1alpha3/namespaces/default/virtual-service/details
      route:
        cluster: outbound|9080|v1|details.default.svc.cluster.local
        # ......
  - domains:
    - productpage.default.svc.cluster.local
    - productpage
    - productpage.default.svc
    - productpage.default
    - 10.97.120.23
    name: productpage.default.svc.cluster.local:9080
    routes:
    - decorator:
        operation: productpage.default.svc.cluster.local:9080/*
      match:
        prefix: /
      name: default
      route:
        cluster: outbound|9080||productpage.default.svc.cluster.local
        # ......
  - domains:
    - ratings.default.svc.cluster.local
    - ratings
    - ratings.default.svc
    - ratings.default
    - 10.101.184.235
    name: ratings.default.svc.cluster.local:9080
    routes:
    - decorator:
        operation: ratings.default.svc.cluster.local:9080/*
      match:
        prefix: /
      metadata:
        filterMetadata:
          istio:
            config: /apis/networking.istio.io/v1alpha3/namespaces/default/virtual-service/ratings
      route:
        cluster: outbound|9080|v1|ratings.default.svc.cluster.local
        # ......
  - domains:
    - reviews.default.svc.cluster.local
    - reviews
    - reviews.default.svc
    - reviews.default
    - 10.97.120.56
    name: reviews.default.svc.cluster.local:9080
    routes:
    - decorator:
        operation: reviews.default.svc.cluster.local:9080/*
      match:
        prefix: /
      metadata:
        filterMetadata:
          istio:
            config: /apis/networking.istio.io/v1alpha3/namespaces/default/virtual-service/reviews
      route:
        cluster: outbound|9080|v1|reviews.default.svc.cluster.local
        # ......
  - domains:
    - '*'
    name: allow_any
    routes:
    - match:
        prefix: /
      name: allow_any
      route:
        cluster: PassthroughCluster
        # ......

这个路由配置中其实包含了 K8s Service 对象中监听 9080 端口的所有服务,如果没有创建对应的 VirtualService 对象,对应的路由配置就没有 metadata.filterMetadata.istio.config 这个属性。比如现在我们正在通过 productpage 请求前往 reviews 服务,因此 Envoy 将选择我们的请求与域匹配的虚拟主机。一旦在域上匹配,Envoy 会查找与请求匹配的第一条路径,我们这里没有任何高级路由,因此只有一条路由匹配所有内容。这条路由告诉 Envoy 将请求发送到 outbound|9080|v1|reviews.default.svc.cluster.local 集群,因为前面我们创建的 reviews 这个 VirtualService 对象配置了的 destination.subset: v1,所以这里的集群命名上多了一个 subset

需要注意的是我们在 VirtualService 对象里面配置了 destination.subset: v1,那么必须要有对应的 subset 存在才行,否则不会生成对应的 Envoy 集群配置,那么就不能正常访问该服务了,而该 subset 就是通过前面的 DestinationRule 对象来定义的,现在我们就可以来查看这个集群配置了:

$ istioctl proxy-config cluster productpage-v1-564d4686f-wwqqf --fqdn reviews.default.svc.cluster.local -o yaml
- edsClusterConfig:
    edsConfig:
      ads: {}
      initialFetchTimeout: 0s
      resourceApiVersion: V3
    serviceName: outbound|9080||reviews.default.svc.cluster.local
  lbPolicy: LEAST_REQUEST
  metadata:
    filterMetadata:
      istio:
        config: /apis/networking.istio.io/v1alpha3/namespaces/default/destination-rule/reviews
        services:
        - host: reviews.default.svc.cluster.local
          name: reviews
          namespace: default
  # ......
  name: outbound|9080||reviews.default.svc.cluster.local
  type: EDS
- edsClusterConfig:
    edsConfig:
      ads: {}
      initialFetchTimeout: 0s
      resourceApiVersion: V3
    serviceName: outbound|9080|v1|reviews.default.svc.cluster.local
  lbPolicy: LEAST_REQUEST
  metadata:
    filterMetadata:
      istio:
        config: /apis/networking.istio.io/v1alpha3/namespaces/default/destination-rule/reviews
        services:
        - host: reviews.default.svc.cluster.local
          name: reviews
          namespace: default
        subset: v1
  name: outbound|9080|v1|reviews.default.svc.cluster.local
  # ......
  type: EDS
- edsClusterConfig:
    edsConfig:
      ads: {}
      initialFetchTimeout: 0s
      resourceApiVersion: V3
    serviceName: outbound|9080|v2|reviews.default.svc.cluster.local
  filters:
  - name: istio.metadata_exchange
    typedConfig:
      '@type': type.googleapis.com/envoy.tcp.metadataexchange.config.MetadataExchange
      protocol: istio-peer-exchange
  lbPolicy: LEAST_REQUEST
  metadata:
    filterMetadata:
      istio:
        config: /apis/networking.istio.io/v1alpha3/namespaces/default/destination-rule/reviews
        services:
        - host: reviews.default.svc.cluster.local
          name: reviews
          namespace: default
        subset: v2
  name: outbound|9080|v2|reviews.default.svc.cluster.local
  # ......
  type: EDS
- edsClusterConfig:
    edsConfig:
      ads: {}
      initialFetchTimeout: 0s
      resourceApiVersion: V3
    serviceName: outbound|9080|v3|reviews.default.svc.cluster.local
  filters:
  - name: istio.metadata_exchange
    typedConfig:
      '@type': type.googleapis.com/envoy.tcp.metadataexchange.config.MetadataExchange
      protocol: istio-peer-exchange
  lbPolicy: LEAST_REQUEST
  metadata:
    filterMetadata:
      istio:
        config: /apis/networking.istio.io/v1alpha3/namespaces/default/destination-rule/reviews
        services:
        - host: reviews.default.svc.cluster.local
          name: reviews
          namespace: default
        subset: v3
  name: outbound|9080|v3|reviews.default.svc.cluster.local
  # ......
  type: EDS

从上面配置可以看到里面一共包含了 4 个 reviews 相关的集群,一个是原始的不包含 subset 的,而另外三个就是前面我们在 DestinationRule 对象中配置的 3 个 subset,所以其实 DestinationRule 映射到 Envoy 的配置文件中就是 Cluster

🍀

最后我们同样还可以查看每个集群下面包含的 endpoint 有哪些:

$ istioctl proxy-config endpoint productpage-v1-564d4686f-wwqqf --cluster "outbound|9080||reviews.default.svc.cluster.local" -o yaml
- edsServiceName: outbound|9080||reviews.default.svc.cluster.local
  - address:
      socketAddress:
        address: 10.244.2.84
        portValue: 9080
    # ......
    weight: 1
  - address:
      socketAddress:
        address: 10.244.2.83
        portValue: 9080
    # ......
    weight: 1
  - address:
      socketAddress:
        address: 10.244.2.88
        portValue: 9080
    # ......
    weight: 1
  name: outbound|9080||reviews.default.svc.cluster.local
  observabilityName: outbound|9080||reviews.default.svc.cluster.local

$ istioctl proxy-config endpoint productpage-v1-564d4686f-wwqqf --cluster "outbound|9080|v1|reviews.default.svc.cluster.local" -o yaml
- edsServiceName: outbound|9080|v1|reviews.default.svc.cluster.local
  hostStatuses:
  - address:
      socketAddress:
        address: 10.244.2.84
        portValue: 9080
    weight: 1
  name: outbound|9080|v1|reviews.default.svc.cluster.local
  observabilityName: outbound|9080|v1|reviews.default.svc.cluster.local

# 过滤 version=v1 的 reviews pod
$ kubectl get pod -l app=reviews,version=v1 -o wide
NAME                          READY   STATUS    RESTARTS        AGE     IP            NODE    NOMINATED NODE   READINESS GATES
reviews-v1-86896b7648-zjh2n   2/2     Running   4 (5h18m ago)   6d17h   10.244.2.84   node2   <none>           <none>

可以看到不包含 subset 的集群下面的 endpoint 其实就是 reviews 这个 Service 对象的 endpoint 集合,包含 subset 就只有和该子集匹配的后端实例了。到了这一步,一切皆明了,后面的事情就跟之前的套路一样了,具体的 Endpoint 对应打了标签 version=v1 的 Pod。

🍀

到这里我们是不是就实现了通过 VirtualServiceDestinationRule 对象将流量路由到了指定的版本上面了,上面的整个过程就是请求从 productpage 到 reviews 的过程,从 reviews 到网格内其他应用的流量与上面类似,就不展开讨论了。

2.基于用户身份的路由

🚩 实战:基于用户身份的路由-2023.11.11(测试成功)

实验环境:

k8s v1.27.6(containerd://1.6.20)(cni:flannel:v0.22.2)

[root@master1 ~]#istioctl version
client version: 1.19.3
control plane version: 1.19.3
data plane version: 1.19.3 (8 proxies)

实验软件:

链接:https://pan.baidu.com/s/1pMnJxgL63oTlGFlhrfnXsA?pwd=7yqb
提取码:7yqb
2023.11.5-实战:BookInfo 示例应用-2023.11.5(测试成功) --本节测试yaml在此目录里

image-20231105111842627

实验步骤:

image-20231111150647965

graph LR
	A[实战步骤] -->B(1️⃣ 更新VirtualService)
	A[实战步骤] -->C(2️⃣ 测试)

接下来我们继续更改路由配置,将来自特定用户的所有流量路由到特定服务版本。我们这里将配置来自名为 Jason 的用户的所有流量被路由到服务 reviews:v2

注意 Istio 对用户身份没有任何特殊的内置机制,productpage 服务在所有到 reviews 服务的 HTTP 请求中都增加了一个自定义的 end-user 请求头来实现该效果:headers['end-user'] = session['user']

🍀

要实现该功能,只需要创建下面的资源对象即可:

$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
virtualservice.networking.istio.io/reviews configured

该资源清单文件创建了一个如下所示的 VirtualService 资源对象:

# virtual-service-reviews-test-v2.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

该对象设置了一条路由规则,它会根据 productpage 服务发起的请求的 end-user 自定义请求头内容进行匹配,如果有该内容且为 jason 则会将流量路由到 reviews 服务的 v2 版本,其余的还是被路由到 v1 版本去。

🍀

现在我们可以前往浏览器访问 Bookinfo 应用,多刷新几次可以看到评论始终访问到的是 v1 版本的服务,即没有星标的:

img

🍀

然后我们点击页面右上角的 Sign in 按钮,使用 jason 进行登录,登录后页面就会出现带有黑色星标的 v2 版本的评论服务,即使多刷新几次依然如此:

img

如果我们选择使用其他用户进行登录或者注销则星标就会消失,这是因为除了 Jason 之外,所有用户的流量都被路由到 reviews:v1

🍀

同样的我们可以去查看下对应的 Envoy Sidecar 配置的变化,因为这里我们只更新了一个 VirtualService 对象,所以只会对 Envoy 的路由表产生影响,查看对应的路由配置即可:

$ istioctl proxy-config routes productpage-v1-564d4686f-wwqqf --name 9080 -oyaml
- name: "9080"
  validateClusters: false
  virtualHosts:
  # ......
  - domains:
    - reviews.default.svc.cluster.local
    - reviews
    - reviews.default.svc
    - reviews.default
    - 10.97.120.56
    includeRequestAttemptCount: true
    name: reviews.default.svc.cluster.local:9080
    routes:
    - decorator:
        operation: reviews.default.svc.cluster.local:9080/*
      match:
        caseSensitive: true
        headers:
        - name: end-user
          stringMatch:
            exact: jason
        prefix: /
      metadata:
        filterMetadata:
          istio:
            config: /apis/networking.istio.io/v1alpha3/namespaces/default/virtual-service/reviews
      route:
        cluster: outbound|9080|v2|reviews.default.svc.cluster.local
        maxGrpcTimeout: 0s
        # ......
    - decorator:
        operation: reviews.default.svc.cluster.local:9080/*
      match:
        prefix: /
      metadata:
        filterMetadata:
          istio:
            config: /apis/networking.istio.io/v1alpha3/namespaces/default/virtual-service/reviews
      route:
        cluster: outbound|9080|v1|reviews.default.svc.cluster.local
        maxGrpcTimeout: 0s
        # ......

从配置上我们可以看到现在的 Envoy 配置中新增了一条路由规则,如下所示:

match:
  caseSensitive: true
  headers:
    - name: end-user
      stringMatch:
        exact: jason
  prefix: /
route:
  cluster: outbound|9080|v2|reviews.default.svc.cluster.local

当请求头中包含 end-user:jason 的时候请求会被路由到 outbound|9080|v2|reviews.default.svc.cluster.local 这个 Envoy Cluster 集群,这个集群就是前面我们通过 DestinationRule 创建的 v2 这个子集,所以最后请求会被路由到带有黑色星标的评论服务去。

img

🍀

到这里我们就明白了要通过 Istio 实现服务的流量管理,需要用到 GatewayVirtualServiceDestinationRule 三个 CRD 对象,这些对象其实最终都是去拼凑 Envoy 的配置,每个对象管理 Envoy 配置的一部分,把这个关系搞清楚我们就能更好的掌握 Istio 的使用了。

关于我

我的博客主旨:

  • 排版美观,语言精炼;
  • 文档即手册,步骤明细,拒绝埋坑,提供源码;
  • 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!

🍀 微信二维码
x2675263825 (舍得), qq:2675263825。

image-20230107215114763

🍀 微信公众号
《云原生架构师实战》

image-20230107215126971

🍀 个人博客站点

http://onedayxyy.cn/

image-20231106071817374

🍀 语雀

https://www.yuque.com/xyy-onlyone

image-20231106071948492

🍀 csdn

https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

image-20230107215149885

🍀 知乎

https://www.zhihu.com/people/foryouone

image-20230107215203185

最后

好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!

image-20231016062113861

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1196421.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

14 # 手写 debounce 防抖方法

什么是防抖 防抖: n 秒后再去执行该事件&#xff0c;若在 n 秒内被重复触发&#xff0c;则重新计时&#xff0c;这个效果跟英雄联盟里的回城技能差不多。 本质上是优化高频率执行代码的一种手段&#xff0c;目的就是降低回调执行频率、节省计算资源。 应用场景&#xff1a; …

基于subversion1.6.3动态库实现简单版本管理

基于subversion1.6.3动态库实现简单版本管理 一、运行环境 windows10 64位系统 VS2015、C Subversion1.6.3 二、功能设计与实现 1、需求背景 编码自动化版本部署、发布验证&#xff1b; svn cli命令行能满足基本功能&#xff0c;但是动作执行是否成功的判断不可靠&#…

GPU CUDA 使用shared memory 运行速度不升反降原因与解决方案

写了两张图像相加&#xff0c;以及图像滤波的的几个算子&#xff0c;分别采用shared memory 进行优化。 #include <stdio.h> #include <cuda_runtime.h>#include "helper_cuda.h" #include "helper_timer.h"#define BLOCKX 32 #define BLOCKY…

【C语言 | 预处理】C语言预处理详解(三)——内存对齐、手把手带你计算结构体大小

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

2023年加氢工艺证考试题库及加氢工艺试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年加氢工艺证考试题库及加氢工艺试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大纲随机出的加氢…

DDU框架学习之路

目录 MVVM对比 DDU 数据消费者UI 数据的转换者&#xff1a;Domain Layer 数据图生产者/提供者 DataLayer 遵循原理&#xff1a; 单一数据流&#xff1a; Android官方推荐架构&#xff1a;DDU MVVM对比 M&#xff1a;Model 网络层 用于获取远端数据 VM:ViewModel 中间转…

【Shell脚本9】Shell test 命令

Shell test 命令 Shell中的 test 命令用于检查某个条件是否成立&#xff0c;它可以进行数值、字符和文件三个方面的测试。 数值测试 num1100 num2100 if test $[num1] -eq $[num2] thenecho 两个数相等&#xff01; elseecho 两个数不相等&#xff01; fi输出结果&#xff1a…

关于Android Studio 同步Gradle失败的解决方案

&#xff08;1&#xff09;打开Android Studio的Settings找到Gradle的目录 &#xff08;2&#xff09;打开本地文件目录&#xff0c;找到对应的gradle版本&#xff0c;可以通过Index of /gradle/ 下载gradle压缩包。把目录中gradle-7.0.2-bin\一堆字符\ 下 的.lck 和.part文…

Oracle(16)Managing Privileges

目录 一、基础知识 1、Managing Privileges管理权限 2、System Privileges 系统特权 3、System Privileges : Example系统权限&#xff1a;示例 4、Who Can Grant or Revoke? 谁可以授予或撤销权限&#xff1f; 5、The PUBLIC 6、SYSDBA and SYSOPER 7、Revoke with A…

KT6368A蓝牙芯片的出现部分芯片距离短换芯片就好是什么问题呢

一、简介 KT6368A蓝牙芯片的出现部分芯片距离短&#xff0c;换一个芯片距离就好了&#xff0c;是什么问题呢&#xff1f;生产2K的样子 详细说明 按照我们出货客户的跟踪情况&#xff0c;这种问题&#xff0c;可能性极低因为芯片本身的不良率&#xff0c;目前是控制在千分之三…

js 求数组中的对象某个属性和

可以直接看下效果 代码&#xff1a; <script>let list [{num: 1,price: 10,},{num: 2,price: 10,},{num: 3,price: 10,},{num: 4,price: 10,},]// for循环 求总数和 num的和let num 0for (let i 0; i < list.length; i) {num list[i].num}console.log(第一种&am…

深度学习 python opencv 火焰检测识别 计算机竞赛

文章目录 0 前言1 基于YOLO的火焰检测与识别2 课题背景3 卷积神经网络3.1 卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV54.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 数据集准备5.1 数…

《红蓝攻防对抗实战》九.内网穿透之利用GRE协议进行隧道穿透

​ 前文推荐&#xff1a; 《红蓝攻防对抗实战》一. 隧道穿透技术详解 《红蓝攻防对抗实战》二.内网探测协议出网之TCP/UDP协议探测出网 《红蓝攻防对抗实战》三.内网探测协议出网之HTTP/HTTPS协议探测出网 《红蓝攻防对抗实战》四.内网探测协议出网之ICMP协议探测出网 《红蓝…

AI:86-基于深度学习的人体姿态估计与运动分析

🚀 本文选自专栏:人工智能领域200例教程专栏 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的代码,详细讲解供大家学习,希望可以帮到大家。欢迎订阅支持,正在不断更新中,…

数据结构线性表——带头双向循环链表

前言&#xff1a;小伙伴们好久不见啦&#xff0c;上篇文章我们一起学习了数据结构线性表其一的单链表&#xff0c;了解了单链表的不少好处&#xff0c;但是不可能有完美的数据结构&#xff0c;就算是单链表&#xff0c;也会有很多缺点。 那么今天这篇文章&#xff0c;我们就来…

全网最细,Apipost接口自动化测试-关联配置,老鸟带你上高速...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 在接口自动化测试…

Arduino到底适不适合做产品

文章目录 一、Arduino性能很低&#xff0c;不如树莓派等开发板&#xff0c;所以不要用Arduino做开发二、Arduino程序效率很低&#xff0c;所以不要用Arduino做开发三、Arduino只能开发玩具&#xff0c;不能做产品四、Arduino开发板成本太高&#xff0c;不适合做产品总结个人见解…

iPhone或在2024开放第三方应用商店。

iPhone或开放第三方应用商店&#xff0c;可以说这是一个老生常谈的话题。对于像是iOS这样封闭的系统来说&#xff0c;此前传出苹果可能开放侧载消息的时候&#xff0c;又有谁能信&#xff0c;谁会信&#xff1f; 如果是按照苹果自身的意愿&#xff0c;这种事情自然是不可能发生…

【LeetCode笔试题】88.合并两个有序数组

问题描述 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中&#xff0c;使合并后的数组同样按 非递减顺序 排列。 注意&#xff1a;最终&#xff0c;合…

王学岗visibility改变后调用onLayout()

自定义控件的时候发现了一个bug。 Button位移动画执行结束后我设置了一个不相关的TextView的可见性由gone变为visible.令人郁闷的是&#xff0c;只要我注释的地方放开。动画执行结束后button都会重新绘制在位移动画开始的位置。注释掉这段代码就正常。 经过分析后得知 View的Vi…