All Products
Search
Document Center

Alibaba Cloud Service Mesh:Migrate an Nginx Ingress that uses a CLB instance to an ASM gateway

Last Updated:Mar 11, 2026

When you adopt Alibaba Cloud Service Mesh (ASM), you need to move ingress traffic handling from NGINX Ingress Controller to the ASM ingress gateway. This guide walks you through a zero-downtime migration that reuses your existing Classic Load Balancer (CLB) instance and IP address, so DNS records stay unchanged. If issues occur at any point, reset weights to route all traffic back to NGINX Ingress immediately.

How it works

Both NGINX Ingress Controller and the ASM ingress gateway run side by side behind the same CLB instance. Traffic distribution between them is controlled by CLB backend weights. You start with all traffic on NGINX Ingress, gradually shift it to the ASM gateway, and decommission NGINX Ingress after the migration is complete.

Migration architecture

The migration follows five steps:

  1. Detach the CLB from NGINX Ingress -- Make the existing CLB instance reusable so that both NGINX Ingress and the ASM gateway can share it.

  2. Create an ASM gateway -- Deploy the ASM ingress gateway and attach it to the same CLB with an initial weight of 0 (no traffic).

  3. Convert Ingress resources to Istio configurations -- Translate your NGINX Ingress rules into Istio Gateway and VirtualService resources.

  4. Verify the configuration -- Send test traffic to confirm that the ASM gateway routes requests correctly.

  5. Shift traffic -- Gradually increase the ASM gateway weight until it handles all traffic.

Note

Because both gateways share the same CLB, your external IP address and DNS records remain unchanged throughout the migration. NGINX Ingress continues to serve production traffic until you explicitly shift weights. To roll back at any point, set the ASM gateway weight to 0 and the NGINX Ingress weight to 100.

Prerequisites

Before you begin, make sure that you have:

Step 1: Make the NGINX Ingress CLB instance reusable

By default, ACK manages the CLB instance for NGINX Ingress and prevents manual changes. To share this CLB with the ASM gateway, detach it from ACK management first.

Get the CLB instance ID

Run the following command to retrieve the CLB instance ID:

kubectl -n kube-system get svc nginx-ingress-lb -o yaml | grep service.k8s.alibaba/loadbalancer-id

Expected output:

service.k8s.alibaba/loadbalancer-id: lb-bp1gts52ced2vgaw1ni78

Record the CLB instance ID (for example, lb-bp1gts52ced2vgaw1ni78). You need it in later steps.

Update CLB settings in the console

  1. Open the Server Load Balancer console.

  2. Find your CLB instance and make the following changes:

    • Disable configuration read-only mode.

    • Delete the kubernetes.do.not.delete and ack.aliyun.com tags.

    • Rename the vServer groups that start with k8s/ to the shared-<port> format. For example, rename k8s/80/nginx-ingress-lb/kube-system/c553a74e6ad13423aa839c8e5******** to shared-80.

Add annotations to the NGINX Ingress Service

Add the following annotations to the NGINX Ingress Service so that it references the CLB explicitly instead of relying on ACK-managed discovery:

metadata:
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id: "<your-clb-instance-id>"
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners: "false"
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-vgroup-port: "<your-vgroup-id-1>:80,<your-vgroup-id-2>:443"
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-weight: "100"

Replace the following placeholders with actual values:

PlaceholderDescriptionExample
<your-clb-instance-id>CLB instance ID from the previous steplb-bp1gts52ced2vgaw1ni78
<your-vgroup-id-1>vServer group ID for port 80rsp-bp1k5xxxxxxx
<your-vgroup-id-2>vServer group ID for port 443rsp-bp1k5yyyyyyy
Important

Use the vServer group ID (not the display name such as shared-80). To find the ID, check the vServer group details in the Server Load Balancer console.

Step 2: Create an ASM gateway

Create an ASM gateway by using YAML. To generate a base YAML file, open the ASM gateway creation page in the ASM console, configure the visual form, and click the preview button.

Edit the serviceAnnotations section to reuse the same CLB instance. The annotations are identical to Step 1 except that the weight is "0", which prevents the ASM gateway from receiving traffic initially.

serviceAnnotations:
  service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id: "<your-clb-instance-id>"
  service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners: "false"
  service.beta.kubernetes.io/alibaba-cloud-loadbalancer-vgroup-port: "<your-vgroup-id>:80"
  service.beta.kubernetes.io/alibaba-cloud-loadbalancer-weight: "0"

The following table explains each annotation:

AnnotationValuePurpose
alibaba-cloud-loadbalancer-idYour CLB instance IDReuses the existing CLB
alibaba-cloud-loadbalancer-force-override-listeners"false"Prevents Istio from overriding existing CLB listeners (Istio overrides listeners by default)
alibaba-cloud-loadbalancer-vgroup-portvServer group ID and port mappingRoutes traffic to the correct backend group
alibaba-cloud-loadbalancer-weight"0"Starts with no traffic on the ASM gateway

Step 3: Convert Ingress resources to Istio configurations

Translate each NGINX Ingress resource into an Istio Gateway and VirtualService pair. The following example shows how to convert a basic Ingress rule with URL rewriting.

NGINX Ingress (before)

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: helloworld
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
    - http:
        paths:
          - backend:
              serviceName: helloworld
              servicePort: 80
            path: /helloworld(/|$)(.*)
      host: example.com

Istio VirtualService (after)

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: example-vs
spec:
  gateways:
  - istio-system/ingressgateway    # Replace with your ASM gateway name
  hosts:
  - example.com
  http:
  - name: route-helloworld
    match:
    - uri:
        prefix: /helloworld/
    - uri:
        prefix: /helloworld
    rewrite:
      uri: /
    route:
    - destination:
        host: helloworld
        port:
          number: 80

Key differences between Ingress and VirtualService

The following table summarizes the mapping between NGINX Ingress fields and their Istio VirtualService equivalents:

AspectNGINX IngressIstio VirtualService
Routing targetserviceName and servicePortdestination.host and destination.port.number
URL rewritingrewrite-target annotationrewrite.uri field
Host matchingrules[].hosthosts[]
Gateway bindingImplicit (the Ingress controller)Explicit (gateways[] field)

Common NGINX Ingress annotation equivalents

If you use advanced NGINX Ingress annotations, refer to the following table for Istio equivalents:

NGINX Ingress annotationIstio equivalentResource type
nginx.ingress.kubernetes.io/rewrite-targethttp[].rewrite.uriVirtualService
nginx.ingress.kubernetes.io/ssl-redirecttls section in GatewayGateway
nginx.ingress.kubernetes.io/proxy-read-timeouttimeout fieldVirtualService
nginx.ingress.kubernetes.io/upstream-hash-byconsistentHash in trafficPolicyDestinationRule
nginx.ingress.kubernetes.io/cors-enablecorsPolicy fieldVirtualService

Cross-namespace routing

If a VirtualService and its target Service are in the same namespace, use the short service name (for example, helloworld). If they are in different namespaces, use the Fully Qualified Domain Name (FQDN) format:

<service-name>.<namespace>.svc.cluster.local
Note

Place the VirtualService and DestinationRule in the same namespace as the target Service Deployment whenever possible. This simplifies routing configuration and avoids FQDN requirements.

Step 4: Verify the configuration

Before shifting production traffic, verify that the ASM gateway handles requests correctly.

Option A: Test through a temporary CLB

Create a new CLB instance and point it to the ASM ingress gateway. Send test requests to this CLB:

curl -s -I -H "Host: example.com" http://<test-clb-ip>/helloworld/

Expected output (key headers):

HTTP/1.1 200 OK
server: istio-envoy

The server: istio-envoy header confirms that traffic is flowing through the ASM gateway.

Option B: Test from inside the cluster

Send requests directly to the ASM ingress gateway Service within the cluster:

# Get the ASM ingress gateway ClusterIP
GATEWAY_IP=$(kubectl -n istio-system get svc istio-ingressgateway -o jsonpath='{.spec.clusterIP}')

# Send a test request
curl -s -I -H "Host: example.com" http://$GATEWAY_IP/helloworld/

Confirm that the response matches what NGINX Ingress returns for the same request. The server: istio-envoy header in the response indicates that traffic is flowing through the ASM gateway.

Step 5: Shift traffic from NGINX Ingress to the ASM gateway

After verification, gradually shift production traffic to the ASM gateway by adjusting CLB backend weights.

Recommended migration schedule

Increase the ASM gateway weight incrementally and monitor at each stage:

StageASM gateway weightNGINX Ingress weightAction
1199Verify with minimal production traffic
21090Monitor error rates and latency
35050Confirm steady-state behavior
41000Complete migration

Adjust weights

ASM gateway weight: Update the service.beta.kubernetes.io/alibaba-cloud-loadbalancer-weight annotation in the IstioGateway serviceAnnotations:

serviceAnnotations:
  service.beta.kubernetes.io/alibaba-cloud-loadbalancer-weight: "50"    # Adjust this value

NGINX Ingress weight: Update the service.beta.kubernetes.io/alibaba-cloud-loadbalancer-weight annotation on the NGINX Ingress Service. If this annotation is not configured, adjust the weight directly in the CLB console.

Rollback

If issues occur during traffic migration, set the ASM gateway weight back to "0" and the NGINX Ingress weight back to "100":

# ASM gateway: stop receiving traffic
serviceAnnotations:
  service.beta.kubernetes.io/alibaba-cloud-loadbalancer-weight: "0"
# NGINX Ingress Service: restore full traffic
metadata:
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-weight: "100"

All traffic returns to NGINX Ingress immediately. No DNS changes are needed because both gateways share the same CLB instance.