阿里云服务网格ASM的流量标签及路由功能之(4): 基于ASM实现全链路灰度发布

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 当您需要在多个服务间实现全链路的灰度发布时,可以通过配置TrafficLabel来识别流量特征,将网关入口流量分为正常流量和灰度流量。灰度流量特征会在请求调用链经过的各个服务间进行传递,从而实现全链路灰度发布。本文介绍如何通过TrafficLabel能力来实现微服务的全链路灰度发布。

当您需要在多个服务间实现全链路的灰度发布时,可以通过配置TrafficLabel来识别流量特征,将网关入口流量分为正常流量和灰度流量。灰度流量特征会在请求调用链经过的各个服务间进行传递,从而实现全链路灰度发布。本文介绍如何通过TrafficLabel能力来实现微服务的全链路灰度发布。

前提条件

背景信息

灰度发布有多种实现方式,例如基于ASM完成蓝绿和灰度发布。该灰度方式偏重于单个服务的发布,通过使用Istio原生提供的VirtualService标签路由和权重分流进行实现。
某些场景下,仅限于两个服务间的灰度不能满足需求,例如多个服务同时发布了灰度版本。这种情况下对业务进行功能灰度验证:入口流量分为正常流量和灰度流量。通常情况下, 可以针对请求流量做流量特征识别,若是灰度流量则需要请求灰度的应用服务。该场景不再是简单的按流量比例灰度分发到后端不同的版本,而且灰度流量特征会在请求调用链经过的各个服务间进行传递。
ASM全链路灰度功能基于流量打标和标签路由功能。更多信息,请参见流量打标和标签路由

示例介绍

您可以单击文件,直接下载示例部署及相关配置文件。
示例中应用服务调用链路如下:

image.png

本示例服务中的应用A在调用B时, 已经包括了传播HTTP标头my-request-id的代码实现逻辑, 具体可以参见代码文件src/mock-abc/go/main.go。

**注意: 如果使用其他的应用示例, 务必确保在调用中包括传播HTTP标头的逻辑, 后续的功能依赖于这个传播的HTTP标头。

应用Base版本对应的部署文件application-base.yaml如下:

apiVersion: v1
kind: Service
metadata:
  name: mocka
  labels:
    app: mocka
    service: mocka
spec:
  ports:
  - port: 8000
    name: http
  selector:
    app: mocka
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mocka-base
  labels:
    app: mocka
    version: base
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mocka
      version: base
  template:
    metadata:
      labels:
        app: mocka
        version: base
    spec:
      containers:
      - name: default
        image: registry.cn-beijing.aliyuncs.com/aliacs-app-catalog/go-http-sample:1.0
        imagePullPolicy: Always
        env:
        - name: version
          value: base
        - name: app
          value: mocka
        - name: upstream_url
          value: "http://mockb:8000/"
        ports:
        - containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: mockb
  labels:
    app: mockb
    service: mockb
spec:
  ports:
  - port: 8000
    name: http
  selector:
    app: mockb
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mockb-base
  labels:
    app: mockb
    version: base
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mockb
      version: base
  template:
    metadata:
      labels:
        app: mockb
        version: base
    spec:
      containers:
      - name: default
        image: registry.cn-beijing.aliyuncs.com/aliacs-app-catalog/go-http-sample:1.0
        imagePullPolicy: Always
        env:
        - name: version
          value: base
        - name: app
          value: mockb
        ports:
        - containerPort: 8000

应用Canary版本对应的部署文件application-canary.yaml如下:

apiVersion: v1
kind: Service
metadata:
  name: mocka
  labels:
    app: mocka
    service: mocka
spec:
  ports:
  - port: 8000
    name: http
  selector:
    app: mocka
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mocka-canary
  labels:
    app: mocka
    version: canary
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mocka
      version: canary
  template:
    metadata:
      labels:
        app: mocka
        version: canary
    spec:
      containers:
      - name: default
        image: registry.cn-beijing.aliyuncs.com/aliacs-app-catalog/go-http-sample:1.0
        imagePullPolicy: Always
        env:
        - name: version
          value: canary
        - name: app
          value: mocka
        - name: upstream_url
          value: "http://mockb:8000/"
        ports:
        - containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: mockb
  labels:
    app: mockb
    service: mockb
spec:
  ports:
  - port: 8000
    name: http
  selector:
    app: mockb
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mockb-canary
  labels:
    app: mockb
    version: canary
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mockb
      version: canary
  template:
    metadata:
      labels:
        app: mockb
        version: canary
    spec:
      containers:
      - name: default
        image: registry.cn-beijing.aliyuncs.com/aliacs-app-catalog/go-http-sample:1.0
        imagePullPolicy: Always
        env:
        - name: version
          value: canary
        - name: app
          value: mockb
        ports:
        - containerPort: 8000

步骤一:在ACK集群下部署示例应用

在指定的命名空间下创建部署示例应用, 例如指定命名空间default。 确认该命名空间已经开启自动注入, 具体可以参见https://help.aliyun.com/document_detail/150501.html?spm=a2c4g.377563.0.0.54fb6de6GSrl08#section-30o-vil-3n7

使用ACK集群的kubeconfig执行以下命令,部署示例应用:

kubectl apply -n default -f application-base.yaml
kubectl apply -n default -f application-canary.yaml

步骤二:初始化路由规则配置

使用以下内容,创建名为routing.yaml的文件。

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: simple-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - hosts:
        - "*"
      port:
        name: http
        number: 80
        protocol: HTTP
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: dr-mocka
spec:
  host: mocka
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
  subsets:
    - labels:
        version: base
      name: version-base
    - labels:
        version: canary
      name: version-canary
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: dr-mockb
spec:
  host: mockb
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
  subsets:
    - labels:
        version: base
      name: version-base
    - labels:
        version: canary
      name: version-canary
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vs-gateway-mocka
spec:
  gateways:
  - simple-gateway
  hosts:
    - "*"
  http:
  - route:
      - destination:
          host: mocka
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vs-mockb
spec:
  hosts:
    - mockb
  http:
    - route:
        - destination:
            host: mockb

使用ASM实例的kubeconfig执行以下命令,配置路由。

kubectl apply -n default -f routing.yaml

验证服务访问是否可以连通。

  1. 通过ASM控制台获取网关的公网IP,执行以下命令。
    export ASM_GATEWAY_IP=xxx.xxx.xxx.xxx
    
    执行以下命令,验证服务访问是否可以连通。
    for i in {
         
         1..200};  do curl   -H'my-asm-prefer-tag: version-base'  -H'my-request-id: x000'{
         
         mathJaxContainer[0]}{
         
         ASM_GATEWAY_IP}/; echo; sleep 1; done;
    
    预期输出:
    -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70)
    -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70)
    -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: canary, ip: 172.17.0.54)
    -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: canary, ip: 172.17.0.54)
    -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70)
    -> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70)
    -> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: canary, ip: 172.17.0.54)
    
    可以看到, 从ASM入口网关到应用服务A, 以及从应用A调用B的过程, 负载均衡是随机的路由策略。 通过curl命令指定的my-asm-prefer-tag或者其他请求头都不会改变随机路由的策略。

步骤三:为示例应用设置流量标签

ASM支持通过TrafficLabel CRD设置流量标签,然后根据流量标签将流量路由到不同的工作负载, 具体定义参考:https://help.aliyun.com/document_detail/375313.html

1)使用以下内容,创建文件trafficlabel.yaml。

注意:

  • 本示例中用于区分版本的请求头为my-asm-prefer-tag, 因此getExternalInboundRequestHeader中的第一个参数也相应地设置为my-asm-prefer-tag。实际使用中, 用户可以自行设置为其他值。
  • 本示例中传播的HTTP标头为my-request-id,因此getExternalInboundRequestHeader中的第二个参数也相应地设置为my-request-id。
apiVersion: istio.alibabacloud.com/v1
kind: TrafficLabel
metadata:
  name: trafficlabel-ns
  namespace: default
spec:
  rules:
  - labels:
    - name: asm-labels-sample
      valueFrom:
      - $getExternalInboundRequestHeader(my-asm-prefer-tag, my-request-id)
---
apiVersion: istio.alibabacloud.com/v1
kind: TrafficLabel
metadata:
  name: ingressgateway
  namespace: istio-system
spec:
  rules:
  - labels:
    - name: asm-labels-sample
      valueFrom:
      - $getInboundRequestHeader(my-asm-prefer-tag)
  workloadSelector:
    labels:
      istio: ingressgateway

2)执行以下命令,使用ASM实例的kubeconfig进行部署。

kubectl apply -f trafficlabel.yaml

上述定义的TrafficLabel trafficlabel-ns针对命名空间default下所有的应用服务生效,也就是示例中部署的mocka和mockb。同时定义的TrafficLabel ingressgateway则是对网关ingressgateway生效。

步骤四:定义标签路由规则

1. 验证服务提供侧的灰度

首先验证应用A→B的调用是否符合预期,其中包括流向A的灰度流量打到灰度版本,以及Base流量打到Base版本。
配置应用B的基于流量标签的路由规则,生效的效果对应如下:
image.png

1)使用以下内容,创建文件vs-tf-mockb.yaml。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vs-mockb
spec:
  hosts:
    - mockb
  http:
    - route:
        - destination:
            host: mockb
            subset: $asm-labels-sample

2) 执行以下命令,在A服务侧生效。

kubectl apply -n default -f vs-tf-mockb.yaml

3) 执行以下命令,验证流向A的灰度流量打到灰度版本。

for i in {
   
   1..200};  do curl -H'my-asm-prefer-tag: version-canary'  -H'my-request-id: x000'{
   
   mathJaxContainer[1]}{
   
   ASM_GATEWAY_IP}/; echo; sleep 1; done;

预期输出:

-> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: canary, ip: 172.17.0.54)
-> mocka(version: base, ip: 172.17.0.132)-> mockb(version: canary, ip: 172.17.0.54)
-> mocka(version: base, ip: 172.17.0.132)-> mockb(version: canary, ip: 172.17.0.54)
-> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: canary, ip: 172.17.0.54)
-> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: canary, ip: 172.17.0.54)
-> mocka(version: base, ip: 172.17.0.132)-> mockb(version: canary, ip: 172.17.0.54)

4) 执行以下命令,验证流向A的Base流量打到Base版本。

for i in {
   
   1..200};  do curl -H'my-asm-prefer-tag: version-base'  -H'my-request-id: x000'{
   
   mathJaxContainer[2]}{
   
   ASM_GATEWAY_IP}/; echo; sleep 1; done;

预期输出:

-> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70)
-> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70)
-> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70)
-> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70)
-> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70)
-> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70)
-> mocka(version: canary, ip: 172.17.0.129)-> mockb(version: base, ip: 172.17.0.70)
-> mocka(version: base, ip: 172.17.0.132)-> mockb(version: base, ip: 172.17.0.70)

说明 此时, 入口流量访问A服务并未流转到指定版本,需要再配置A服务的基于流量标签的路由规则, 下一步将进行配置。

  1. 验证全链路灰度
    配置A服务的TrafficLabel路由vs-tf-mocka.yaml,在ASM网关侧生效。预期结果为入口请求灰度流量打到A的灰度版本,Base流量打到A的Base版本,并传递到B服务。

配置应用A的基于流量标签的路由规则之后,生效的效果对应如下:
image.png

1) 使用以下示例,创建文件vs-tf-mocka.yaml。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vs-gateway-mocka
spec:
  gateways:
  - simple-gateway
  hosts:
    - "*"
  http:
  - route:
      - destination:
          host: mocka
          subset: $asm-labels-sample

2) 执行以下命令,在ASM网关侧生效。

kubectl apply -n default -f vs-tf-mocka.yaml

3) 执行以下命令,验证入口请求灰度流量打到A的灰度版本。

for i in {
   
   1..200};  do curl -H'my-asm-prefer-tag: version-canary'  -H'my-request-id: x000'{
   
   mathJaxContainer[3]}{
   
   ASM_GATEWAY_IP}/; echo; sleep 1; done;

预期输出:

-> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130)

4) 执行以下命令,验证Base流量打到A的Base版本,并传递到B服务。

for i in {
   
   1..200};  do curl -H'my-asm-prefer-tag: version-base'  -H'my-request-id: x000'{
   
   mathJaxContainer[4]}{
   
   ASM_GATEWAY_IP}/; echo; sleep 1; done;

预期输出:

-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)

3. 验证路由权重

当在应用A上配置了基于权重与基于流量标签的路由规则之后,生效的效果对应如下:
image.png

1) 使用以下示例,创建文件vs-tf-mocka-90-10.yaml。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: vs-gateway-mocka
spec:
  gateways:
  - simple-gateway
  hosts:
    - "*"
  http:
  - route:
      - destination:
          host: mocka
          subset: version-base
        weight: 90
      - destination:
          host: mocka
          subset: $asm-labels-sample
        weight: 10

2) 执行以下命令,在ASM网关侧生效。

kubectl apply -n default -f vs-tf-mocka-90-10.yaml

3) 执行以下命令,验证入口请求灰度流量打到应用A的版本。

for i in {
   
   1..200};  do curl -H'my-asm-prefer-tag: version-canary'  -H'my-request-id: x000'{
   
   mathJaxContainer[5]}{
   
   ASM_GATEWAY_IP}/; echo; sleep 1; done;

可以通过执行结果看到, 入口请求灰度流量大约90%左右流向了应用A的Base版本, 10%左右则是流向到了Canary版本。这样因为上述生效的路由规则中, 90%的请求进入应用A的Base版本, 剩下的10%请求按照指定的请求头my-asm-prefer-tag的值来决定去向, 而下面的请求中指定version-canary为请求头my-asm-prefer-tag的值, 即这10%的请求将转向Canary版本。

预期输出:

-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: canary, ip: 172.17.0.130)
-> mocka(version: canary, ip: 172.17.0.69)-> mockb(version: canary, ip: 172.17.0.130)

4) 执行以下命令,验证入口请求的Base版本流量将全部转到应用A的Base版本。这样因为上述生效的路由规则中, 90%的请求进入Base版本, 剩下的10%请求按照指定的请求头my-asm-prefer-tag的值来决定去向, 而下面的请求中指定version-base为请求头my-asm-prefer-tag的值, 即这10%的请求也将转向Base版本。

for i in {
   
   1..200};  do curl -H'my-asm-prefer-tag: version-base'  -H'my-request-id: x000'{
   
   mathJaxContainer[6]}{
   
   ASM_GATEWAY_IP}/; echo; sleep 1; done;

预期输出:

-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
-> mocka(version: base, ip: 172.17.0.90)-> mockb(version: base, ip: 172.17.0.93)
相关文章
|
6月前
|
Cloud Native 容器 Kubernetes
基于阿里云服务网格流量泳道的全链路流量管理(三):无侵入式的宽松模式泳道
本文简要讨论了使用流量泳道来实现全链路流量灰度管理的场景与方案,并回顾了阿里云服务网格 ASM 提供的严格与宽松两种模式的流量泳道、以及这两种模式各自的优势与挑战。接下来介绍了一种基于 OpenTelemetry 社区提出的 baggage 透传能力实现的无侵入式的宽松模式泳道,这种类型的流量泳道同时具有对业务代码侵入性低、同时保持宽松模式的灵活特性的特点。同时,我们还介绍了新的基于权重的流量引流策略,这种策略可以基于统一的流量匹配规则,将匹配到的流量以设定好的比例分发到不同的流量泳道。
73539 16
基于阿里云服务网格流量泳道的全链路流量管理(三):无侵入式的宽松模式泳道
|
5月前
|
人工智能 自然语言处理 安全
使用阿里云服务网格高效管理LLM流量:(一)流量路由
ASM支持通过LLMProvider和LLMRoute资源管理大型语言模型流量。LLMProvider负责注册LLM服务,LLMRoute负责设定流量规则,应用可灵活切换模型,满足不同场景需求。
|
6月前
|
负载均衡 Kubernetes 算法
服务网格 ASM 负载均衡算法全面解析
在本文中,笔者将解析服务网格的多种负载均衡算法的实现原理和使用场景,为服务网格负载均衡算法的选择提供参考。
|
Kubernetes API 容器
基于阿里云服务网格流量泳道的全链路流量管理(二):宽松模式流量泳道
基于阿里云服务网格流量泳道的全链路流量管理(二):宽松模式流量泳道
10992 18
|
7月前
|
Kubernetes Cloud Native 测试技术
使用ASM流量泳道的全链路灰度发布实践
服务网格ASM实现全链路灰度发布:通过流量泳道隔离不同版本环境,配置虚拟服务实现灰度比例控制。从创建泳道、打标签、部署新版本到灰度切流、最终上线及下线旧版。
|
7月前
|
Oracle 关系型数据库
oracle asm 磁盘显示offline
oracle asm 磁盘显示offline
356 2
|
2月前
|
存储 Oracle 关系型数据库
数据库数据恢复—Oracle ASM磁盘组故障数据恢复案例
Oracle数据库数据恢复环境&故障: Oracle ASM磁盘组由4块磁盘组成。Oracle ASM磁盘组掉线 ,ASM实例不能mount。 Oracle数据库故障分析&恢复方案: 数据库数据恢复工程师对组成ASM磁盘组的磁盘进行分析。对ASM元数据进行分析发现ASM存储元数据损坏,导致磁盘组无法挂载。
|
7月前
|
存储 Oracle 关系型数据库
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
oracle数据库ASM磁盘组掉线,ASM实例不能挂载。数据库管理员尝试修复数据库,但是没有成功。
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
|
SQL Oracle 关系型数据库
Oracle ASM磁盘和磁盘组的常用SQL语句
Oracle ASM磁盘和磁盘组的常用SQL语句
290 0
|
文字识别 Oracle NoSQL
oracle 11g 单机asm配置
oracle 11g 单机asm配置
677 0