All Products
Search
Document Center

Microservices Engine:Implement frontend canary releases using an MSE cloud-native gateway

Last Updated:Mar 11, 2026

Routing all users to a new frontend version at once risks exposing everyone to defects. Frontend canary release routes a subset of users -- identified by a cookie or header value -- to the new version first. You can monitor for issues with the small group, then gradually expand or roll back without affecting other users.

Microservices Engine (MSE) cloud-native gateways support frontend canary release through the frontend-gray plug-in. The plug-in inspects each request for a user identifier, matches it against your canary rules, and routes the request to either the base or canary version.

How it works

Each user request passes through the MSE cloud-native gateway. After authentication, the request cookie contains a unique user identifier, such as userid: 001. The frontend-gray plug-in evaluates this identifier against configured rules and forwards the request to the matching frontend version.

User request --> Cloud-native gateway --> frontend-gray plug-in evaluates userid
                                            |-- Matches canary rule --> Canary version
                                            |-- No match            --> Base version

The plug-in supports two routing strategies:

StrategyHow it worksUse case
Rule-basedRoutes users whose identifier matches a whitelist (grayKeyValue) to the canary versionTarget specific test users or internal teams
Weight-basedRoutes a percentage of non-rule-matched traffic to the canary version (weight)Gradually roll out to a broader audience

When both strategies are configured, rule-based matching is evaluated first. If a request does not match any rule, weight-based routing applies.

Note

To extend canary release beyond the frontend to your entire microservices call chain, combine this approach with end-to-end canary release based on cloud-native gateways. This is useful when your frontend calls Spring Cloud or Dubbo backend services that also have canary versions.

Prerequisites

Before you begin, make sure that you have:

Choose a deployment approach

MSE supports four approaches for frontend canary release. Choose the one that matches your infrastructure:

ApproachWhen to useKey difference
MSE Ingress gatewayKubernetes workloads with Ingress-based routingTraffic splitting defined through Ingress annotations
ACK cluster with MSE console routesKubernetes workloads with console-managed routingRoutes configured in the MSE console instead of Ingress resources
ECS instancesApplications deployed directly on ECSServices registered by fixed IP address
CDN or OSSStatic frontend assets hosted in OSSPlug-in rewrites paths to serve versioned assets from OSS

MSE Ingress gateway

Step 1: Deploy the base and canary applications

Deploy two versions of your frontend application in the ACK cluster: a base Deployment and a canary Deployment, each with its own Service and Ingress resource. For details, see Create a stateless application using a Deployment.

Important

Install MSE Ingress Controller before proceeding. For setup instructions, see Use MSE Ingress gateways to access services in ACK clusters and ACS clusters.

Expand YAML

frontend-base.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
        - image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:base'
          imagePullPolicy: Always
          name: frontend
          resources: {}
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-base-svc
  namespace: default
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: frontend
  type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  labels:
    ingress-controller: mse
  namespace: default
  name: frontend-base-ingress
spec:
  ingressClassName: mse
  rules:
    - http:
        paths:
          - backend:
              service:
                name: frontend-base-svc
                port:
                  number: 80
            path: /
            pathType: Prefix
frontend-gray.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-gray
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend-gray
  template:
    metadata:
      labels:
        app: frontend-gray
    spec:
      containers:
        - image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:gray'
          imagePullPolicy: Always
          name: frontend-gray
          resources: {}
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-gray-svc
  namespace: default
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: frontend-gray
  type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  labels:
    ingress-controller: mse
  annotations:
    nginx.ingress.kubernetes.io/canary: 'true'
    nginx.ingress.kubernetes.io/canary-by-header: x-higress-tag
    nginx.ingress.kubernetes.io/canary-by-header-value: gray
  name: frontend-gray-ingress
  namespace: default
spec:
  ingressClassName: mse
  rules:
    - http:
        paths:
          - backend:
              service:
                name: frontend-gray-svc
                port:
                  number: 80
            path: /
            pathType: Prefix

The canary Ingress uses three annotations to enable header-based traffic splitting:

AnnotationPurpose
nginx.ingress.kubernetes.io/canary: 'true'Marks this Ingress as a canary route
nginx.ingress.kubernetes.io/canary-by-header: x-higress-tagSpecifies the header used for routing decisions
nginx.ingress.kubernetes.io/canary-by-header-value: grayRoutes requests with x-higress-tag: gray to the canary Service

Step 2: Configure the frontend-gray plug-in

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. On the Gateways page, click the ID of the gateway.

  3. In the left-side navigation pane, click Plug-in Marketplace.

  4. On the Plug-in Marketplace page, search for frontend-gray and click the frontend-gray plug-in card.

  5. Click the Plug-in Configuration tab, choose Domain-level plug-in rules, and then click Add Rule. Configure the following rule: This rule routes users with userid values 00000002 and 00000003 to the canary (gray) version. All other users see the base version. For all available configuration fields, see Plug-in configuration reference and the Higress frontend-gray plug-in documentation.

       grayKey: userid
       rules:
         - name: beta-user
           grayKeyValue:
             - "00000002"
             - "00000003"
       baseDeployment:
         version: base
       grayDeployments:
         - name: beta-user
           version: gray
           enabled: true

    Plugin configuration rule panel

Step 3: Verify the result

  1. Log on to the ACK console. In the left-side navigation pane, click Clusters. Click the cluster that you created. In the left-side navigation pane, choose Network > Ingresses to find the public endpoint.

    ACK console Ingresses view

  2. Open the public endpoint (for example, nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com). Log on with the admin/ice account. Confirm that the user ID is 00000001 and you see the base version.

  3. Log on with the user/ice account. Confirm that the user ID is 00000002 and you see the canary version.


ACK cluster with MSE console routes

This approach uses the same Kubernetes workloads but configures routing through the MSE console instead of Ingress resources.

Step 1: Deploy the base and canary applications

Deploy the base and canary Deployments and Services in the ACK cluster. Use the same Deployment and Service manifests as the MSE Ingress gateway approach, but omit the Ingress resources. For details, see Create a stateless application using a Deployment.

Expand YAML

frontend-base.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
        - image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:base'
          imagePullPolicy: Always
          name: frontend
          resources: {}
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-base-svc
  namespace: default
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: frontend
  type: ClusterIP
frontend-gray.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-gray
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend-gray
  template:
    metadata:
      labels:
        app: frontend-gray
    spec:
      containers:
        - image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:gray'
          imagePullPolicy: Always
          name: frontend-gray
          resources: {}
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-gray-svc
  namespace: default
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: frontend-gray
  type: ClusterIP

Step 2: Configure the frontend-gray plug-in

Follow the same plug-in configuration steps as the MSE Ingress gateway approach.

Step 3: Add a service source

Register your ACK cluster as a service source so the gateway can discover your Kubernetes Services.

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Routes. Click the Source tab.

  4. Click Add Source. In the Add Source panel, select Container Service for Source Type, select your ACK cluster from the ACK/ASK/ACS Cluster drop-down list, and then click OK.

    Add Source panel

Step 4: Add services

Import the base and canary Kubernetes Services into the gateway.

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Routes. Click the Services tab.

  4. Click Add Service. In the Add Service panel, configure the parameters, and click OK.

    Add Service panel

Step 5: Add a base route

Create a route that directs default traffic to the base frontend Service.

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Routes. Click Add Route.

  4. On the Add Route page, configure the parameters, and click Save and Advertise.

    Add Route page -- base route

Step 6: Add a canary route

Create a route that directs canary traffic to the canary frontend Service.

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Routes. Click Add Route.

  4. On the Add Route page, configure the parameters, and click Save and Advertise.

    Note

    Set the version to gray. This value corresponds to grayDeployments.version in the frontend-gray plug-in configuration.

    Add Route page -- canary route

Step 7: Verify the result

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. On the Overview page, click the Endpoint tab to find the public endpoint.

    Gateway endpoint

  4. Open the public endpoint (for example, nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com). Log on with the admin/ice account. Confirm that the user ID is 00000001 and you see the base version.

  5. Log on with the user/ice account. Confirm that the user ID is 00000002 and you see the canary version.


ECS instances

Use this approach when frontend applications run directly on Elastic Compute Service (ECS) instances instead of Kubernetes.

Step 1: Deploy two frontend application versions on an ECS instance

Deploy the base and canary versions on the same or separate ECS instances:

  • Base version endpoint: 120.***.137.243:80

  • Canary version endpoint: 120.***.137.243:8081

Step 2: Add services

Register both frontend versions as fixed-address services in the gateway.

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Routes. Click the Services tab.

  4. Click Add Service. In the Add Service panel, select Fixed Address from the Service Source drop-down list, configure the parameters, and then click OK.

    Add Service -- Fixed Address (base)

    Add Service -- Fixed Address (canary)

Step 3: Add a base route

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Routes. Click Add Route.

  4. On the Add Route page, configure the parameters, and click Save and Advertise.

    Add Route page -- base route

Step 4: Add a canary route

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Routes. Click Add Route.

  4. On the Add Route page, configure the parameters, and click Save and Advertise.

    Note

    Set the version to gray. This value corresponds to grayDeployments.version in the frontend-gray plug-in configuration.

    Add Route page -- canary route

Step 5: Configure the frontend-gray plug-in

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Plug-in Marketplace.

  4. On the Plug-in Marketplace page, search for frontend-gray and click the frontend-gray plug-in card.

  5. Click the Plug-in Configuration tab, choose Domain-level plug-in rules, and then click Add Rule. Configure the following rule: For all available configuration fields, see Plug-in configuration reference and the Higress frontend-gray plug-in documentation.

       grayKey: userid
       rules:
         - name: beta-user
           grayKeyValue:
             - "00000002"
             - "00000003"
       baseDeployment:
         version: base
       grayDeployments:
         - name: beta-user
           version: gray
           enabled: true

    Plugin configuration rule panel

Step 6: Verify the result

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. On the Overview page, click the Endpoint tab to find the public endpoint.

    Gateway endpoint

  4. Open the public endpoint (for example, nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com). Log on with the admin/ice account. Confirm that the user ID is 00000001 and you see the base version.

  5. Log on with the user/ice account. Confirm that the user ID is 00000002 and you see the canary version.


CDN or OSS

Use this approach when frontend assets are hosted in Object Storage Service (OSS) and optionally served through CDN. The frontend-gray plug-in rewrites request paths to serve versioned assets from different OSS directories.

Step 1: Prepare your OSS file structure

Organize your frontend assets in OSS with version-based directories:

Expand YAML

- app1                          # Application
  - dev                         # Base version (development)
    - index.html
    - js/
    - css/
    - images/
  - 0.0.1                      # Canary version 1
    - index.html
    - js/
    - css/
    - images/
  - 0.0.2                      # Canary version 2
    - index.html
    - js/
    - css/
    - images/
- app2
  - dev/
  - 0.0.1/
  - 0.0.2/

Step 2: Add a service

Register your OSS endpoint as a DNS-based service in the gateway.

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Routes. Click the Services tab.

  4. Click Add Service. In the Add Service panel, select DNS Domain Name from the Service Source drop-down list, enter the OSS endpoint, and then click OK.

    Important

    If OSS and the gateway are in the same region, use the internal OSS endpoint to avoid public network charges. If they are in different regions, use the public endpoint.

    Add Service -- DNS Domain Name

Step 3: Add a route

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Routes. Click Add Route.

  4. On the Add Route page, configure the parameters, and click Save and Advertise.

    Add Route page -- CDN/OSS

Step 4: Configure the frontend-gray plug-in

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. In the left-side navigation pane, click Plug-in Marketplace.

  4. On the Plug-in Marketplace page, search for frontend-gray and click the frontend-gray plug-in card.

  5. Click the Plug-in Configuration tab, choose Domain-level plug-in rules, and then click Add Rule. Configure the following rule: The CDN/OSS approach differs from the other approaches in the following fields: For all available configuration fields, see Plug-in configuration reference and the Higress frontend-gray plug-in documentation.

    FieldDescription
    rewrite.hostThe OSS endpoint that hosts your frontend assets
    rewrite.indexRoutingMaps URL paths to versioned index.html files in OSS. The {version} placeholder is replaced by the version string (dev or 0.0.1)
    rewrite.fileRoutingMaps URL paths to versioned static asset directories in OSS
    baseDeployment.versionSet to dev (the base version directory name in OSS)
    grayDeployments[0].versionSet to 0.0.1 (the canary version directory name in OSS)
       grayKey: userid
       rules:
         - name: beta-user
           grayKeyValue:
             - "00000002"
             - "00000003"
       rewrite:
         host: xx.oss-cn-shanghai.aliyuncs.com       ## Replace with your OSS endpoint
         indexRouting:
           "/app1": "/project-a/app1/{version}/index.html"  # Path rewrite for HTML entry pages
         fileRouting:
           "/app1": "/project-a/app1/{version}"              # Path rewrite for CSS, JavaScript, and images
       baseDeployment:
         version: dev
       grayDeployments:
         - name: beta-user
           version: 0.0.1
           enabled: true

Step 5: Verify the result

  1. Log on to the MSE console. In the top navigation bar, select a region.

  2. In the left-side navigation pane, choose Cloud-native Gateway > Gateways. Click the ID of the gateway.

  3. On the Overview page, click the Endpoint tab to find the public endpoint.

    Gateway endpoint

  4. Open the public endpoint (for example, nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com). Log on with the admin/ice account. Confirm that the user ID is 00000001 and you see the base version.

  5. Log on with the user/ice account. Confirm that the user ID is 00000002 and you see the canary version.


Plug-in configuration reference

The following table lists the main configuration fields for the frontend-gray plug-in. For the complete field reference, see the Higress frontend-gray plug-in documentation.

FieldTypeRequiredDescription
grayKeystringNoThe key name used to extract the user identifier from a cookie or header. Example: userid
graySubKeystringNoA JSON sub-key within the grayKey value. Use this when the user identifier is embedded in a JSON-formatted cookie or header
rulesarrayYesA list of canary rules. Each rule defines a name and a set of user identifier values to match
rules[].namestringYesThe name of the rule. Must match a corresponding entry in grayDeployments
rules[].grayKeyValuearray of stringsNoA list of user identifier values. Requests with a matching identifier are routed to the corresponding canary version
rules[].grayTagKeystringNoAn alternative key for matching. Use this for tag-based routing instead of user ID-based routing
rules[].grayTagValuearray of stringsNoA list of tag values to match when using grayTagKey
baseDeployment.versionstringYesThe version identifier for the base (production) deployment
grayDeploymentsarrayYesA list of canary deployments
grayDeployments[].namestringYesThe canary deployment name. Must match a rule name in rules
grayDeployments[].versionstringYesThe version identifier for this canary deployment
grayDeployments[].enabledbooleanYesWhether this canary deployment is active
grayDeployments[].weightinteger (0--100)NoThe percentage of non-rule-matched traffic to route to this canary version. Defaults to 0
rewriteobjectNoPath rewrite configuration for CDN/OSS deployments
rewrite.hoststringNoThe OSS endpoint hostname
rewrite.indexRoutingmapNoMaps URL paths to versioned index.html files. Use {version} as a placeholder
rewrite.fileRoutingmapNoMaps URL paths to versioned static asset directories. Use {version} as a placeholder
injectionobjectNoHTML injection configuration. Injects scripts or styles into the HTML entry page
injection.headarray of stringsNoHTML snippets to inject into the <head> tag
injection.body.firstarray of stringsNoHTML snippets to inject at the beginning of the <body> tag
injection.body.lastarray of stringsNoHTML snippets to inject at the end of the <body> tag

Monitor and roll back

After you deploy a canary release, monitor the canary version for issues before promoting it to all users.

Monitor the canary version:

  • Check the MSE gateway logs for error rates on canary routes. Compare error rates between the base and canary versions.

  • Use Cloud Monitor or Application Real-Time Monitoring Service (ARMS) to track page load times, JavaScript errors, and API success rates for canary users.

  • Set up alerts for abnormal metrics such as elevated HTTP 5xx error rates or increased page load latency on canary routes.

Roll back the canary version:

If the canary version shows problems, roll back by disabling the canary deployment:

  1. Log on to the MSE console. Navigate to your gateway's Plug-in Marketplace and open the frontend-gray plug-in configuration.

  2. Set enabled: false in the grayDeployments section, or remove the canary rule entirely:

       grayDeployments:
         - name: beta-user
           version: gray
           enabled: false    # Disables canary routing; all traffic goes to the base version
  3. Save the configuration. All traffic immediately returns to the base version.

Promote the canary version:

After successful validation, promote the canary version by updating the base deployment image to the canary version image and removing the canary rules from the plug-in configuration.


FAQ

Can I use rewrite policies and frontend canary release at the same time?

It depends on your service source:

  • Non-CDN/OSS sources (ACK, ECS): Yes. Rewrite policies and canary release work independently and do not conflict.

  • CDN or OSS sources: No. The frontend-gray plug-in handles path rewriting internally through the rewrite configuration block. Adding a separate rewrite policy causes conflicts and may return HTTP 403 errors.

Can I inject global variables into the HTML page?

Yes. Use the injection configuration block to inject JavaScript or CSS into the HTML entry page. Injection supports three positions:

PositionDescription
injection.headInjects into the <head> tag. Typically used for CSS styles or meta tags
injection.body.firstInjects at the beginning of the <body> tag
injection.body.lastInjects at the end of the <body> tag

Example configuration:

grayKey: userid
rules:
  - name: inner-user
    grayKeyValue:
      - '00000001'
      - '00000005'
baseDeployment:
  version: base
grayDeployments:
  - name: beta-user
    version: gray
    enabled: true
    weight: 80
injection:
  head:
    - <script>console.log('Header')</script>
  body:
    first:
      - <script>console.log('hello world before')</script>
      - <script>console.log('hello world before1')</script>
    last:
      - <script>console.log('hello world after')</script>
      - <script>console.log('hello world after2')</script>

This example also demonstrates weight-based canary release. With weight: 80, 80% of non-rule-matched traffic goes to the canary version, and 20% goes to the base version.

When does the canary version take effect for a user?

The canary version takes effect on the next full page load, not in real time. If user A is on version 0.0.1 and you publish version 0.0.2 with a canary rule that matches user A, the new version appears only after user A refreshes or re-loads the page.

This behavior is by design for two reasons:

  • User experience: Switching versions mid-session could break in-progress interactions, such as making a button disappear while a user is clicking it.

  • Architecture decoupling: Real-time version switching would require the backend to dynamically control frontend versions, coupling frontend and backend releases and preventing CDN caching.

When does a page refresh occur?

A page refresh typically occurs when:

  • A session expires and the user re-authenticates.

  • The user navigates to the login page.

To load the latest canary configuration on login, redirect with a full page navigation:

async function handleLogin(values: LoginParams) {
  try {
    const result = await login(values);
    if (result.success) {
      message.success('Logon succeeded.');
      await updateUserInfo();
      const urlParams = new URL(window.location.href).searchParams;
      // Full page redirect ensures the canary version is loaded
      window.location.href = `${urlParams.get('redirect') || '/'}`;
      return;
    }
    console.log(result);
    setLoginResult(result);
  } catch (error) {
    message.error('Logon failed. Try again.');
    console.log(error);
  }
}

The key line is window.location.href = .... This triggers a full page navigation, forcing the browser to request the page from the gateway. The frontend-gray plug-in then evaluates the canary rules and serves the correct version.