阿里云服务网格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)
相关文章
|
2月前
|
Cloud Native 测试技术 Nacos
云效 AppStack + 阿里云 MSE 实现应用服务全链路灰度
本文介绍了如何通过阿里云 MSE 微服务引擎和云效应用交付平台 AppStack 实现灰度发布。
90874 4
|
2月前
|
存储 域名解析 应用服务中间件
阿里云OSS对象存储,实现内网访问,免流量费用
阿里云OSS对象存储,实现内网访问,免流量费用
462 2
|
3月前
|
弹性计算
2024阿里云服务器带宽计费价格表_流量费用_固定带宽报价
2024阿里云服务器带宽计费价格表_流量费用_固定带宽报价,北京地域服务器按固定带宽计费一个月23元/M,按使用流量计费0.8元/GB
375 5
|
3月前
|
弹性计算
阿里云服务器“带宽计费模式”详细说明_2024固定带宽和流量详解
阿里云服务器“带宽计费模式”详细说明_2024固定带宽和流量详解,按固定带宽是指直接购买多少M带宽,比如1M、5M、10M、100M等,阿里云直接分配用户所购买的带宽值,根据带宽大小先付费再使用;按使用流量是先设置一个带宽峰值,然后根据实际公网产生的出流量来计算费用,先使用后付费
101 1
|
4月前
|
Kubernetes Cloud Native 测试技术
使用ASM流量泳道的全链路灰度发布实践
服务网格ASM实现全链路灰度发布:通过流量泳道隔离不同版本环境,配置虚拟服务实现灰度比例控制。从创建泳道、打标签、部署新版本到灰度切流、最终上线及下线旧版。
|
5月前
|
域名解析 弹性计算 负载均衡
阿里云——超大流量网站的负载均衡
阿里云——超大流量网站的负载均衡
110 0
|
6月前
|
Kubernetes API 容器
基于阿里云服务网格流量泳道的全链路流量管理(二):宽松模式流量泳道
基于阿里云服务网格流量泳道的全链路流量管理(二):宽松模式流量泳道
10895 7
|
7月前
|
弹性计算
阿里云服务器公网带宽10M价格和流量价格
阿里云服务器公网带宽10M价格和流量价格,阿里云服务器上海地域10M带宽一年优惠价格5355元,10M带宽一个月525元,地域不同带宽价格不同,阿里云服务器网以华东1(上海)地域为例,5M及5M以下带宽按照23元一个月的价格收取,6M及6M以上公网带宽按照80元一个月的价格收取
87 0
|
7月前
|
负载均衡 网络协议 测试技术
使用eBPF加速阿里云服务网格ASM
服务网格下的Sidecar 代理业务服务的收发请求,并提供业务层面的流量控制(路由)、负载均衡等功能,会引入一定的Latency 延迟。 通过eBPF 技术(部署sidecar 加速组件)将同节点下两个进程间的TCP 报文进行socket 短路可以提升一定的性能,HTTP 场景下QPS 可提升15% 左右, 有效地降低业务请求的Latency 。
916 0
使用eBPF加速阿里云服务网格ASM
|
4天前
|
弹性计算 运维 监控
解密阿里云弹性计算:探索云服务器ECS的核心功能
阿里云ECS是核心计算服务,提供弹性云服务器资源,支持实例按需配置、集群管理和监控,集成安全防护,确保服务稳定、安全,助力高效业务运营。
30 0