当Istio遇到mall之改造篇


随着微服务的大势不断前进,企业业务逐渐复杂,开发者不得不将原本的一个单体架构,演变成十几个甚至几十上百个微服务来对业务进行拆解。服务增加后,开发者发现多个服务相互通信带来的服务发现问题,网络访问的容错保护,访问安全等问题开始变得复杂起来,就连最简单的查看调用栈实现故障的定位,都变得十分困难。

面对日益凸显的问题,开发者需要一整套针对性的服务治理方案,这套方案能帮助开发者解决由服务数量的增多带来的网络层面的各种麻烦。

微服务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的版本。但是我们任然不推荐使用服务注册中心,理由如下:

1.大多服务注册中心的实现原理是读取注册服务的IP地址进行配置,所有微服务调度都需要先去服务注册中心获取目的服务的真实IP进行访问。这就意味着服务和虚拟机是需要一个稳定的关联关系,然而在Kubernetes集群中,Pod与Node之间是非常松散的,Pod在不同Node间切换经常发生,这会导致服务注册和注销会频繁发生

2.Kubernetes本身已经提供了强大的服务发现机制,Istio是借助在Kubernetes本身提供的服务发现基础上做的流量劫持,服务读取本地IP做服务注册是无法享受到流量劫持的,也就是无法利用istio的能力

将mall-swarm上所有组件的服务注册中心的依赖去掉,这样调度就不会默认走到服务注册中心去。
<!--        <dependency>-->
<!--            <groupId>com.alibaba.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>-->
<!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>com.alibaba.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>-->
<!--        </dependency>-->


接着将所有服务间调度的 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<String, String> 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-resources/**"
  - "/swagger/**"
  - "/**/v2/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,并且流量视图功能将会提供直观的流量拓扑图。

接入sidecar

solarmesh提供了namespace级别的自动注入能力,只需要在solarmesh的页面上开启自动注入就可以了,之前我们将mall-swarm项目的所有组件都部署在mall这个namespace中。

微信图片_20211026155422.jpg


流量监控

直接访问mall-swarm项目的前端页面,比如我们希望查看订单列表。

微信图片_20211026155437.png


访问solarmesh的流量视图页面,可以看到,流量视图已经将mall-swarm项目的服务调度清晰的展现出来了。

微信图片_20211026155448.jpg

0 个评论

要回复文章请先登录注册