AWS REST API gateway를 VPC Link를 사용하여 NLB와 통합하기

728x90

서론


프로젝트를 진행하면서 HTTP API gateway와 Network Load Balancer를 통합해봤다. 하지만 이 통합 방식에는 단점이 하나 있었는데, API gateway의 라우팅 주소가 실제 어플리케이션 코드에서 라우팅 주소와 정확히 일치해야 정상 작동하는 것이었다. 문제를 그림으로 설명하면 다음과 같다.

현재 프로젝트 서비스 구조는 다음과 같이 세가지 개별적 VPC에 API gateway가 라우팅 하는 형태로 되어있다. API gateway의 리소스 "/customer"에 접근하면, 소비자 서비스의 루트 경로로 들어가고 "/restaurant"에 접근하면, 음식점 서비스의 루트 경로로, "/rider"에 접근하면 배달기사 서비스의 루트 경로로 접근하게 하고 싶다. 





원하던 동작


API gateway에 "/rider"라는 라우팅 정보를 넣으면 rider 서비스의 루트경로로 접근하고 싶다.

 

 

HTTP API gateway의 실제 동작


하지만 HTTP API gateway는 NLB와 통합을 진행할 때 자동적으로 라우팅 주소를 1대1 매칭하여 연결해준다. 라우팅 주소를 커스터마이징할 옵션이 주어지지 않는 것이다. 

 


로드밸런서와의 통합을 진행하면 그냥 "/" -> '/" 이렇게 라우팅이 매핑될 뿐이다.



REST API gateway는 HTTP API gateway와 다르게 NLB와 통합할 때 엔드포인트 URL을 자유롭게 설정할 수 있다. API gateway의 라우팅 주소와는 별도로 내가 연결하고자하는 어플리케이션의 라우팅 주소를 지정할 수 있다는 말이다.

 

 


각 서비스마다 루트 주소를 "/customer", "/restaurant", "/rider" 붙이는 방법도 있겠으나, 모든 컨트롤러에 이렇게 동일한 주소를 붙여넣는 것은 상당히 번거로운 작업이 될 것 같다. 그러므로 HTTP API gateway가 아닌 REST API gateway를 사용하여 NLB와의 통합을 진행하도록 하겠다.

 

REST API gateway 생성하여 NLB와 통합

 

REST API gateway 생성 하기


API gateway 서비스에서 API 생성 버튼 누름

 



REST API 구축 선택 (프라이빗 말고 퍼블릭으로 해야 함)

 


REST 선택, 새 API 선택, 엔드포인트 유형은 지역으로 선택하고 이름 입력하여 API 생성 누름

 


리소스 작업 버튼에서 리소스 생성을 누름

 


라우팅 주소로 사용할 리소스 이름과 경로를 입력.

 


그 다음으로는 각 리소스에 대해 메소드를 지정해줘야한다. 작업에서 메서드 생성을 누름

 



통합 유형은 VPC 링크를 선택하고, 방법은 ANY를 선택 VPC 링크는 방금 전 만든 REST API gateway용 VPC link를 선택한다. 엔드포인트 URL은 매칭하려는 NLB의 도메인 주소값을 입력하면 된다. 그리고 저장 버튼을 누름

 

 


메소드 생성까지 끝났으면 이것을 배포해줘야한다. HTTP API gateway는 기본적으로 자동배포 설정이 되어있지만, REST API gateway는 API 배포를 수동적으로 눌러줘야함. 배포 스테이지 이름과 설명을 채워넣고 배포해준다.

 



왼쪽 탭에 스테이지로 들어가면 배포한 스테이지 목록을 볼 수 있다. 배포한 스테이지 목록에서 스테이지를 클릭하면 배포 버전의 URL을 확인할 수 있다. 


 

오류: internal server error 발생


REST API gateway와 NLB를 통합하여 구동하면 다음과 같은 에러 메시지가 발생할 수 있다.

 


이는 HTTP API gateway를 사용하여 통합했을 때 아래와 같이 정상적으로 출력문이 나오는 것과 대조적이다. 

 


이는 REST API gateway에 돌려보내줘야 할 응답문의 형식이 정해져있기 때문이다. internal server error가 왜 발생하는지 아래 링크를 참고해보자.
https://stackoverflow.com/questions/47672377/message-internal-server-error-when-try-to-access-aws-gateway-api

즉, Status code를 반환하지 않으면 API gateway는 500 Internal server error 응답을 자동적으로 일으키게 되어있다. 즉, REST API gateway에 응답을 보낼 때는 status code를 반드시 포함시켜야 한다. HTTP API gateway에 비해 REST API gateway는 참 다루기 까다로운 것 같다. 😑 (하지만 그렇기 때문에 더 세부적인 커스터마이징이 가능한 것 같다. 라우팅 주소도 어플리케이션 코드와 구분해서 설정할 수도 있고)

해결책: application code 수정하기

REST API gateway 응답 형식 준수 필요


조사 결과 REST API gateway에는 다음과 같은 형식으로 응답을 돌려줘야 된다고 한다.

 

return {
    'statusCode': 200,
    'headers': {'Content-Type': 'application/json'},
    'body': message
}



반환문에는 statusCode와 header 그리고 body를 포함해야하는 것이다. 글쓴이는 현재 어플리케이션 코드를 자바 스프링으로 작성했다. Javascript나 파이썬에서 코드 작성은 어떻게 할지 궁금하다면 아래 링크를 접속하여 확인해보자.

파이썬: https://bablabs.tistory.com/39
자바스크립트: https://stackoverflow.com/questions/47672377/message-internal-server-error-when-try-to-access-aws-gateway-api



현재 루트 ("/") 경로 컨트롤러는 다음과 같이 되어 있다. 



이 코드에는 status code를 설정하는 부분이 빠져있다. 헤더와 바디는? 헤더와 바디도 별도로 작성해야할까? 이 세 정보를 어떤 형태로 결합하여 반환해줘야 HTTP 응답을 정상적으로 보내줄 수 있을까?


스프링 동작 분석



결론부터 말하자면 status code를 붙여주는 것 외에는 아무것도 건들지 않아도 된다. @ResponseBody가 자동적으로 HTTP 헤더와 바디를 모두 알아서 채워넣는다.

반환 데이터가 어떻게 만들어질지 잠깐 분석해보자. @RestController를 사용하고 있으므로 @ResponseBody를 사용하고 있는 꼴이다. @ResponseBody가 붙으면 응답으로 자바 객체를 HTTP 바디 내용으로 곧바로 매핑하여 클라이언트로 전송한다. @ResponseBody는 함수의 반환 값이 String 형식이면 StringHttpMessageConverter를 동작시켜 HTTP 응답을 String 형태로 돌려주고, 반환 값이 객체 형태라면 MappingJackson2HttpMessageConverter가 동작되어 HTTP 응답을 JSON형태로 돌려준다.

StringHttpMessageConverter가 동작되면 Response Header에 content-type: text/html;charset=UTF-8가 붙으며, MappingJackson2HttpMessageConverter가 동작되면 Response Header에 Content-type:Application/json이 붙는다. 즉, @ResponseBoy를 사용하면 Spring에서 알아서 헤더의 Content-type과 바디는 채워주는 것이다. 그러므로 우리는 그냥 Status Code만 붙여넣어주면된다. 이것도 Spring에서 간편하게 해결할 수 있도록 애노테이션을 제공하고 있다.

@ResponseStatus



아래처럼 @ResponseStatus 애노테이션을 붙여 상태코드를 넣어주기만 하면 API gateway가 정상적으로 동작한다. (HttpStatus.OK는 상태코드 200을 의미한다.)

 



REST API gateway가 정상적으로 동작하여 ECS로부터 정상적으로 응답을 받은 것을 확인할 수 있다.


결론


인터페이스의 편이성이나 배포의 난이도만 따져보면 확실히 HTTP API gateway가 사용에는 수월하고 스테이지 배포도 자동으로 진행되고 시간 소모도 적다. 하지만 이처럼 라우팅을 커스터마이징하는 것에는 REST API gateway를 사용하는 것이 좋다. 그리고 REST API gateway가 접속 시에Internal server error를 보낸=다면 REST API gateway에 보내는 응답 형식에 상태코드가 포함되어있는지 확인해보자.