All Products
Search
Document Center

Alibaba Cloud Service Mesh:Use traffic lanes and hash tagging to perform user-based canary testing

Last Updated:Jun 20, 2026

Service Mesh (ASM) lets you isolate multiple versions or features of an application into independent runtime environments—called traffic lanes—and route matching request traffic to the target version or feature by defining lane rules. In a production environment, you might want to isolate stable and canary release versions using lanes and route traffic to different lanes based on user identity. Specifically, you may want to route requests from certain identified users directly to the canary version for testing, while routing a random portion of other users’ traffic to the canary version based on weight. This topic describes how to combine traffic lanes and hash tagging to implement user-based canary testing.

Prerequisites

Procedure

This example scenario creates three applications with the following call chain.

  • mocka, with version v1.

  • mockb, with version v1.

  • mockc, with versions v1 and v2.

The applications use the x-user-id request header to identify user identity, and this header is passed through across service calls. This scenario demonstrates the following:

  • When x-user-id: jason, the request routes to the new version.

  • For all other users, compute a hash of the x-user-id value and route a specified percentage of users to the new version based on the hash result.

Step 1: Deploy sample applications

  1. Create a file named sample.yaml with the following content.

    Expand to view YAML content

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mocka-v1
      labels:
        app: mocka
        version: v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mocka
          version: v1
          ASM_TRAFFIC_TAG: v1
      template:
        metadata:
          labels:
            app: mocka
            version: v1
            ASM_TRAFFIC_TAG: v1
        spec:
          containers:
          - name: default
            image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
            imagePullPolicy: IfNotPresent
            env:
            - name: version
              value: v1
            - name: app
              value: mocka
            - name: upstream_url
              value: "http://mockb:8000/"
            ports:
            - containerPort: 8000
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mockb-v1
      labels:
        app: mockb
        version: v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mockb
          version: v1
          ASM_TRAFFIC_TAG: v1
      template:
        metadata:
          labels:
            app: mockb
            version: v1
            ASM_TRAFFIC_TAG: v1
        spec:
          containers:
          - name: default
            image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
            imagePullPolicy: IfNotPresent
            env:
            - name: version
              value: v1
            - name: app
              value: mockb
            - name: upstream_url
              value: "http://mockc:8000/"
            ports:
            - containerPort: 8000
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mockc-v1
      namespace: default
      labels:
        app: mockc
        version: v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mockc
          version: v1
          ASM_TRAFFIC_TAG: v1
      template:
        metadata:
          labels:
            app: mockc
            version: v1
            ASM_TRAFFIC_TAG: v1
        spec:
          containers:
          - name: default
            image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
            imagePullPolicy: IfNotPresent
            env:
            - name: version
              value: v1
            - name: app
              value: mockc
            ports:
            - containerPort: 8000
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mockc-v2
      namespace: default
      labels:
        app: mockc
        version: v2
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mockc
          version: v2
          ASM_TRAFFIC_TAG: v2
      template:
        metadata:
          labels:
            app: mockc
            version: v2
            ASM_TRAFFIC_TAG: v2
        spec:
          containers:
          - name: default
            image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
            imagePullPolicy: IfNotPresent
            env:
            - name: version
              value: v2
            - name: app
              value: mockc
            ports:
            - containerPort: 8000
  2. Using the kubeconfig of your data plane cluster, run the following command to deploy the sample applications.

    kubectl apply -f sample.yaml

Step 2: Create a gateway rule

Create a Gateway resource named ingressgateway in the istio-system namespace using the following configuration. For more information, see Manage gateway rules.

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: ingressgateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - '*'

Step 3: Create a lane group and lanes

  1. Create a lane group.

    1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

    2. On the Mesh Management page, click the target instance name. In the navigation pane on the left, choose Traffic Management Center > Traffic Lane.

    3. On the Traffic Lane page, click Create Swimlane Group. In the Create Swimlane Group panel, configure the settings and click OK.

      Configuration item

      Description

      Name of swim lane group

      Set to canary in this example.

      Entrance gateway

      Select ingressgateway.

      Lane Mode

      Select Permissive Mode.

      Pass-through Mode of Trace Context

      Select Pass Through Trace ID.

      Trace ID Request Header

      Set to x-user-id in this example.

      Routing Request Header

      Specify a header that the gateway uses to route traffic to different lanes and maintain lane context. You can set any value. In this example, set it to x-asm-prefer-tag.

      Swimlane Services

      Select your target Kubernetes cluster and the default namespace. In the list below, select the mocka, mockb, and mockc services, then click the 移动 icon to add them to the selected area.

  2. Create two lanes, s1 and s2, and bind them to versions v1 and v2 respectively.

    1. In the Traffic Lane page, under the Traffic Rule Definition section, click Create swimlanes.

    2. In the Create swimlanes dialog box, configure the settings and click OK.

      Configuration item

      Description

      Swimlane Name

      Set to s1 and s2 respectively.

      Configure Service Tag

      Label Key: Select ASM_TRAFFIC_TAG.

      Label Value: Select v1 for one lane and v2 for the other.

      Add Service

      Lane s1: Select mocka(default), mockb(default), and mockc(default).

      Lane s2: Select mockc(default).

      The following image shows an example of creating lane s1:

      image

      After both lanes are created, the result looks like this:

      image

      Note

      By default, the first lane you create in a lane group becomes the baseline lane. You can change the baseline lane so that when traffic targets a service not present in another lane, the request falls back to the baseline lane. For more information, see Change the baseline lane in loose mode.

  3. Create routing rules for the lanes.

    1. Use the following configuration to create a gateway routing rule for the lanes. This rule has three parts:

      1. Requests with x-user-id: jason route to lane s2, and the system adds the x-asm-prefer-tag: s2 header to mark the request for lane s2.

      2. Requests with x-asm-prefer-tag: s2 route to lane s2.

      3. Requests with x-asm-prefer-tag: s1 route to lane s1.

      Expand to view YAML content

      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: swimlane-ingress-vs
        namespace: istio-system
      spec:
        gateways:
        - istio-system/ingressgateway
        hosts:
        - '*'
        http:
        # Routing rule 1: Requests with x-user-id: jason go to lane s2
        # and add x-asm-prefer-tag: s2 to mark the request for lane s2
        - match:
          - headers:
              x-user-id:
                exact: jason
            uri:
              exact: /
          name: r2
          route:
          - destination:
              host: mocka.default.svc.cluster.local
              subset: s2
            fallback:
              target:
                host: mocka.default.svc.cluster.local
                subset: s1
            headers:
              request:
                set:
                  x-asm-prefer-tag: s2
        # Routing rule 2: Requests with x-asm-prefer-tag: s2 go to lane s2
        - match:
          - headers:
              x-asm-prefer-tag:
                exact: s2
            uri:
              exact: /
          name: r2
          route:
          - destination:
              host: mocka.default.svc.cluster.local
              subset: s2
            # If mocka is not in lane s2, fall back to mocka in lane s1
            fallback:
              target:
                host: mocka.default.svc.cluster.local
                subset: s1
        # Routing rule 3: Requests with x-asm-prefer-tag: s1 go to lane s1
        - match:
          - headers:
              x-asm-prefer-tag:
                exact: s1
            uri:
              exact: /
          name: r1
          route:
          - destination:
              host: mocka.default.svc.cluster.local
              subset: s1

Step 4: Deploy the hash tagging plugin

  1. Create a file named wasm.yaml with the following content.

    apiVersion: extensions.istio.io/v1alpha1
    kind: WasmPlugin
    metadata:
      name: hash-tagging
      namespace: istio-system
    spec:
      imagePullPolicy: IfNotPresent 
      selector:
        matchLabels:
          istio: ingressgateway
      url: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-wasm-hash-tagging:v1.22.6.2-g72656ba-aliyun 
      phase: AUTHN
      pluginConfig:
        rules:
          - header: x-user-id
            modulo: 100
            tagHeader: x-asm-prefer-tag
            policies:
              # Route 20% of user traffic to lane s2
              - range: 20
                tagValue: s2
              # Route 80% of user traffic to lane s1
              - range: 100
                tagValue: s1
  2. Using the kubeconfig of your ASM instance, run the following command to deploy the tagging plugin.

    kubectl apply -f wasm.yaml

Step 5: Verify the setup

  1. Run the following command to set a temporary environment variable for the ingress gateway address.

    export GATEWAY_ADDRESS=`kubectl get svc -n istio-system | grep istio-ingressgateway | awk '{print $4}'`
  2. Run the following command to access the application as Jason.

    curl ${GATEWAY_ADDRESS} -H 'x-user-id: jason'

    Expected output:

    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v2, ip: 10.0.0.133)%     

    The request routes directly to version v2 of the mockc application.

  3. You can execute the following command to route random users to the new version.

     for i in 'bob' 'stacy' 'jessie' 'vance' 'jack'; do curl ${GATEWAY_ADDRESS} -H "x-user-id: $i";echo "   user $i requested"; done

    Expected output:

    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v1, ip: 10.0.0.131)   user bob requested
    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v1, ip: 10.0.0.131)   user stacy requested
    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v2, ip: 10.0.0.133)   user jessie requested
    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v1, ip: 10.0.0.131)   user vance requested
    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v2, ip: 10.0.0.133)   user jack requested

    Requests from users Jessie and Jack route to version v2 of mockc, while others route to version v1.