본문 바로가기
개발/Spring Cloud

[Spring Cloud] Spring Cloud Gateway 구축하기

by baau 2023. 6. 12.

Spring Cloud Gateway 👍🏻

  • 스프링 기반 API Gateway
  • 마이크로서비스 아키텍처에서 라우팅, 로드 밸런싱, 필터링 등 역할을 수행
  • Spring 5, Project Reactor를 기반으로 구축되어 비동기 및 논블로킹 기능 지원
  • Netty 서버를 사용하여 높은 성능을 제공

 

Gradle 의존성 추가

implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
  • API Gateway 서버를 Eureka Server(서비스 디스커버리)에 등록하기 위해 eureka-client 의존성 추가

 

Gateway Server 설정 파일 (application.yml)

server:
  port: 8000

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka

spring:
  application:
    name: apigateway-service
  cloud:
    gateway:
      default-filters:
        - name : GlobalFilter
          args:
            baseMessage : Spring Cloud Gateway GlobalFilter
            preLogger : true
            postLogger : true
      routes:
        - id : first-service
          uri : lb://MY-FIRST-SERVICE
          predicates:
            - Path=/first-service/**
            - Method=GET
          filters:
            - AddRequestHeader=first-request, first-request-header2
            - AddResponseHeader=first-response, first-response-header2
            - CustomFilter
        - id : second-service
          uri : lb://MY-SECOND-SERVICE
          predicates:
            - Path=/second-service/**
          filters:
            - RewritePath=/second-service/(?<segment>.*), /$\{segment}
  • eureka.client
    • register-with-eureka : 현재 애플리케이션을 Eureka Server에 등록하지에 대한 여부 (true)
    • fetch-registry : Eureka Server로부터 인스턴스들의 정보를 주기적으로 가져올 것인지에 대한 속성 (true)
    • service-url.defaultZone : Eureka Client가 Eureka Server에 연결하기 위한 URL 설정, defaultZone은 기본적으로 사용되는 Eureka Server의 URL를 나타낸다.
  • spring.application.name
    • MSA에서 해당 서비스를 구별할 수 있는 고유한 ID
  • spring.cloud.gateway.default-filters : 전역 필터 설정 (모든 라우터 목록들에 대해서 해당 필터 적용)
    • name : 전역 필터 클래스 이름
    • args : 필터에 전달되는 추가 인수 설정
  • spring.cloud.gateway.routes : 라우팅 규칙 목록 설정
    • id : 라우팅 규칙 식별자 지정
    • uri : 라우팅할 대상 서비스 지정
      • lb://MY-FIRST-SERVICE
        • Eureka에 등록된 서비스 이름 지정
        • Spring Cloud Gateway에서는 Eureka에 등록된 서비스를 검색하고, Load Balancer는 Eureka에서 처리한다.
    • predicates : 라우팅을 결정하기 위한 조건 설정
      • Path=/first-service/** : 요청 경로가 "/first-service/**"와 일치하는 경우
      • Method=GET : 요청 메서드가 GET일 경우
    • filters : 라우팅에 적용할 필터 목록 설정
      • AddRequestHeader=first-request, first-request-header2 : 요청 헤더 추가 필터 적용
      • AddResponseHeader=first-response, first-response-headers : 응답 헤더 추가 필터 적용
      • CustomFilter : 적용할 필터 클래스 이름 설정
      • RewritePath=/second-service/(?<segment>.*), /$\{segment}
        • :8000/second-service/posts로 gateway에 요청이 와서 second-service로 라우팅을 할 때, 실제 second-service에서는 :60000/second-service/posts로 대기해야 요청을 처리할 수 있다.
          - @GET("/second-service/posts") 와 같이
        • 하지만 second-service에서 모든 uri에 second-service를 포함시켜야 할까는 굳이 일까 싶다.
        • 따라서 RewritePath를 통해 :8000/second-service/posts로 요청이 오더라도, second-service에서 uri에서 "second-service"를 빼고 :60000/posts로 요청을 처리할 수 있도록 Path를 재설정해주는 기능을 한다.

 

 

Gateway에 적용할 Filter 구현 (예시)

@Component
@Slf4j
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {

    public CustomFilter() {
        super(Config.class);
    }

    @Data
    public static class Config {
        private String baseMessage;
        private boolean preLogger;
        private boolean postLogger;
    }

    @Override
    public GatewayFilter apply(Config config) {
        // Pre Filter
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();

            log.info("Custom PRE filter: request id -> {}", request.getId());

            // Post Filter
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("Custom POST filter: response code -> {}", response.getStatusCode());
            }));
        };
    }
}
  • Gateway Filter 를 구현하기 위해서는 AbstractGatewayFilterFactory를 상속해야 한다.
  • 전역 필터와 지역 필터의 구현 방법은 동일하며, 설정 파일에 어디에 위치하느냐에 따라 전역 필터인지 지역 필터인지 결정된다.
  • Tomcat이 아닌 Netty에서는 HttpRequestServlet과 HttpResponseServlet 대신 ServerHttpRequest와 ServerHttpResponse를 사용한다.
  • spring.cloud.gateway.default-filters.args 로 설정한 인자는 Config 클래스를 만들어 넘겨 받을 수 있다.
  • Pre Filter & Post Filter
    • Pre Filter
      • 요청이 라우팅 및 핸들러에 도달하기 전에 실행되는 필터
      • 요청을 사전에 검증하고 변형하는 목적을 가진다. (요청의 인증, 인가, 헤더 수정, 요청 로깅 등의 작업)
    • Post Filter
      • 요청이 라우팅과 핸들러를 거친 후 응답을 처리하기 전에 실행되는 필터
      • 응답을 사후에 변형하거나 로깅하는 것을 목적으로 한다. (응답의 헤더 수정, 응답 시간 측정, 응답 로깅 등의 작업)
      • Mono.fromRunnable을 통해 Post Filter가 실행되기 전에 비동기 작업을 수행하고, 작업이 완료되면 Mono가 완료되어 Post Filter 단계로 진행한다.

 

MSA 공부

(1) Eureka Server 구성
(2) Eureka Client 구성
(3) Client Side Load Balancer & API Gateway 개념 정리
(4) Spring Cloud Gateway 구축

참고 강의 : https://www.inflearn.com/course/스프링-클라우드-마이크로서비스/dashboard