您可以将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 v1world
。

若Consumer、Provider不开启Mesh能力,即业务POD不注入Sidecar的情况下,请求可以正常访问,但缺少Istio提供的相关服务治理能力,本文通过以下步骤,验证ASM管理Spring Cloud服务是否成功。
步骤一:ASM控制面开启SpringCloud能力支持
方式一:适用于所有SpringCloud版本和注册中心
说明 ASM实例需为1.13.4.32及以上版本。
- 通过控制面kubectl访问Istio资源。
- 在ASM集群下创建EnvoyFilter。
通过EnvoyFilter针对目标服务开启com.aliyun.reverse_dns filter
。
- 使用以下内容,创建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或ASK集群的Pod CIDR。您可以登录容器服务管理控制台,在集群信息页面的基本信息页签,查看Pod CIDR。若容器网络插件采用Terway ,您可以在集群信息页面的集群资源页签,查看Pod虚拟交换机对应的CIDR进行配置。
方式二:仅适用于Nacos注册中心
- 通过控制面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。
- 获取集群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 -
关于创建Nacos引擎的具体操作,请参见创建Nacos引擎。
- 执行以下命令,查看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
步骤三:创建网关规则和虚拟服务
- 通过控制面kubectl访问Istio资源。
- 创建网关规则。
- 使用以下内容,创建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:
- "*"
- 执行以下命令,创建网关规则。
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能力的方式。
若采用
方式二,Nacos Client SDK版本需低于2.0。Nacos 2.0版本以上的Client SDK采用GRPC和服务端建立连接,
方式二不适用。
方式一对Nacos版本没有依赖,支持任意Nacos版本。
- 检查相关服务的Sidecar版本,若Sidecar镜像版本低于v1.13.4.32,可能存在仅升级了ASM实例控制面,未升级数据面的情况,需要将对应服务的Deployment进行滚动更新。