随着微服务的大势不断前进,企业业务逐渐复杂,开发者不得不将原本的一个单体架构,演变成十几个甚至几十上百个微服务来对业务进行拆解。服务增加后,开发者发现多个服务相互通信带来的服务发现问题,网络访问的容错保护,访问安全等问题开始变得复杂起来,就连最简单的查看调用栈实现故障的定位,都变得十分困难。
面对日益凸显的问题,开发者需要一整套针对性的服务治理方案,这套方案能帮助开发者解决由于服务数量的增多带来的网络层面的各种麻烦。微服务SDK曾经是一个常用的解决方案。将微服务化后通用的能力封装在一个开发框架中,开发者使用这个框架开发写自己的业务代码,生成的微服务自然就内置了这些能力。在很长的一段时间内,这种形态是微服务治理的标配,最为典型的例子就是 Spring Cloud,很多开发者甚至以为Spring Cloud就代表着微服务。
随着Kubernetes的流行,云原生的概念又一次推动技术变革,以Service Mesh理念为基础出现了以Istio为代表的云原生服务治理中间件,Istio为部署在Kubernetes的应用增加了完备的服务治理功能,包括流量策略、可观察性和安全通信。Istio的出现使得Kubernetes上的微服务可以在一个独立的代理进程中提供服务治理的能力。区别于曾经以Spring Cloud为代表的SDK,Istio作为一种基础设施完全和开发解耦,将服务治理的能力完全从代码中抽离,在有效降低开发难度的同时让开发者专注于自身的业务。
优劣Spring Cloud是一个开发框架,它的出发点是以开发人员的角度出发去解决微服务的问题。
Istio是Kubernetes上的一个基础设施,它的出发点是以运维平台的角度出发去解决微服务的网络问题。
通过对比我们可以发现,Spring Cloud与Istio在理念上并不存在完全的冲突,在去掉部分功能冲突的部分后可以形成优势互补,开发者既可以借助Spring Cloud在开发上的能力,又可以将运维能力从代码中抽离。
Spring Cloud向Service Mesh的迁移方案那么如何做到在改动最小的情况下进行有效的迁移呢?让我们以mall-swarm项目为例。
mall-swarm项目是mall项目的微服务化版本,是一套比较典型的电商系统,包括前台商城系统及后台管理系统,相比单体形式使用Spring Boot的mall项目,mall-swarm使用了部分SpringCloud组件做微服务化的改造,采用Docker容器化部署,github star 47.7k,是典型的Spring Cloud微服务模板。
改造开始开始前我们需要准备一个Kubernetes的集群
让我们拉取mall-swarm的代码: https://github.com/macrozheng/mall-swarm
去掉服务注册中心Spring Cloud项目向Service Mesh的迁移改造第一步其实非常简单,就是去掉服务注册中心
当然不是说服务注册中心完全无法在Kubernetes上工作,事实上很多服务注册中心都实现了兼容Kubernetes的版本。但是我们任然不推荐使用服务注册中心,理由有如下几点:
- 大多服务注册中心的实现原理是读取注册服务的IP地址进行配置,所有微服务调度都需要先去服务注册中心获取目的服务的真实IP进行访问。这就意味着服务和虚拟机是需要一个稳定的关联关系,然而在Kubernetes集群中,Pod与Node之间是非常松散的,Pod在不同Node间切换经常发生,这会导致服务注册和注销会频繁发生。
- Kubernetes本身已经提供了强大的服务发现机制,Istio是借助在Kubernetes本身提供的服务发现基础上做的流量劫持,服务读取本地IP做服务注册是无法享受到流量劫持的,也就是无法利用istio的能力
将mall-swarm上所有组件的服务注册中心的依赖去除,这样调度就不会默认走到服务注册中心去了
然后将所有服务间调度的 FeignClient 配置到service上,service名称就用项目名即可,为了方便以后改动我们可以配置到环境变量中,例如mall-admin这个服务需要调度到mall-auth服务可以这么写:
@FeignClient(name = "mall-auth", url = "${host.mall-auth}") // 直接配置到环境变量上,容易以后改动
public interface AuthService {
@PostMapping(value = "/oauth/token")
CommonResult getAccessToken(@RequestParam Map parameters);
}
只需要在application.yml中给一个默认值就可以了
host: mall-auth: http://mall-auth:8401
最后配置网关,让走网关的流量可以被路由到正确的位置
server:
port: 8201
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true #使用小写service-id
routes: #配置路由路径 这里全部更改为service名称
- id: mall-auth
uri: http://mall-auth:8401
predicates:
- Path=/mall-auth/**
filters:
- StripPrefix=1
- id: mall-admin
uri: http://mall-admin:8080
predicates:
- Path=/mall-admin/**
filters:
- StripPrefix=1
- id: mall-portal
uri: http://mall-portal:8085
predicates:
- Path=/mall-portal/**
filters:
- StripPrefix=1
- id: mall-search
uri: http://mall-search:8081
predicates:
- Path=/mall-search/**
filters:
- StripPrefix=1
- id: mall-demo
uri: http://mall-demo
predicates:
- Path=/mall-demo/**
filters:
- StripPrefix=1
- id: mall-admin-web
uri: http://mall-admin-web:8080
predicates:
- Path=/mall-admin-web/**
filters:
- StripPrefix=1
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: 'http://localhost:8201/mall-auth/rsa/publicKey' #配置RSA的公钥访问地址
redis:
database: 0
port: 6379
host: localhost
password:
secure:
ignore:
urls: #配置白名单路径
- "/doc.html"
- "/swagger-resourcesv2/api-docs"
- "*.js"
- "*.css"
- "*.png"
- "*.ico"
- "/webjars/springfox-swagger-ui/**"
- "/actuator/**"
- "/mall-auth/oauth/token"
- "/mall-auth/rsa/publicKey"
- "/mall-search/**"
- "/mall-portal/sso/login"
- "/mall-portal/sso/register"
- "/mall-portal/sso/getAuthCode"
- "/mall-portal/home/**"
- "/mall-portal/product/**"
- "/mall-portal/brand/**"
- "/mall-admin/admin/login"
- "/mall-admin/admin/register"
- "/mall-admin/minio/upload"
- "/mall-admin-web/**"
management: #开启SpringBoot Admin的监控
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
这样做完,我们服务的所有改造工作就完成了,只需要将代码重新编译打成docker的image即可交付,接下来就是运维的工作了
添加label在mall-swarm的document/k8s文件夹下面提供了部署k8s所需的yaml,我们需要对这些yaml添加必要的label,才能让istio发现它们
在控制器和template中添加 app,version 2个label,例如mall-admin这个服务
apiVersion: apps/v1
kind: Deployment
metadata:
name: mall-admin
namespace: mall
labels:
app: mall-admin # 添加 app
version: v1 # 添加 version
spec:
replicas: 1
selector:
matchLabels:
app: mall-admin
template:
metadata:
labels:
app: mall-admin # 添加 app
version: v1 # 添加 version
spec:
restartPolicy: Always
containers:
- name: mall-admin
# 指定Docker Hub中的镜像地址
image: harbor.cloud2go.cn/macrodocker/mall-admin:1.0-SNAPSHOT
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
# 指定环境
- name: spring.profiles.active
value: prod
# 指定时区
- name: TZ
value: Asia/Shanghai
- name: spring_datasource_url
value: jdbc:mysql://mall-mysql:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
- name: spring_elasticsearch_rest_uris
value: elasticsearch:9200
- name: spring_redis_host
value: redis
- name: spring_rabbitmq_host
value: rabbitmq
- name: spring_rabbitmq_username
value: guest
- name: spring_rabbitmq_password
value: guest
在service中添加 app 这个label,例如mall-admin这个服务
apiVersion: v1
kind: Service
metadata:
name: mall-admin
namespace: mall
labels:
app: mall-admin # 添加 app
spec:
type: ClusterIP
selector:
app: mall-admin
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
其他服务类似,改造完成之后我们就可以部署到Kubernetes环境中了
改造完的仓库可见 https://github.com/solarmesh-cn/mall-swarm-istio
验证我们将mall-swarm项目部署进集群之后,接下来就需要安装istio了
istio我们选择1.6版本,并使用solarmesh进行安装,solarmesh是一款基于istio的云原生流量监管平台。提供应用网络观测能力,方便快捷的策略配置,安全可靠的istio使用体验。使用solarmesh能快速安装istio,并且流量视图功能将会为我们提供直观的流量拓扑图
接入sidecarsolarmesh提供了namespace级别的自动注入能力,只需要在solarmesh的页面上开启自动注入就可以了,之前我们将mall-swarm项目的所有组件都部署在mall这个namespace中
流量监控我们直接访问mall-swarm项目的前端页面,比如我们希望查看订单列表
然后访问solarmesh的流量视图页面,可以看到,流量视图已经将mall-swarm项目的服务调度清晰的展现在我们的面前
SolarMesh体验网站
有问题欢迎扫码加微信咨询



