且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Spring Cloud Kubernetes之实战网关Gateway

更新时间:2022-03-19 10:29:26

微服务化已成为当今主流趋势,但不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:

  • 客户端会多次请求不同的微服务,增加了客户端的复杂性
  • 存在跨域请求,在一定场景下处理相对复杂
  • 认证复杂,每个服务都需要独立认证
  • 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施
  • 某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难

今天介绍的网关,会解决这些问题,可以将服务跟外网进行隔离起到一定的保护作用,同时服务间局域网通信更加快捷。而且在网关中可以做限流、权限校验,使得服务更加专注自身业务。

优点如下:

  1. 安全,只有网关系统对外进行暴露,微服务可以隐藏在内网,通过防火墙保护
  2. 易于监控,可以在网关收集监控数据并将其推送到外部系统进行分析
  3. 易于认证,可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证
  4. 减少了客户端与各个微服务之间的交互次数
  5. 易于统一鉴权
  6. 可以用来作LB

介绍了网关的好处,接下来,我们实战网关。先介绍环境:

  • ubuntu16.04
  • docker18.04
  • k8s1.13.x +
  • maven3.5.3
  • java1.8 +
  • springboot 2.1.6

在依赖的时候,我们来看看主要有哪些package:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-kubernetes-core</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-kubernetes-discovery</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
</dependency>

配置完依赖后,我们看看一些初始化的bean配置,这就涉及到配置文件bootstrap.yaml:

spring:
  cloud:
    kubernetes:
      discovery:
        all-namespaces: true
    gateway:
      discovery:
        locator:
          enabled: true
          lowerCaseServiceId: true
          
      routes:
      #001
      - id: cas-server
        uri: lb://cas-server-service
        order: -1
        predicates:
        - Path=/cas-server/**
        filters:
        - StripPrefix=1

这里我们可以看到,给的routers是一个集合,每个router都要配置,并且我并没有给每一个服务单独配置路由,而是使用了服务发现自动注册路由的方式。这里的Path,是判断匹配条件,即地址带有/ribbon/cas-server/**的请求,会转发至lb:cas-server-service。StripPrefix代表去掉Path的前缀,参数为1代表去掉/ribbon,即通过/cas-server/**就能访问我们的鉴权服务。

接下来,我们主要看main函数:

@SpringBootApplication(scanBasePackages = { "com.gemantic" })

@EnableDiscoveryClient

public class GatewayApp {

    public static void main(String[] args) {

        SpringApplication.run(GatewayApp.class, args);

    }

}

这里引入了注解@EnableDiscoveryClient,为了实现服务的LB。

注意:在springboot2.x中,需要处理跨域时的问题:1.x中我们用的是Netflix公司的Zuul组件做的网关以及LB,其在处理时无需加跨域处理,只要在各微服务上加注解@CrossOrigin即可解决跨域问题。但在springboot2.x中默认的跨域拦截方式前面说了,改了。而且Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代Netflix ZUUL,与其不同,所以在跨域问题上需要注意,这里需要加上跨域的bean,同时,各微服务就不需要注解来解决跨域问题了。

核心代码:

@Bean
public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // 允许cookies跨域
        config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
        config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
        config.addAllowedMethod("*");
        //config.addExposedHeader("token");
        config.setMaxAge(18000L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
}

其实,Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,比如:内置了10种Router等,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。所以可以自行添加使用。这里分享实战源码:https://gitee.com/damon_one/spring-cloud-k8s