toy project-msa: Spring Cloud Gateway

bo-yoonยท2021๋…„ 11์›” 14์ผ
1

msa

๋ชฉ๋ก ๋ณด๊ธฐ
6/7

๐Ÿค” ์Šคํ”„๋ง ํด๋ผ์šฐ๋“œ ์‹œ๋ฆฌ์ฆˆ!

์Šคํ”„๋ง ํด๋ผ์šฐ๋“œ ๊ฒŒ์ดํŠธ์›จ์ด๋ฅผ ์„ธํŒ…ํ•˜๊ณ  ํ™•์ธํ•ด๋ณด์ž

์ด ๊ธ€์€ ํ•ด๋‹น ๊ธ€๊ณผ ์ด์–ด์ง€๋Š” ๊ธ€์ž…๋‹ˆ๋‹ค. https://velog.io/@borab/Spring-Cloud-Eureka



Spring Cloud Gateway๋ž€?

spring cloud gateway๋Š” api gateway์ด๋‹ค. api gateway๋ž€ Client(vue, react๋กœ ๋œ front-end) ์™€ back-end(springboot) ๋ฅผ ์—ฐ๋™ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋กœ spring cloud gateway ๋ง๊ณ  Zuul, Zuul2 ๊ฐ€ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ Zuul ๊ฐ™์€ ๊ฒฝ์šฐ Blocking ๋ฐฉ์‹์œผ๋กœ ๋น„๋™๊ธฐ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์•„ ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฐ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๊ณ , Zuul2๋Š” ์ด๋ฅผ ๊ฐœ์„ ํ•˜์—ฌ non-blocking ๋ฐฉ์‹์œผ๋กœ ์ง€์›์„ ํ–ˆ์ง€๋งŒ ์Šคํ”„๋ง ํด๋ผ์šฐ๋“œ์˜ ์ผ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ž‘ ํ˜ธํ™˜์ด ๋˜์ง€ ์•Š์•˜๋‹ค.

๊ทธ๋ž˜์„œ ์ตœ๊ทผ๋“ค์–ด์„œ๋Š” spring cloud gateway๊ฐ€ ์ฃผ๋ชฉ์„ ๋ฐ›๊ธฐ ์‹œ์ž‘ํ–ˆ๊ณ  ํ† ์ด ํ”„๋กœ์ ํŠธ์—์„œ๋„ Spring Cloud Gateway๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.


Api Gateway

๊ทธ๋Ÿผ ์ •ํ™•ํ•œ api ๊ฒŒ์ดํŠธ์›จ์ด๋Š” ๋ฌด์—‡์ผ๊นŒ?

api gateway๋Š” Application Programing Interface Gateway๋กœ ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด

  • Client์™€ Springboot(back-end) ์„œ๋น„์Šค๋ฅผ ์—ฐ๋™

์™ธ์—๋„

  • ๋ณด์•ˆ ์ธ์ฆ/์ธ๊ฐ€
  • ์ผ์ •๋Ÿ‰ ์ด์ƒ์˜ ์š”์ฒญ ์ œํ•œ
  • ์‘๋‹ต ์บ์‹ฑ
  • L/B Routing : ๋ผ์šฐํŒ…, ํ•„ํ„ฐ๋ง ํ”„๋ก์‹œ
  • Logging
  • Circuit Break

๋กœ๋„ ์“ฐ์ธ๋‹ค.

๊ฐœ์ธ์ ์œผ๋กœ ์•ค๋“œํฌ์ธํŠธ ๋ผ๋Š” ๋‹จ์–ด๊ฐ€ spring cloud gateway ๊ฐ€ ์ง€์›ํ•˜๋Š” api gateway ๋ฐฉ์‹์„ ๊ฐ€์žฅ ์ž˜ ํ‘œํ˜„ํ•˜๋Š” ๋‹จ์–ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋Š”๋ฐ, ์š”์ฒญ์„ ํ•œ ๊ณณ์„ ๋ชจ์•„ ๋ผ์šด๋“œ๋กœ๋นˆ ๋ฐฉ์‹์œผ๋กœ ์ ํ•ฉํ•œ ์„œ๋น„์Šค์— ๋ผ์šฐํŒ…ํ•ด์ฃผ๊ณ , ์š”์ฒญ์ด ๋งŽ์ด ์˜ฌ ๊ฒฝ์šฐ ํŠธ๋ž˜ํ”ฝ์„ ์ œํ•œํ•œ๋‹ค. ๋˜ํ•œ ๋ฐ˜๋ณต๋˜๋Š” ๋กœ์ง์€ ์บ์‹ฑ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜, ๊ณตํ†ต์œผ๋กœ ์ด ์•ค๋“œํฌ์ธํŠธ์— ์š”์ฒญ์ด ๋“ค์–ด์™€ ๋กœ๊น…์ฒ˜๋ฆฌ๋„ ์ˆ˜์›”ํ•˜๋‹ค.



Spring Cloud Gateway ๊ตฌ์กฐ

Spring Cloud Gateway ๊ฐ™์€ ๊ฒฝ์šฐ

Predicates ์™€ Filter ๊ตฌ์„ฑ๋˜์–ด ๋™์ž‘ํ•œ๋‹ค.

predicate ์˜์—ญ์€ ์กฐ๊ฑด์„ ์ฃผ์–ด์„œ ํ•ด๋‹น ๊ฒฝ๋กœ๊ฐ€ ๋งž๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ๋งž์œผ๋ฉด ํ•„ํ„ฐ๋กœ ์š”์ฒญ์„ ์ „์†กํ•˜๊ณ 
filter ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.



Spring cloud gateway ์‹ค์Šตํ•˜๊ธฐ

๊ธฐ๋ณธ base ์„ธํŒ…

1. ๋ชจ๋“ˆ์— gateway project๋ฅผ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•œ๋‹ค


2. build.gradle์— ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-gateway/3.0.5

  // config
    implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-config', version: '3.0.5'

    // eureka
    implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-eureka-client', version: '3.0.4'

    // gateway
    implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-gateway', version: '3.0.5'

์•ž์„œ ๋ฉ€ํ‹ฐ๋ชจ๋“ˆ๋กœ ์ƒ์„ฑํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ƒ์œ„ ๋ฃจํŠธ build.gradle์—๋Š” ๋กฌ๋ณต ์„ค์ •๋„ ์ด์ฏค์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

	// lombok
		compileOnly 'org.projectlombok:lombok'
		annotationProcessor 'org.projectlombok:lombok'

3. resources ๋ฐ‘ application.yml์™€ bootstrap.yml์„ ์ƒ์„ฑํ•˜๊ณ  ํŒŒ์ผ์— ๋‹ค์Œ ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

application.yml

server:
  port: 8000


spring:
  main:
    web-application-type: reactive
  cloud:
    gateway:
      routes:
        - id: api-member
          uri: http://localhost:9090
          predicates:
            - Path=/member/**
        - id: api-order
          uri: http://localhost:9091
          predicates:
            - Path=/order/**
        - id: api-product
          uri: http://localhost:9092
          predicates:
            - Path=/product/**




eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
    healthcheck:
      enabled: true
  • spring.cloud.gateway.routes ์€ ์Šคํ”„๋ง ํด๋ผ์šฐ๋“œ ๊ฒŒ์ดํŠธ์›จ์ด๊ฐ€ ํŠน์ • ์กฐ๊ฑด์˜ ์š”์ฒญ์ด ๋“ค์–ด ์˜ฌ๋•Œ ์–ด๋””๋กœ ๋ผ์šฐํŒ…ํ• ์ง€์— ๋Œ€ํ•œ ์„ค์ •์ด๋‹ค.
  • spring.cloud.gateway.routes.id : ๋ผ์šฐํŒ…ํ•  ์Šคํ”„๋ง ๋ถ€ํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ช…์ด๋‹ค.
  • spring.cloud.gateway.routes.uri : ๋ผ์šฐํŒ…ํ•  ์ฃผ์†Œ์ด๋‹ค
  • spring.cloud.gateway.routes.predicates : ๋ผ์šฐํŒ… ์กฐ๊ฑด์ด๋‹ค. ์ด ์กฐ๊ฑด์ด ๋“ค์–ด์˜ค๋ฉด ํ•ด๋‹น uri๋กœ ์š”์ฒญ์ด ๋ณด๋‚ด์ง„๋‹ค.

bootstrap.yml

spring:
  application:
    name: api-gateway
  cloud:
    config:
      uri: http://localhost:8888

4. ๊ธฐ์กด ์„œ๋น„์Šค์— Context Path ์„ค์ • ์ง‘์–ด ๋„ฃ๊ธฐ

์œ„์˜ ๋ผ์šฐํŒ… ์„ค์ •์„ ํ™•์ธ ํ•ด๋ณด๋ฉด member ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ• ๋•Œ localhost:9090/member ๋ผ๋Š” ๊ฒฝ๋กœ๋กœ ๊ฐ€๊ฒŒ ์„ธํŒ…๋˜์–ด ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ /member ๋Š” ๋””ํดํŠธ ์„ค์ •์œผ๋กœ ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค

์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” server.servlet.context-path ์„ค์ •์„ ์ถ”๊ฐ€ํ•ด ์„œ๋ฒ„ ํฌํŠธ ์ฒ˜๋Ÿผ ๊ณ ์ •์œผ๋กœ ์ง€์ •ํ•ด์ฃผ์ž!

๊ธฐ์กด์— ํฌํŠธ๋ฅผ ์„ค์ •ํ–ˆ๋˜ yml ํŒŒ์ผ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ๋‹ค.

server:
  port: 9090
  servlet:
    context-path: /member


5. gateway ํ˜ธ์ถœ

์ด์ œ gateway๋กœ ์ง€์ •ํ•œ ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•ด๋ณด์ž

gateway๋Š” 8000 ๋ฒˆ์œผ๋กœ ๋„์› ๋‹ค. ๊ทธ๋ž˜์„œ localhost:8000/member/config/profile ๋ผ๋Š” ๊ฒƒ์œผ๋กœ ๋ฉค๋ฒ„์— ์žˆ๋Š” api ๋ฅผ ํ˜ธ์ถœํ•˜์˜€๋‹ค.

์ž˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋ฅธ ์„œ๋น„์Šค์—๋„ ๊ฐ™์€ ์„ค์ •์„ ํ•ด์ฃผ๊ณ  ํ˜ธ์ถœํ•ด๋ดค๋‹ค.

localhost:8000 ์œผ๋กœ ๋ชจ๋“  ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

front ์—์„œ ํ•„์š”ํ•œ api๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์œผ๋ฉด spring cloud gateway ๋ผ๋Š” ๊ณตํ†ต์˜ ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ spring cloud gateway ๊ฐ€ ์•Œ๋งž๋Š” ๊ณณ์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด์ฃผ๊ณ  ๊ฐ’์„ ๋ฐ˜ํ™˜ ํ•ด์ค€๋‹ค.


์œ ๋ ˆ์นด์—๋„ ์ž˜ ํ™•์ธ๋œ๋‹ค.

7. Eureka์— ๋งž์ถฐ์„œ route uri ์ˆ˜์ •

https://cloud.spring.io/spring-cloud-netflix/multi/multi__service_discovery_eureka_clients.html

์•ž์„œ ์œ ๋ ˆ์นด๋Š” ์ „ํ™”๋ฒˆํ˜ธ๋ถ€ ๊ฐ™์€ ์กด์žฌ๋กœ spring cloud gateway์—์„œ ์ฐธ๊ณ ํ•ด์„œ ๊ฐ™์ด ์“ฐ์ธ๋‹ค. ์ด๋ฒˆ์—๋Š” ์œ ๋ ˆ์นด๋ฅผ ์—ฐ๋™ํ•ด๋ณด์ž!.

์œ„์— ์œ ๋ ˆ์นด ์‚ฌ์ง„์„ ๋ณด๋ฉด ๊ฐ ์„œ๋น„์Šค์˜ ์ด๋ฆ„์ด ๋‚˜์˜ค๋Š”๋ฐ ๊ทธ๊ฒƒ์„ lb://{์„œ๋น„์Šค} ๋ผ๊ณ  ๋ณ€๊ฒฝํ•œ๋‹ค.



spring:
  main:
    web-application-type: reactive
  cloud:
    gateway:
      routes:
        - id: api-member
          uri: lb://API-MEMBER
          predicates:
            - Path=/member/**
        - id: api-order
          uri: lb://API-ORDER
          predicates:
            - Path=/order/**
        - id: api-product
          uri: lb://API-PRODUCT
          predicates:
            - Path=/product/**

์ด๋ ‡๊ฒŒ ๋ณ€ํ™˜ํ•˜๋ฉด cloud ๊ตฌ์กฐ์—์„œ ์„œ๋ฒ„์˜ ip ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋„ ์„œ๋น„์Šค ์ด๋ฆ„์„ ์ฐพ์•„๊ฐ„๋‹ค.



global filter ์ ์šฉ

์•„๊นŒ ์–ธ๊ธ‰ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ api-gateway๋Š” ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฒˆ์—๋Š” ์ด ๊ธ€๋กœ๋ฒŒ ํ•„ํ„ฐ๋กœ ์Šคํ”„๋ง ํด๋ผ์šฐ๋“œ ๊ฒŒ์ดํŠธ์›จ์ด๋กœ ๋“ค์–ด์˜จ ์š”์ฒญ์ด ์–ด๋””๋กœ ์˜จ ์š”์ฒญ์ด๊ณ , status code๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฐ„๋‹จํ•œ ๋กœ๊น… ์„ค์ •์„ ์ถ”๊ฐ€ํ•ด๋ณด์ž!

๋จผ์ € api-gateway ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ application.yml ํŒŒ์ผ์— ๋‹ค์Œ์˜ ์„ค์ •์„ ์ถ”๊ฐ€ํ•ด์คฌ๋‹ค.


application.yml

spring:
  cloud:
    gateway:
      default-filters:
        - name: GlobalFilter
          args:
            preLogger: true
            postLogger: true
  • spring.cloud.gateway.default-filters ๋Š” ๊ธ€๋กœ๋ฒŒ ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์„ค์ •์ด๋‹ค.
  • -name : ํ•„ํ„ฐ ์ด๋ฆ„์„ ๋„ฃ์–ด์ค€๋‹ค.
  • args : ์‚ฌ์šฉํ• 

๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ๋‹ค.


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

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

    @Override
    public GatewayFilter apply(Config config) {

        return ((exchange, chain) -> {
            ServerHttpRequest req = exchange.getRequest();
            ServerHttpResponse res = exchange.getResponse();

            if (config.isPreLogger()) {
                log.info("[REQ ID : {}][REQUEST PATH]          -> {}", req.getId(), req.getPath());
                if (!req.getQueryParams().isEmpty()) {
                    log.info("[REQ ID : {}][REQUEST PATH]          -> {}", req.getId(), req.getPath());
                }
            }
            req.getQueryParams();
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                if (config.isPostLogger()) {
                    log.info("[REQ ID : {}][RESPONSE STATUS CODE]  -> {}", req.getId(), res.getStatusCode());
                }
            }));
        });
    }

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

}

๊ทธ๋ฆฌ๊ณ  ํ™”๋ฉด์„ ํ˜ธ์ถœํ•ด๋ณด์ž

์ด๋ ‡๊ฒŒ ๋กœ๊ทธ๊ฐ€ ์ฐํžˆ๋Š” ๊ฒƒ๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.



์ •๋ฆฌ

spring cloud gateway๋Š” ์ด๋ ‡๊ฒŒ ๋กœ๊ทธ๋ฅผ ๊ณตํ†ต์œผ๋กœ ๊ด€๋ฆฌํ•ด์ค„ ๋ฟ๋งŒ์•„๋‹ˆ๋ผ ๋ผ์šฐํŒ… ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•ด์ค€๋‹ค.

๋˜ํ•œ ์—ฌ๊ธฐ์—์„œ๋Š” ๋‹ค๋ฃจ์ง€ ์•Š์•˜์ง€๋งŒ ๋’ค์—์„œ ๋‹ค๋ฃฐ filter๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ณตํ†ต์œผ๋กœ ์„ธ์…˜, ํ† ํฐ ๊ด€๋ฆฌ๋ฅผ ์ œ๊ณตํ•ด์ฃผ์–ด ์ธ์ฆ ์ธ๊ฐ€์— ๋Œ€ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜๋„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ณ , ์„œํ‚ท๋ธŒ๋ ˆ์ด์ปค์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ๋„ ๋‹ค๋ฃฐ์ˆ˜ ์žˆ๋‹ค.

์ž์„ธํ•œ ๊ฒƒ์€ ์ดํ›„ spring cloud gateway 2์—์„œ ๋‹ค๋ค„๋ณด์ž

profile
๊ฐœ๋ฐœ ๋กœ๊ทธ ๐ŸŽ ๐ŸŽ ๐ŸŽ

0๊ฐœ์˜ ๋Œ“๊ธ€