All Products
Search
Document Center

Alibaba Cloud Service Mesh:Manage Spring Cloud services

Last Updated:Mar 11, 2026

Service Mesh (ASM) adds Istio-based traffic management to Spring Cloud applications without code changes. After you connect your Spring Cloud services to ASM, you can use Istio CRDs such as VirtualService and DestinationRule to control routing, load balancing, and version-based traffic splitting -- while your applications continue to use their existing service registry for discovery.

Supported implementations and registries

ASM supports the following Spring Cloud implementations. All migrations require zero code changes.

Spring Cloud implementationService registryMigration supported without code modification
Spring Cloud AlibabaMicroservices Engine (MSE) NacosYes
Spring Cloud AlibabaSelf-managed NacosYes
Spring Cloud NetflixEurekaYes. ASM version 1.13.4.53 or later.
Spring Cloud ConsulConsulYes. ASM version 1.13.4.53 or later.
Spring Cloud ZookeeperZookeeperYes. ASM version 1.13.4.53 or later.

How it works

Spring Cloud applications rely on a service registry (Nacos, Eureka, Consul, or Zookeeper) for service discovery. ASM bridges this registry-based discovery with Istio's mesh-native model by intercepting registry traffic through an EnvoyFilter. After interception, sidecar proxies resolve service names to pod IPs, and Istio CRDs govern all traffic between services.

Two methods enable this bridge on the ASM control plane:

MethodSupported registriesRequirements
Method 1: Reverse DNSAll registriesASM 1.13.4.32 or later
Method 2: Lua filterNacos onlyNacos client SDK earlier than 2.0 (v2.0+ uses gRPC, incompatible with Lua)

Prerequisites

Before you begin, make sure that you have:

Demo architecture

This tutorial uses a Spring Cloud Nacos demo with three services:

  • Consumer service: Exposes port 8080 with an /echo endpoint. Forwards requests to the provider service and returns the response.

  • Provider service (V1): Responds with Hello Nacos Discovery From v1<parameter>.

  • Provider service (V2): Responds with Hello Nacos Discovery From v2<parameter>.

Both provider versions register with the Nacos registry. The consumer discovers them through Nacos and distributes requests across V1 and V2 in round-robin fashion.

For example, a request to /echo/world returns either Hello Nacos Discovery From v1world or Hello Nacos Discovery From v2world.

Demo architecture

Download the demo source code from the nacos-examples repository.

Without sidecar injection, these services work normally but are invisible to Istio. The following steps add mesh-based traffic management on top of the existing Spring Cloud service discovery.

Step 1: Enable Spring Cloud support on the ASM control plane

Method 1: Reverse DNS (all registries)

Note

Requires ASM 1.13.4.32 or later.

Important
  • A Kubernetes service must exist as the destination service. The service port and destination port must match the port through which the application is routed via a Server Load Balancer (SLB) instance.

  • For ASM 1.23.6.32 or later, disable REGISTRY_ONLY.

  1. Connect kubectl to the ASM control plane. See Use kubectl on the control plane to access Istio resources.

  2. Create a file named any-spring-cloud-support.yaml: Replace the following values based on your environment:

    ParameterDescriptionWhere to find it
    portNumberPort of your Spring Cloud service. Remove this parameter to match all ports, or create separate EnvoyFilter resources to target specific ports.Application configuration
    pod_cidrsPod CIDR block of the ACK or ACK Serverless cluster.In the Container Service Management Console, go to Clusters, click your cluster, and open the Cluster Resources tab. Click the VPC link to view the vSwitch CIDR block.
       apiVersion: networking.istio.io/v1alpha3
       kind: EnvoyFilter
       metadata:
         labels:
           provider: "asm"
           asm-system: "true"
         name: any-spring-cloud-support
         namespace: istio-system
       spec:
         configPatches:
         - applyTo: HTTP_FILTER
           match:
             proxy:
               proxyVersion: "^1.*"
             context: SIDECAR_OUTBOUND
             listener:
               portNumber: 8070
               filterChain:
                 filter:
                   name: "envoy.filters.network.http_connection_manager"
                   subFilter:
                     name: "envoy.filters.http.router"
           patch:
             operation: INSERT_BEFORE
             value:
              name: com.aliyun.reverse_dns
              typed_config:
                "@type": "type.googleapis.com/udpa.type.v1.TypedStruct"
                type_url: type.googleapis.com/envoy.config.filter.reverse_dns.v3alpha.CommonConfig
                value:
                  pod_cidrs:
                  - "10.0.128.0/18"
  3. Apply the EnvoyFilter:

       kubectl apply -f any-spring-cloud-support.yaml

Method 2: Lua filter (Nacos only)

  1. Connect kubectl to the ASM control plane. See Use kubectl on the control plane to access Istio resources.

  2. Create a file named external-nacos-svc.yaml to define a service entry for the Nacos server: Replace <your-nacos-server-host> with the Nacos server endpoint (for example, mse-xxx-p.nacos-ans.mse.aliyuncs.com). Port 8848 is the default Nacos port. If your self-managed Nacos uses a different port, update the number value.

       kind: ServiceEntry
       metadata:
         name: external-nacos-svc
       spec:
         hosts:
         - "<your-nacos-server-host>"  # Example: mse-xxx-p.nacos-ans.mse.aliyuncs.com
         location: MESH_EXTERNAL
         ports:
         - number: 8848
           name: http
         resolution: DNS
  3. Apply the service entry:

       kubectl apply -f external-nacos-svc.yaml
  4. Create a file named external-envoyfilter.yaml for the Lua-based EnvoyFilter:

       apiVersion: networking.istio.io/v1alpha3
       kind: EnvoyFilter
       metadata:
         labels:
           provider: "asm"
           asm-system: "true"
         name: nacos-subscribe-lua
         namespace: istio-system
       spec:
         configPatches:
         - applyTo: HTTP_FILTER
           match:
             proxy:
               proxyVersion: "^1.*"
             context: SIDECAR_OUTBOUND
             listener:
               portNumber: 8848
               filterChain:
                 filter:
                   name: "envoy.filters.network.http_connection_manager"
                   subFilter:
                     name: "envoy.filters.http.router"
           patch:
             operation: INSERT_BEFORE
             value:
              name: envoy.lua
              typed_config:
                 "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
                 inlineCode: |
                    -- copyright: ASM (Alibaba Cloud ServiceMesh)
                    function envoy_on_request(request_handle)
                      local request_headers = request_handle:headers()
                      local path = request_headers:get(":path")
                      if string.match(path,"^/nacos/v1/ns/instance/list") then
                        local servicename = string.gsub(path,".*&serviceName.*40([%w.\\_\\-]+)&.*","%1")
                        request_handle:streamInfo():dynamicMetadata():set("context", "request.path", path)
                        request_handle:streamInfo():dynamicMetadata():set("context", "request.servicename", servicename)
                        request_handle:logInfo("subscribe for serviceName: " .. servicename)
                      else
                        request_handle:streamInfo():dynamicMetadata():set("context", "request.path", "")
                      end
                    end
                    function envoy_on_response(response_handle)
                      local request_path = response_handle:streamInfo():dynamicMetadata():get("context")["request.path"]
                      if request_path == "" then
                         return
                      end
                      local servicename = response_handle:streamInfo():dynamicMetadata():get("context")["request.servicename"]
                      response_handle:logInfo("modified response ip to serviceName:" .. servicename)
                      local bodyObject = response_handle:body(true)
                      local body= bodyObject:getBytes(0,bodyObject:length())
                      body = string.gsub(body,"%s+","")
                      body = string.gsub(body,"(ip\":\")(%d+.%d+.%d+.%d+)","%1"..servicename)
                      response_handle:body():setBytes(body)
                    end
  5. Apply the EnvoyFilter:

       kubectl apply -f external-envoyfilter.yaml

Step 2: Deploy Spring Cloud services

Important

Apply the EnvoyFilter from Step 1 before deploying services. The filter must be in place to intercept the service registration process. If services are already deployed, trigger a rolling update on those deployments.

Note

Each Spring Cloud service requires a Kubernetes service resource with a cluster IP address.

  1. Connect kubectl to the ACK data plane. See Obtain the kubeconfig file of a cluster.

  2. Deploy the demo services: Replace <your-nacos-endpoint> with the endpoint of your MSE Nacos registry or self-managed Nacos registry.

       # Set the Nacos registry endpoint (VPC endpoint recommended)
       export NACOS_ADDRESS=<your-nacos-endpoint>
    
       # Download and apply the demo deployment
       wget https://alibabacloudservicemesh.oss-cn-beijing.aliyuncs.com/asm-labs/springcloud/demo.yaml -O demo.yaml
       sed -e "s/NACOS_SERVER_CLUSTERIP/$NACOS_ADDRESS/g" demo.yaml | kubectl apply -f -
  3. Verify that all pods are running with 2/2 containers (application + sidecar): Expected output: The 2/2 in the READY column confirms that both the application container and the Envoy sidecar proxy are running.

       kubectl get pods
       consumer-bdd464654-jn8q7       2/2     Running     0          25h
       provider-v1-66bc67fb6d-46pgl   2/2     Running     0          25h
       provider-v2-76568c45f6-85z87   2/2     Running     0          25h

Step 3: Create an Istio gateway and virtual service

  1. Create a file named test-gateway.yaml for the Istio gateway:

       apiVersion: networking.istio.io/v1alpha3
       kind: Gateway
       metadata:
         name: test-gateway
       spec:
         selector:
           istio: ingressgateway
         servers:
         - port:
             number: 80
             name: http
             protocol: HTTP
           hosts:
           - "*"
  2. Connect kubectl to the ASM control plane and apply the gateway:

       kubectl apply -f test-gateway.yaml
  3. Create a file named consumer.yaml for a virtual service that routes incoming traffic to the consumer:

       apiVersion: networking.istio.io/v1alpha3
       kind: VirtualService
       metadata:
         name: consumer
       spec:
         hosts:
         - "*"
         gateways:
         - test-gateway
         http:
         - match:
           - uri:
               prefix: /
           route:
           - destination:
               host: consumer.default.svc.cluster.local
               port:
                 number: 8080
  4. Apply the virtual service:

       kubectl apply -f consumer.yaml

Step 4: Verify traffic management

This step confirms that ASM controls Spring Cloud traffic. First, observe the default round-robin behavior without routing rules, then apply Istio routing rules and verify the change.

Observe default behavior (before routing rules)

  1. Get the ingress gateway IP address:

    1. Log on to the ASM console.

    2. In the left-side navigation pane, choose Service Mesh > Mesh Management.

    3. Click your ASM instance name, then choose ASM Gateways > Ingress Gateway.

    4. Note the Service address on the Ingress Gateway page.

  2. Send several requests to the consumer service: The responses alternate between V1 and V2 in round-robin fashion: This confirms that the consumer discovers both provider versions through Nacos and distributes traffic evenly. No Istio routing rules are in effect yet.

       curl <ingress-gateway-ip>/echo/world
       Hello Nacos Discovery From v1world
       Hello Nacos Discovery From v2world
       Hello Nacos Discovery From v1world
       Hello Nacos Discovery From v2world

Apply routing rules (after)

  1. Create a file named service-provider.yaml to define a destination rule with version-based subsets:

       apiVersion: networking.istio.io/v1alpha3
       kind: DestinationRule
       metadata:
         name: service-provider
       spec:
         host: service-provider
         subsets:
         - name: v1
           labels:
             label: v1
         - name: v2
           labels:
             label: v2
  2. Apply the destination rule:

       kubectl apply -f service-provider.yaml
  3. Create a file named service-provider-vs.yaml to define a virtual service that routes /echo/hello requests to V1 and all other requests to V2:

       apiVersion: networking.istio.io/v1alpha3
       kind: VirtualService
       metadata:
         name: service-provider
       spec:
         hosts:
         - service-provider
         http:
         - name: "hello-v1"
           match:
           - uri:
               prefix: "/echo/hello"
           route:
           - destination:
               host: service-provider
               subset: v1
         - name: "default"
           route:
           - destination:
               host: service-provider
               subset: v2
  4. Apply the virtual service:

       kubectl apply -f service-provider-vs.yaml
  5. Test the routing rules: All responses now come from V1 only: Compare this with the round-robin behavior observed earlier: /echo/hello requests now route exclusively to V1, while all other requests go to V2. Istio CRDs have taken over Spring Cloud traffic routing, confirming that ASM manages the services.

       curl <ingress-gateway-ip>/echo/hello
       Hello Nacos Discovery From v1hello
       Hello Nacos Discovery From v1hello

FAQ

Traffic is not intercepted by the mesh

Check whether traffic blocking is enabled for the port or IP address of the registry:

  • Method 1 (reverse DNS): You must block the IP address of the pod. Make sure the pod_cidrs value in your EnvoyFilter covers the correct pod CIDR block of your ACK cluster.

  • Method 2 (Lua filter): You must block the Nacos server IP address and the cluster IP address.

Services are not registering correctly

This usually happens when the EnvoyFilter was not in place before the services started. The filter must intercept the registration process from the beginning. Restart the affected deployments:

kubectl rollout restart deployment <deployment-name>

Also confirm that each Spring Cloud service has a corresponding Kubernetes service resource with a cluster IP address.

Routing rules are not taking effect

Two common causes:

  1. Nacos client SDK version (Method 2 only): Method 2 requires Nacos client SDK earlier than 2.0. Version 2.0+ uses gRPC instead of HTTP, which is incompatible with the Lua filter. Switch to Method 1 if your Nacos client SDK is 2.0 or later -- Method 1 works with all Nacos versions.

  2. Outdated sidecar version: If the sidecar image version is earlier than 1.13.4.32, the data plane may not have been updated after a control plane upgrade. Restart the affected deployments to pick up the latest sidecar version.