API Gateway
는 마이크로 서비스별로 공통적으로 처리되는 로직에 대해서 하나의 포트에서 처리할 수 있도록 클라이언트와 서비스들 사이에 위치하는 Proxy Server
이다.
클라이언트는 각 서비스에 요청을 보내는 것이 아니라 API Gateway에게 요청을 보내고, API Gateway는 서비스에게 설정에 따라 요청을 전달하고 응답을 받은 뒤 해당 내용을 다시 클라이언트에게 전달한다.
다시 말해서 MSA로 구성된 서비스에서의 단일 진입점 역할을 한다.
각 서비스마다 인증/인가를 하는 로직을 넣는 것은 매우 비효율적이기에 모든 트래픽이 통과하는 API Gateway에서 처리할 수 있다.
또한 토큰 발급도 인증 서버를 두고 자격을 위임할 수 있다.
각 서비스에 트래픽을 전달할 때 설정을 통해 균등하게 전달할 수 있다.
메디에이션 기능 중 Message Exchange Pattern
이 있는데, API Gateway를 사용하면 동기 호출을 비동기 호출로 바꿀 수 있다.
SCG
는 상용화된 API Gateway중 하나로 Route
Predicate
Filter
세가지 요소로 이루어져 있다.
서비스 고유의 id를 통해 트래픽 전달 주소를 파악하며, 요청된 uri의 조건이 predicate와 일치하는지 확인 후 경로로 매칭시켜준다.
API Gateway로 들어온 요청이 주어진 조건을 만족하는지 확인하는 구성요소이다. 하나 이상의 조건을 설정할 수 있으며 조건에 맞지 않으면 404 에러 응답을 반환한다.
API Gateway로 들어오는 요청에 대해 Filter를 적용해 선처리/후처리 작업을 할 수 있게 해준다.
이 기능으로 토큰검사 등을 진행할 수 있다.
실습 환경은 spring cloud config server , eureka server 를 사용한다.
스프링 부트 프로젝트를 생성해준다.
여기에 추가로 actuator
와 bootstrap
을 추가해준다.
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap'
...
}
config server
에서 해당 서비스의 설정 파일을 가져올 수 있는 설정 파일을 만든다
spring:
cloud:
config:
uri: http://localhost:8888
name: service-name
profile: default
config server
가 바라보고 있는 레포지토리에 우리 서비스의 설정 파일을 커밋 해준다.
이 설정 파일엔 유레카 서버에 서비스를 레지스트리 하는 코드도 포함된다.
# 같은 종류의 다양한 서비스가 컨테이너로 배포되는 상황을 위해 포트는 랜덤 설정
server:
port: 0
spring:
application:
name: service-name
# 유레카 레지스트리 코드
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}}
# Actuator 사용해서 설정 파일을 갱신하기 위한 코드
management:
endpoints:
web:
exposure:
include: health, refresh
유레카 서버에 잘 등록된 것까지 확인 후 게이트웨이 서버 작업 시작
추가로 actuator
와 bootstrap
을 넣어준다.
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap'
...
}
config server
에서 해당 서비스의 설정 파일을 가져올 수 있는 설정 파일을 만든다
spring:
cloud:
config:
uri: http://localhost:8888
name: gateway
profile: default
config server
가 바라보고 있는 레포지토리에 우리 서비스의 설정 파일을 커밋 해준다.
이 설정 파일엔 유레카 서버에 서비스를 레지스트리 하는 코드도 포함된다.
server:
port: 80
# 유레카 레지스트리 코드
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}}
# SCG 설정 코드
spring:
application:
name: gateway-service
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: first-service
uri: lb://FIRST-SERVICE
predicates:
- Path=/first-service/**
filters:
- RemoveRequestHeader=Cookie
- id: second-service
uri: lb://SECOND-SERVICE
predicates:
- Path=/second-service/**
filters:
- RemoveRequestHeader=Cookie
# Actuator 사용해서 설정 파일을 갱신하기 위한 코드
management:
endpoints:
web:
exposure:
include: health, refresh
cloud.gateway.routes.id.uri : lb
인 이유 : http://localhost:7777/first-service/** 이런 식으로 적어주어도 되긴 하지만 유레카 서버를 통해 도메인을 등록해서 서버는 도메인 네임만으로 서비스들을 찾을 수 있게 해 동적 포트 할당을 원활하게 하기 위함이다.
추후 POD단위로 배포할 때에 POD는 언제든 버릴 준비를 하고 있어야 하는 배포 자원이므로 항상 새로 띄울 준비를 해야하는데 이 때 포트가 계속 변하게 된다. 따라서 유레카 서버에 등록한 도메인 네임으로 서비스를 찾는다.
유레카 서버는 로드벨런싱을 진행할 때 라운드 로빈 방식으로 서비스의 트래픽을 분산해준다고 한다. 서비스 A에 인스턴스 a, b, c 가 있다면 순차적으로 a, b, c 로 트래픽을 분산하는 것.
원래였다면 서비스의 포트로 기입을 해주어야 하지만 게이트웨이의 도메인으로 각 서비스의 route로 접근할 수 있게 됐다.