您可以将Spring Cloud业务应用接入ASM,从而可以使用云原生化的服务治理能力,不需要业务做任何代码修改,即可管理Spring Cloud业务服务。本文介绍如何使用ASM管理Spring Cloud服务。
前提条件
已创建ASM企业版或旗舰版实例。具体操作,请参见创建ASM实例。
已创建Kubernetes托管版集群。具体操作,请参见创建ACK托管集群。
已添加集群到ASM实例。具体操作,请参见添加集群到ASM实例。
已部署入口网关。具体操作,请参见创建入口网关。
背景信息
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 v1world
。
若Consumer、Provider不开启Mesh能力,即业务POD不注入Sidecar的情况下,请求可以正常访问,但缺少Istio提供的相关服务治理能力,本文通过以下步骤,验证ASM管理Spring Cloud服务是否成功。
步骤一:ASM控制面开启SpringCloud能力支持
方式一:适用于所有SpringCloud版本和注册中心
ASM实例需为1.13.4.32及以上版本。
使用kubectl连接到控制面集群。具体操作,请参见通过控制面kubectl访问Istio资源。
在ASM集群下创建EnvoyFilter。
使用以下内容,创建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。您可以登录容器服务管理控制台,在集群信息页面的集群资源页签,查看虚拟专有网络 VPC下虚拟交换机对应的CIDR进行配置。
执行以下命令,对目标服务开启
com.aliyun.reverse_dns filter
。kubectl apply -f any-spring-cloud-support.yaml
方式二:仅适用于Nacos注册中心
使用kubectl连接到控制面集群。具体操作,请参见通过控制面kubectl访问Istio资源。
创建ServiceEntry。
使用以下内容,创建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
参数也需要对应修改。执行以下命令,创建ServiceEntry。
kubectl apply -f external-nacos-svc.yaml
创建EnvoyFilter。
使用以下内容,创建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
执行以下命令,创建EnvoyFilter。
kubectl apply -f external-envoyfilter.yaml
步骤二:在ACK部署Spring Cloud服务
因为需要拦截注册流程,EnvoyFilter需要先于业务工作负载Deployment之前创建。若某些业务Deployment先于EnvoyFilter创建,您需要滚动更新该业务Deployment。
业务服务需要创建Kubernetes Service资源,并且需要有Cluster IP。
使用kubectl连接到数据面集群。具体操作,请参见获取集群KubeConfig并通过kubectl工具连接集群。
执行以下命令,部署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 -
执行以下命令,查看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
步骤三:创建网关规则和虚拟服务
创建网关规则。
使用以下内容,创建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: - "*"
使用ASM的kubeconfig,执行以下命令,创建网关规则。
kubectl apply -f test-gateway.yaml
创建虚拟服务。
使用以下内容,创建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
执行以下命令,创建虚拟服务。
kubectl apply -f consumer.yaml
步骤四:验证ASM管理Spring Cloud服务是否成功
查看Ingress Gateway的IP地址。
登录ASM控制台,在左侧导航栏,选择 。
在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择 。
在入口网关页面,查看Ingress Gateway的服务地址。
执行以下命令,通过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版本间轮询访问。
创建目标规则和虚拟服务。
使用以下内容,创建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
执行以下命令,创建目标规则。
kubectl apply -f service-provider.yaml
使用以下内容,创建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
执行以下命令,创建虚拟服务。
kubectl apply -f service-provider1.yaml
执行以下命令,向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业务服务不生效?
检查是否开启了针对Nacos端口或者IP的流量拦截。
若采用reverse_dns方式,需要拦截Pod IP。
若采用Lua脚本方式,需要拦截Nacos Server IP和Cluster IP。
因为需要拦截注册流程,EnvoyFilter需要先于业务工作负载Deployment之前创建。若某些业务Deployment先于EnvoyFilter创建,您需要滚动更新该业务Deployment。
检查业务服务是否创建了Kubernetes Service资源,并且Type类型为Cluster IP。
查看ASM控制面开启SpringCloud能力的方式。
检查相关服务的Sidecar版本,若Sidecar镜像版本低于v1.13.4.32,可能存在仅升级了ASM实例控制面,未升级数据面的情况,需要将对应服务的Deployment进行滚动更新。