3 분 소요

이번에는 Spring Cloud Gateway와 Eureka 서버를 연동해보자.
유레카라는 네이밍 서비스에 스프링 게이트웨이를 등록하고,
first-servicesecond-service까지 등록해보자.

🙂 Spring Cloud Gateway - Eureka 연동

개요

스크린샷 2022-09-28 오전 1 52 16

  1. 예를 들어, 클라이언트가 http://localhost:8000/first-service/**에 요청할 때
  2. 이 요청정보가 유레카 서버에 전달되고
  3. 유레카로부터 그 요청을 처리할 수 있는 마이크로 서비스의 위치 정보를 전달 받고
  4. 게이트웨이 서비스가 해당 요청을 해당 마이크로 서비스로 포워딩한다.

코드

1) apigateway-service

pom.xml

유레카 클라이언트를 등록하자.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

유레카 클라이언트는 first-servicesecond-service 모두 추가해준다.

application.yml

유레카 클라이언트 설정을 true로 변경하자.
이는 “8761번 포트(discovery-service)에 유레카 클라이언트로 등록하겠다”는 의미이다.

...
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 Global Filter
            preLogger: true
            postLogger: true
      routes:
        - id: first-service
          uri: lb://MY-FIRST-SERVICE # 🌟 uri 변경
          predicates:
            - Path=/first-service/** 
          filters:
            - CustomFilter
        - id: second-service
          uri: lb://MY-SECOND-SERVICE # 🌟 uri 변경
          predicates:
            - Path=/second-service/**
          filters:
            - name: CustomFilter
            - name: LoggingFilter
              args:
                baseMessage: Hi, there.
                preLogger: true
                postLogger: true

spring.cloud.gateway.routes에서,
first-serviceuri는 원래 http://localhost:8081/ 이었고,
second-serviceuri는 원래 http://localhost:8082/ 이었다.

이것을 lb://MY-FIRST-SERVICElb://MY-SECOND-SERVICE로 바꿈으로써,
기존처럼 http 프로토콜을 이용해 localhost:8081 혹은 localhost:8082로 가는게 아니라,
클라이언트의 요청 정보를 유레카 서버에게 전달하겠다는 의미이다.

2) first-service

pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml

...
eureka:
  client:
    register-with-eureka: true # 🌟 변경
    fetch-registry: true # 🌟 변경
    service-url:
      defaultZone: http://localhost:8761/eureka

3) second-service

pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml

...
eureka:
  client:
    register-with-eureka: true # 🌟 변경
    fetch-registry: true # 🌟 변경
    service-url:
      defaultZone: http://localhost:8761/eureka

이로써 총 3개의 서비스가 유레카 서버(discovery-service)에 등록된 것이다.

  • apigateway-service: 8000번 포트
  • first-service: 8001번 포트
  • second-service: 8002번 포트

서버 기동

유레카 서버(discovery-service)를 먼저 기동시킨 후,
게이트웨이(apigateway-service), first-service, second-service 순으로 기동시키자.

이제 http://localhost:8761(= 유레카 서버)에 접속하면 3개의 서비스가 등록된 것을 확인할 수 있다. 스크린샷 2022-09-28 오전 2 14 06

포스트맨 결과

스크린샷 2022-09-28 오전 2 26 39

스크린샷 2022-09-28 오전 2 26 26
이를 통해, 기존에 http://localhost:8081 혹은 http://localhost:8082로 호출했던 정보들을
유레카 서버에 있는 위치로 정보를 변경하더라도 (lb://MY-FIRST-SEVICE, lb://MY-SECOND-SEVICE)
정상적으로 작동하는 것을 확인할 수 있다.

여기까지 하면, 이제 하나 이상의 마이크로 서비스를 기동해서 로드 밸런서의 기능을 구현할 수 있는 것이다.
이제 이것을 테스트해보자.

🙂 first-servicesecond-service를 각각 2개씩 기동

  • 방법 1
    - 인텔리제이에서 Edit Configurations -> VM options에 -Dserver.port=9003 입력
  • 방법 2
    - 터미널에 mvn spring-boot:run -Dspring-boot.run.jvmArguments='-Dserver.port=9003' 커맨드 입력
  • 방법 3
    - 패키지 파일 생성 후 java 명령어로 해당 패키지 파일 실행
    mvn clean compile package  # maven 빌드
    java -jar -Dserver.port=9003 ./target/uesr-service-0.0.1-SNAPSHOT.jar
    

연습을 위해 first-servicesecond-service를 각각 다른 방법으로 2개씩 기동해보자.
first-service는 방법 1을 이용했고, second-service는 방법 3을 이용했다.

first-service
스크린샷 2022-09-28 오후 8 02 20

second-service
스크린샷 2022-09-28 오후 8 09 07 스크린샷 2022-09-28 오후 8 08 49

이로써 유레카 서버(discoveryservice)에는 아래 사진에서 볼 수 있듯이,
게이트웨이 서비스(apigateway-service)와 4개의 마이크로 서비스(first-service 2대, second-service 2대)가 등록된 상태이다.
스크린샷 2022-09-28 오후 8 11 43

그런데, apigateway-serviceapplication.yml을 보면 아래와 같다.
스크린샷 2022-09-28 오후 8 17 47
위 사진에서 lb://MY-FIRST-SERVICE
/first-service/**로 요청이 들어오면 디스커버리 서비스(= 네이밍 서비스) 안에 등록되어있는 서비스들 중,
이름이 MY-FIRST-SERVICE인 서비스로 보내겠다는 의미인데, MY-FIRST-SERVICE 서비스 안에는 2개의 인스턴스가 있다.
이 때, 9091로 갔는지 8081로 갔는지 어떻게 알 수 있을까?

랜덤포트 사용

first-service

copy 한 FirstServiceApplication(1)은 삭제하고 application.yml을 아래와 같이 변경한다.

server:
  port: 0 # 🌟 8081에서 0으로 변경

spring:
  application:
    name: my-first-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance: # 🌟 추가
    instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}

first-service 하나 더 기동

터미널을 이용해 first-service를 하나 더 기동해보자.

mvn spring-boot:run

랜덤포트를 사용하기 때문에 뒤에 옵션으로 포트번호를 지정할 필요가 없다.

결과
스크린샷 2022-09-28 오후 8 33 14

어떤 서비스가 실행될 때 몇 번 포트가 사용되었는지 출력

first-service

FirstServiceController.java

@RestController
@RequestMapping("/first-service")
@Slf4j
public class FirstServiceController {

    Environment env;

    @Autowired
    public FirstServiceController(Environment env) {
        this.env = env;
    }

    @GetMapping("/check")
    public String check(HttpServletRequest request) {
        log.info("server port={}", request.getServerPort());
        return String.format("Check First Service on PORT %s", env.getProperty("local.server.port"));
    }
}

스프링에서는 @Autowired Environment env;으로 변수에 직접 주입받는 것보다는,
위 코드에서처럼 생성자를 통해 주입받는 것을 권장한다.

request에서 포트 번호를 가져올 수도 있고, 환경변수에서 가져올 수도 있다.

포스트맨 테스트

인텔리제이에서 run 버튼을 클릭하고, 터미널에서 mvn spring-boot:run 커맨드를 입력해
first-service를 총 2대 기동한 후에 포스트맨에서 테스트 해보자.

포스트맨에서 http://localhost:8000/first-service/check에 접속해보자.

첫 번째 호출
스크린샷 2022-09-28 오후 8 53 07
스크린샷 2022-09-28 오후 8 50 32

두 번째 호출
스크린샷 2022-09-28 오후 8 52 45
스크린샷 2022-09-28 오후 8 49 53

이와 같이, Round Robin 방식으로,
한 번은 인텔리제이의 마이크로 서비스로, 또 한 번은 터미널의 마이크로 서비스로 번갈아가며 호출을 해준다.
따라서 게이트웨이를 사용하면, 라우팅 기능과 로드 밸런싱 기능을 사용할 수 있다.



💛 개인 공부 기록용 블로그입니다. 👻

맨 위로 이동하기