When you adopt Service Mesh (ASM) for traffic management, existing services behind Nginx Ingress Controller must continue to receive traffic without interruption. ASM lets you run both gateways behind the same Classic Load Balancer (CLB) instance and shift traffic gradually through weight-based routing, so you can validate each stage and roll back instantly if needed.
How it works
With Nginx Ingress Controller, a single Ingress resource handles both listener configuration (ports, hosts, TLS) and routing rules (paths, backends). Istio separates these into two resources:
Gateway -- Defines the infrastructure layer: which ports to expose, which protocols to accept, and which hosts to serve.
VirtualService -- Defines the routing layer: how to match incoming requests and where to send them.
During migration, both Nginx Ingress Controller and the ASM ingress gateway share the same CLB instance. A weight-based traffic split lets you shift traffic incrementally, verify behavior at each stage, and roll back by setting the weight to 0.

Prerequisites
Before you begin, make sure that you have:
An ASM instance of Enterprise Edition or Ultimate Edition, running the latest version. See Create an ASM instance
A Container Service for Kubernetes (ACK) cluster added to the ASM instance. See Add a cluster to an ASM instance
The CLB instance ID and vServer group IDs for your existing Nginx Ingress Controller setup
The CLB scheduling algorithm set to weighted round-robin (WRR)
Step 1: Create an ingress gateway that shares the existing CLB
Create an ASM ingress gateway that reuses the CLB instance already associated with Nginx Ingress Controller. This lets both gateways coexist behind the same load balancer during migration.
Add the following service annotations to the gateway YAML to bind the ingress gateway to your existing CLB:
| Annotation | Purpose | Example value |
|---|---|---|
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id | CLB instance to reuse | "lb-xxxxx" |
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners | Whether to overwrite existing CLB listeners. Set to false to preserve Nginx Ingress listeners. | 'false' |
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-vgroup-port | vServer groups to bind, in the format <vserver-group-id>:<port>. Separate multiple entries with commas. | "${YOUR_VGROUP_ID}:80" |
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-weight | Traffic weight for the ingress gateway. Set to 0 when routing is not yet configured or when issues occur -- the CLB sends no traffic to the gateway at weight 0. | "0" |
Sample gateway configuration:
serviceAnnotations:
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id: "lb-xxxxx"
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: "60"Replace the placeholder values:
| Placeholder | Description | Where to find it |
|---|---|---|
lb-xxxxx | CLB instance ID | CLB console > Instances |
${YOUR_VGROUP_ID} | vServer group ID | CLB console > vServer Groups |
If you set the weight to 0, the ingress gateway no longer receives traffic. You can set the weight to 0 when routing rules have not been configured or when exceptions occur.
For details on reusing CLB instances created with the LoadBalancer Service type, see FAQ.
Verify the gateway
Confirm that the ingress gateway pod is running and the CLB instance shows the new vServer group members:
kubectl get pods -n istio-system -l istio=ingressgatewayExpected output:
NAME READY STATUS RESTARTS AGE
istio-ingressgateway-xxxx-xxxxx 1/1 Running 0 1mStep 2: Translate Ingress rules to Istio VirtualService and DestinationRule
Convert each Nginx Ingress resource into a pair of Istio resources: a Gateway (already created in Step 1) and a VirtualService. If you need traffic policies such as connection pool settings or outlier detection, also create a DestinationRule.
Example: rewrite-based Ingress rule
Original Ingress:
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.comEquivalent VirtualService:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: example-vs
spec:
gateways:
- istio-system/ingressgateway # Reference your gateway name
hosts:
- example.com
http:
- name: route-helloworld
match:
- uri:
prefix: /helloworld/
- uri:
prefix: /helloworld
rewrite:
uri: /
route:
- destination:
host: helloworld
port:
number: 80Key differences from the Ingress resource:
The
rewrite-targetannotation becomes arewrite.urifield in the VirtualService.The regex path
/helloworld(/|$)(.*)becomes two explicit prefix matches:/helloworld/and/helloworld.The
hostand routing rules are defined separately (Gateway vs. VirtualService) rather than in a single resource.
Deploy VirtualService and DestinationRule resources in the same namespace as the corresponding Kubernetes Service. If you deploy them in a different namespace, use the fully qualified domain name (FQDN) format for destination.host (for example, helloworld.default.svc.cluster.local).
Verify the routes
Apply the VirtualService and confirm that the routes are accepted:
kubectl apply -f virtualservice.yaml
kubectl get virtualservice example-vs -o yamlCheck that the status section shows no errors or warnings.
Step 3: Verify the configurations
Verify that the configurations are valid and take effect by checking the traffic flow. Create a CLB instance, send traffic to the CLB instance, and check whether the traffic flow meets expectations. For more information, see Traffic flow.
Step 4: Shift traffic gradually
After the routing configuration is verified, increase the ingress gateway weight incrementally to migrate traffic:
Start with a low weight (for example,
1) and monitor for errors.Increase the weight in stages -- for example,
1->10->30->60->100.At each stage, verify that latency, error rates, and response content remain consistent.
After all traffic routes through the ingress gateway, set the Nginx Ingress Controller weight to
0.
How to adjust weights
| Component | How to adjust |
|---|---|
| ASM ingress gateway | Edit the service.beta.kubernetes.io/alibaba-cloud-loadbalancer-weight annotation in the gateway configuration. |
| Nginx Ingress Controller | Edit the service.beta.kubernetes.io/alibaba-cloud-loadbalancer-weight annotation on the related Kubernetes Service. If no weight annotation exists, adjust the weight in the CLB console. |
The CLB scheduling algorithm must be set to weighted round-robin (WRR) for weight-based traffic splitting to work.
Next steps
After all traffic flows through the ASM ingress gateway:
Configure TLS termination on the ASM ingress gateway
Set up monitoring and access logging for the ingress gateway
Remove the Nginx Ingress Controller deployment after confirming stable operation
Explore Istio traffic management features such as fault injection, circuit breaking, and canary releases