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

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 当您需要在多个服务间实现全链路的灰度发布时,可以通过配置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)
相关文章
|
10天前
|
Kubernetes 大数据 调度
使用Kmesh作为阿里云服务网格ASM Sidecarless模式数据面
阿里云服务网格ASM支持Sidecar和Sidecarless两种模式,本文介绍了如何在阿里云ACK集群中部署Kmesh作为Sidecarless数据面并连接ASM控制面。
|
21天前
|
Kubernetes 调度 容器
使用Kmesh作为阿里云服务网格ASM Sidecarless模式数据面
阿里云服务网格ASM支持Sidecar和Sidecarless两种模式,其中Sidecarless模式如Istio Ambient、ACMG和Kmesh等,可减少延迟和资源消耗。Kmesh基于eBPF技术,通过内核空间拦截流量,结合Waypoint Proxy处理L7流量,实现高效的服务治理。本文介绍了如何在阿里云ACK集群中部署Kmesh并连接ASM控制面,包括安装步骤、检查服务状态和流量调度示例。
|
4月前
|
人工智能 自然语言处理 安全
使用阿里云服务网格高效管理LLM流量:(一)流量路由
ASM支持通过LLMProvider和LLMRoute资源管理大型语言模型流量。LLMProvider负责注册LLM服务,LLMRoute负责设定流量规则,应用可灵活切换模型,满足不同场景需求。
|
4月前
|
Cloud Native 测试技术 开发者
阿里云服务网格ASM多集群实践(二):高效按需的应用多环境部署与全链路灰度发布
介绍服务网格ASM提出的一种多集群部署下的多环境部署与全链路灰度发布解决方案。
|
5月前
|
人工智能 安全 Go
使用阿里云服务网格 ASM LLMProxy 插件保障大模型用户数据安全
本文介绍如何使用ASM LLMProxy动态为LLM请求添加API_KEY、使用模式匹配以及私有大模型判别请求敏感信息并根据判别结果拒绝请求等功能,帮助用户提升LLM场景下的安全水位。
|
6月前
|
Oracle 关系型数据库
oracle asm 磁盘显示offline
oracle asm 磁盘显示offline
326 2
|
28天前
|
存储 Oracle 关系型数据库
数据库数据恢复—Oracle ASM磁盘组故障数据恢复案例
Oracle数据库数据恢复环境&故障: Oracle ASM磁盘组由4块磁盘组成。Oracle ASM磁盘组掉线 ,ASM实例不能mount。 Oracle数据库故障分析&恢复方案: 数据库数据恢复工程师对组成ASM磁盘组的磁盘进行分析。对ASM元数据进行分析发现ASM存储元数据损坏,导致磁盘组无法挂载。
|
6月前
|
存储 Oracle 关系型数据库
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
oracle数据库ASM磁盘组掉线,ASM实例不能挂载。数据库管理员尝试修复数据库,但是没有成功。
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
|
SQL Oracle 关系型数据库
Oracle ASM磁盘和磁盘组的常用SQL语句
Oracle ASM磁盘和磁盘组的常用SQL语句
284 0
|
文字识别 Oracle NoSQL
oracle 11g 单机asm配置
oracle 11g 单机asm配置
656 0