You can integrate your Spring Cloud applications with Service Mesh (ASM) to leverage cloud-native service governance capabilities without modifying your code. This topic describes how to use ASM to manage Spring Cloud services.
Prerequisites
-
You have an ASM Enterprise or Ultimate Edition instance. For more information, see Create an ASM instance.
An ACK managed cluster is created. For more information, see Create an ACK managed cluster.
An ingress gateway is deployed. For more information, see Create an ingress gateway.
Background
Spring Cloud is a standard with various implementations, such as Spring Cloud Netflix, Spring Cloud Alibaba, and Spring Cloud Consul. For ASM, the key difference between these implementations is the service registry they use. The following table lists the ASM migration support for different Spring Cloud versions.
|
Spring Cloud version |
Service registry |
Migration support |
|
Spring Cloud Alibaba |
Microservices Engine (MSE) Nacos (an Alibaba Cloud service) |
Supported |
|
Spring Cloud Alibaba |
Nacos (self-managed) |
Supported |
|
Spring Cloud Netflix |
Eureka |
Supported. The ASM instance version must be 1.13.4.53 or later. |
|
Spring Cloud Consul |
Consul |
Supported. The ASM instance version must be 1.13.4.53 or later. |
|
Spring Cloud Zookeeper |
Zookeeper |
Supported. The ASM instance version must be 1.13.4.53 or later. |
Demo overview
This topic uses an application built with Spring Cloud and Nacos as an example. You can download the sample code from the nacos-example repository.
The application consists of a consumer service and a provider service. The provider service has two versions, v1 and v2, both registered with a Nacos registry. The consumer service fetches the provider service addresses from the Nacos registry and load-balances requests between them. When the consumer service receives a request, it forwards the request to a provider and returns the provider's response. The two provider versions return different responses:
-
The v1 provider responds to an echo request with
Hello Nacos Discovery From v1xxx. -
The v2 provider responds to an echo request with
Hello Nacos Discovery From v2xxx.
In the response, .xxx is a placeholder for the parameter passed to the echo API. For example, if a request to /echo/world is sent to the v1 provider, it returns Hello Nacos Discovery From v1world.
If you do not enable the service mesh capabilities for the consumer and provider services, meaning no sidecars are injected into the application pods, requests will still be processed but will lack the service governance capabilities provided by Istio. The following steps demonstrate how to use ASM to manage the Spring Cloud services.
Step 1: Enable Spring Cloud support
Method 1: For all versions and registries
The ASM instance version must be 1.13.4.32 or later.
Limitations:
-
You must create a Kubernetes Service for the destination service. The service port and target port must be set to the listening port of the application.
-
In ASM versions earlier than 1.23.6.32, you must disable REGISTRY_ONLY when you use this solution.
-
Connect to the control plane cluster by using kubectl. For more information, see Access Istio resources on the control plane by using kubectl.
-
Create an EnvoyFilter in the ASM cluster.
-
Create a file named any-spring-cloud-support.yaml with the following content.
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: # reverse_dns filter specification 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"Modify the parameters in the YAML file based on your business requirements. The parameters are described as follows:
-
portNumber: The port of the Spring Cloud service. If the ports are not uniform, you can remove this parameter. If the ports can be consolidated, you can configure multiple EnvoyFilter resources, each binding to a specificportNumber. -
pod_cidrs: The pod CIDR of the ACK or ACK Serverless cluster. To find this value, log on to the Container Service Management Console and go to the Cluster Information page. On the Cluster Resources tab, find the Pod CIDR block under VPC and use this value for the parameter.
-
-
Run the following command to apply the
EnvoyFilter.kubectl apply -f any-spring-cloud-support.yaml
-
Method 2: For Nacos registries only
-
Connect to the control plane cluster by using kubectl. For more information, see Access Istio resources on the control plane by using kubectl.
-
Create a ServiceEntry.
-
Create a file named external-nacos-svc.yaml with the following content.
kind: ServiceEntry metadata: name: external-nacos-svc spec: hosts: - "NACOS_SERVER_HOST" ## Replace this with your Nacos Server HOST, for example, "mse-xxx-p.nacos-ans.mse.aliyuncs.com". location: MESH_EXTERNAL ports: - number: 8848 name: http resolution: DNSIn the preceding YAML file,
8848is the default port for Nacos. If you use a self-managed Nacos server and have changed the port, you must also modify thenumberparameter accordingly. -
Run the following command to create the ServiceEntry.
kubectl apply -f external-nacos-svc.yaml
-
-
Create an EnvoyFilter.
-
Create a file named external-envoyfilter.yaml with the following content.
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: labels: provider: "asm" asm-system: "true" name: nacos-subscribe-lua namespace: istio-system spec: configPatches: # The first patch adds the lua filter to the listener/http connection manager. - 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: # lua filter specification 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() -- /nacos/v1/ns/instance/list?healthyOnly=false&namespaceId=public&clientIP=10.122.63.81&serviceName=DEFAULT_GROUP%40%40service-provider&udpPort=53174&encoding=UTF-8 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 -
Run the following command to create the EnvoyFilter.
kubectl apply -f external-envoyfilter.yaml
-
Step 2: Deploy Spring Cloud services
-
To intercept the registration process, you must create the EnvoyFilter before you create the workloads. If a workload is created before the EnvoyFilter, you must perform a rolling update for that workload.
-
You must create a Kubernetes Service of the ClusterIP type for each service.
-
Connect to the data plane cluster by using kubectl. For more information, see Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.
-
Run the following commands to deploy the Spring Cloud services.
export NACOS_ADDRESS=xxxx # Replace xxxx with the address of your MSE or self-managed Nacos. We recommend using an internal VPC address. 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 -For more information about how to create a Nacos engine, see Create a Nacos engine.
-
Run the following command to check the Spring Cloud services.
kubectl get podsExpected output:
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 a gateway and virtual service
-
Create an Istio gateway.
-
Create a file named test-gateway.yaml with the following content.
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: test-gateway spec: selector: istio: ingressgateway # use istio default controller servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" -
Use the kubeconfig file of the ASM instance and run the following command to create the Istio gateway.
kubectl apply -f test-gateway.yaml
-
-
Create a virtual service.
-
Create a file named consumer.yaml with the following content.
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 -
Run the following command to create the virtual service.
kubectl apply -f consumer.yaml
-
Step 4: Verify service management
-
Obtain the IP address of the ingress gateway.
-
Log on to the ASM console. In the left-side navigation pane, choose .
-
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose .
-
On the Ingress Gateway page, view the Service address of the ingress gateway.
-
-
Run the following command to send a request to the Spring Cloud consumer service through the ingress gateway.
curl <IP address of the ingress gateway>/echo/worldExpected output:
Hello Nacos Discovery From v1world Hello Nacos Discovery From v2world Hello Nacos Discovery From v1world Hello Nacos Discovery From v2worldThe output shows that requests are routed to the v1 and v2 providers in a round-robin fashion by default.
-
Create a destination rule and a virtual service.
-
Create a file named service-provider.yaml with the following content.
--- 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 -
Run the following command to create the destination rule.
kubectl apply -f service-provider.yaml -
Create a file named service-provider1.yaml with the following content.
The following virtual service routes requests to /echo/hello to the v1 provider and routes all other requests to the v2 provider.
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 -
Run the following command to create the virtual service.
kubectl apply -f service-provider1.yaml
-
-
Run the following command to send a request to the Spring Cloud consumer service.
curl <IP address of the ingress gateway>/echo/helloExpected output:
Hello Nacos Discovery From v1hello Hello Nacos Discovery From v1helloThe output shows that all requests to
/echo/helloare routed to the v1 provider, while other requests are routed to the v2 provider. This confirms that Istio now controls the Spring Cloud traffic, allowing you to manage the services by using Istio routing rules.
FAQ
Troubleshooting Spring Cloud services
-
Check whether traffic interception is enabled for the Nacos port or IP address.
-
If you use the reverse_dns method, you must intercept pod IP addresses.
-
If you use the Lua script method, you must intercept the Nacos Server IP address and cluster IP address.
-
-
To intercept the registration process, you must create the EnvoyFilter before the workloads. If a workload was created first, you must perform a rolling update on it.
-
Check that a Kubernetes Service of the ClusterIP type exists for each service.
-
Check which method you used to enable Spring Cloud support on the ASM control plane.
-
Check the sidecar version of the services. If the sidecar image version is earlier than 1.13.4.32, only the control plane of the ASM instance was upgraded, but not the data plane. You need to perform a rolling update on the affected service deployments.