全部產品
Search
文件中心

Alibaba Cloud Service Mesh:管理Spring Cloud服務

更新時間:Jan 14, 2025

您可以將Spring Cloud業務應用接入ASM,從而可以使用雲原生化的服務治理能力,不需要業務做任何代碼修改,即可管理Spring Cloud商務服務。本文介紹如何使用ASM管理Spring Cloud服務。

前提條件

背景資訊

Spring Cloud是一個標準,有不同的實現,例如Spring Cloud Netflix、Spring Cloud Alibaba、Spring Cloud Consul 等。不同的Spring Cloud實現對於ASM來說核心區別主要在於採用了不同的服務發現,ASM針對這些不同的Spring Cloud版本遷移支援列表如下:

Spring Cloud版本

服務發現

遷移支援 (零代碼修改)

Spring Cloud Alibaba

MSE Nacos(阿里雲上產品)

支援

Spring Cloud Alibaba

Nacos(自建)

支援

Spring Cloud Netflix

Eureka

支援,ASM版本需≥1.13.4.53

Spring Cloud Consul

Consul

支援,ASM版本需≥1.13.4.53

Spring Cloud Zookeeper

Zookeeper

支援,ASM版本需≥1.13.4.53

Demo介紹

本文以Spring Cloud+Nacos為例進行說明,Demo範例程式碼可以通過此nacos-example下載。

Spring Cloud服務包含Consumer服務和Provider服務,其中Provider有v1和v2兩個版本,並且都註冊到Nacos註冊中心。Consumer從Nacos註冊中心同步Provider服務地址進行負載平衡發起請求,其中Consumer暴露一個8080連接埠,提供了一個echo介面,對應邏輯是將請求轉寄給Provider,並輸出Provider返回的結果,不同的Provider版本返回結果不同:

  • Provider v1版本收到echo請求會返回Hello Nacos Discovery From v1xxx

  • Provider v2版本收到echo請求會返回Hello Nacos Discovery From v2xxx

其中返回結果中.xxx為echo介面對應的具體參數,例如請求/echo/world發送到Provider v1版本,則會返回Hello Nacos Discovery From v1worlddemo

若Consumer、Provider不開啟Mesh能力,即業務POD不注入Sidecar的情況下,請求可以正常訪問,但缺少Istio提供的相關服務治理能力,本文通過以下步驟,驗證ASM管理Spring Cloud服務是否成功。

步驟一:ASM控制面開啟SpringCloud能力支援

方式一:適用於所有SpringCloud版本和註冊中心

說明

ASM執行個體需為1.13.4.32及以上版本。

  1. 使用kubectl串連到控制面叢集。具體操作,請參見通過控制面kubectl訪問Istio資源

  2. 在ASM叢集下建立EnvoyFilter。

    1. 使用以下內容,建立any-spring-cloud-support.yaml

      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"

      YAML中的參數請您根據實際業務進行修改,部分參數說明如下:

      • portNumber :SpringCloud服務的連接埠。若連接埠不統一,可以刪除該參數不進行配置;若連接埠可以收斂,可以配置多個該EnvoyFilter(每個EnvoyFilter綁定一個具體portNumber。)

      • pod_cidrs:ACK或ACK Serverless叢集的Pod CIDR。您可以登入Container Service管理主控台,在叢集資訊頁面的叢集資源頁簽,查看Virtual Private Cloud絡 VPC下虛擬交換器對應的CIDR進行配置。

    2. 執行以下命令,對目標服務開啟com.aliyun.reverse_dns filter

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

方式二:僅適用於Nacos註冊中心

  1. 使用kubectl串連到控制面叢集。具體操作,請參見通過控制面kubectl訪問Istio資源

  2. 建立ServiceEntry。

    1. 使用以下內容,建立external-nacos-svc.yaml

      kind: ServiceEntry
      metadata:
        name: external-nacos-svc
      spec:
        hosts:
        - "NACOS_SERVER_HOST"  ## 需要替換為您的Nacos Server HOST,例如"mse-xxx-p.nacos-ans.mse.aliyuncs.com"。
        location: MESH_EXTERNAL
        ports:
        - number: 8848
          name: http
        resolution: DNS

      上述YAML中,8848為Nacos的預設連接埠。如果您是自建的Nacos Server且對連接埠有修改,則number參數也需要對應修改。

    2. 執行以下命令,建立ServiceEntry。

      kubectl apply -f external-nacos-svc.yaml
  3. 建立EnvoyFilter。

    1. 使用以下內容,建立external-envoyfilter.yaml

      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. 執行以下命令,建立EnvoyFilter。

      kubectl apply -f external-envoyfilter.yaml

步驟二:在ACK部署Spring Cloud服務

說明
  • 因為需要攔截註冊流程,EnvoyFilter需要先於業務工作負載Deployment之前建立。若某些業務Deployment先於EnvoyFilter建立,您需要變換該業務Deployment。

  • 商務服務需要建立Kubernetes Service資源,並且需要有Cluster IP。

  1. 使用kubectl串連到資料面叢集。具體操作,請參見擷取叢集KubeConfig並通過kubectl工具串連叢集

  2. 執行以下命令,部署Spring Cloud服務。

    export NACOS_ADDRESS=xxxx # xxxx為MSE或自建的Nacos地址,建議使用VPC內網地址。
    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. 執行以下命令,查看Spring Cloud服務。

     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

步驟三:建立網關規則和虛擬服務

  1. 建立網關規則。

    1. 使用以下內容,建立test-gateway.yaml

      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. 使用ASM的kubeconfig,執行以下命令,建立網關規則。

      kubectl apply -f test-gateway.yaml
  2. 建立虛擬服務。

    1. 使用以下內容,建立consumer.yaml

      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. 執行以下命令,建立虛擬服務。

      kubectl apply -f consumer.yaml

步驟四:驗證ASM管理Spring Cloud服務是否成功

  1. 查看Ingress Gateway的IP地址。

    1. 登入ASM控制台,在左側導覽列,選擇服務網格 > 網格管理

    2. 網格管理頁面,單擊目標執行個體名稱,然後在左側導覽列,選擇ASM網關 > 入口網關

    3. 入口網關頁面,查看Ingress Gateway的服務地址

  2. 執行以下命令,通過Ingress Gateway向Spring Cloud Consumer服務發起請求。

    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

    可以看到Provider預設在v1、v2版本間輪詢訪問。

  3. 建立目標規則和虛擬服務。

    1. 使用以下內容,建立service-provider.yaml

      ---
      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. 執行以下命令,建立目標規則。

      kubectl apply -f service-provider.yaml
    3. 使用以下內容,建立service-provider1.yaml

      以下虛擬服務定義了/echo/hello的請求將被路由到Provider v1版本,其他請求將被路由到Provider 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. 執行以下命令,建立虛擬服務。

      kubectl apply -f service-provider1.yaml
  4. 執行以下命令,向Spring Cloud Consumer服務發起請求。

    curl <Ingress Gateway的IP地址>/echo/hello

    預期輸出:

    Hello Nacos Discovery From v1hello
    Hello Nacos Discovery From v1hello

    可以看到/echo/hello請求都被路由到Provider v1版本,其他請求則會路由到Provider v2版本。說明Spring Cloud流量被Istio接管,並可以支援使用Istio方式配置相關路由規則,管理Spring Cloud服務成功。

FAQ

為什麼部署的SpringCloud商務服務不生效?

  1. 檢查是否開啟了針對Nacos連接埠或者IP的流量攔截。

    • 若採用reverse_dns方式,需要攔截Pod IP。

    • 若採用Lua指令碼方式,需要攔截Nacos Server IP和Cluster IP。

  2. 因為需要攔截註冊流程,EnvoyFilter需要先於業務工作負載Deployment之前建立。若某些業務Deployment先於EnvoyFilter建立,您需要變換該業務Deployment。

  3. 檢查商務服務是否建立了Kubernetes Service資源,並且Type類型為Cluster IP。

  4. 查看ASM控制面開啟SpringCloud能力的方式。

    若採用方式二,Nacos Client SDK版本需低於2.0。Nacos 2.0版本以上的Client SDK採用GRPC和服務端建立串連,方式二不適用。方式一對Nacos版本沒有依賴,支援任意Nacos版本。

  5. 檢查相關服務的Sidecar版本,若Sidecar鏡像版本低於v1.13.4.32,可能存在僅升級了ASM執行個體控制面,未升級資料面的情況,需要將對應服務的Deployment進行變換。