Manage Spring Cloud services

更新时间:
复制 MD 格式

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

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

Note

The ASM instance version must be 1.13.4.32 or later.

Important

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.

  1. Connect to the control plane cluster by using kubectl. For more information, see Access Istio resources on the control plane by using kubectl.

  2. Create an EnvoyFilter in the ASM cluster.

    1. 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 specific portNumber.

      • 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.

    2. Run the following command to apply the EnvoyFilter.

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

Method 2: For Nacos registries only

  1. Connect to the control plane cluster by using kubectl. For more information, see Access Istio resources on the control plane by using kubectl.

  2. Create a ServiceEntry.

    1. 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: DNS

      In the preceding YAML file, 8848 is the default port for Nacos. If you use a self-managed Nacos server and have changed the port, you must also modify the number parameter accordingly.

    2. Run the following command to create the ServiceEntry.

      kubectl apply -f external-nacos-svc.yaml
  3. Create an EnvoyFilter.

    1. 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
    2. Run the following command to create the EnvoyFilter.

      kubectl apply -f external-envoyfilter.yaml

Step 2: Deploy Spring Cloud services

Note
  • 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.

  1. 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.

  2. 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.

  3. Run the following command to check the Spring Cloud services.

     kubectl get pods

    Expected 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

  1. Create an Istio gateway.

    1. 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:
          - "*"
    2. Use the kubeconfig file of the ASM instance and run the following command to create the Istio gateway.

      kubectl apply -f test-gateway.yaml
  2. Create a virtual service.

    1. 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
    2. Run the following command to create the virtual service.

      kubectl apply -f consumer.yaml

Step 4: Verify service management

  1. Obtain the IP address of the ingress gateway.

    1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

    2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose ASM Gateways > Ingress Gateway.

    3. On the Ingress Gateway page, view the Service address of the ingress gateway.

  2. 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/world

    Expected output:

    Hello Nacos Discovery From v1world
    Hello Nacos Discovery From v2world
    Hello Nacos Discovery From v1world
    Hello Nacos Discovery From v2world

    The output shows that requests are routed to the v1 and v2 providers in a round-robin fashion by default.

  3. Create a destination rule and a virtual service.

    1. 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
                                      
    2. Run the following command to create the destination rule.

      kubectl apply -f service-provider.yaml
    3. 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
    4. Run the following command to create the virtual service.

      kubectl apply -f service-provider1.yaml
  4. Run the following command to send a request to the Spring Cloud consumer service.

    curl <IP address of the ingress gateway>/echo/hello

    Expected output:

    Hello Nacos Discovery From v1hello
    Hello Nacos Discovery From v1hello

    The output shows that all requests to /echo/hello are 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

  1. 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.

  2. 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.

  3. Check that a Kubernetes Service of the ClusterIP type exists for each service.

  4. Check which method you used to enable Spring Cloud support on the ASM control plane.

    If you use Method 2, the Nacos client SDK version must be earlier than 2.0. Nacos client SDK 2.0 and later uses gRPC to connect to the server, which makes Method 2 incompatible. Method 1 has no dependency on the Nacos version and supports all Nacos versions.

  5. 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.