API Gateway

마이크로 서비스를 운영하기 위해서는 작은 기능들을 개발하고 수시로 배포하게 되는데 이런 기능들을 손쉽게 외부에 제공하는 것이 용이 하지는 않습니다. 누구나에게 오픈된 기능이라도 비정상적인 접근에 대해 차단이 필요하기도 하고 – 요즘 외부에 기능이 오픈되면 바로 admin 계정을 얻기 위한 불법저긴 시도들이 로그에 넘쳐납니다 – 그런 인증에 대한 고급 기능(예를 들어 oauth2 지원 등)이 아니더라도 간단한 로그를 남기려 한다면 서비스 마다 로그 기능을 추가하는 것이 마이크로 하다고 보기는 어렵습니다.

뿐만 아니라 서비스 운영 중에 패치나 업그레이드가 필요한 경우 끊김 없는 안정적인 – 동적으로 빌드해서 서비스하는 경우도 있지만 – 서비스를 하려 한다면 2대 이상의 서버에 서비스를 구성하고 패치하는 동안 1대로 운영을 하는 방법이 필요할 수 있습니다. 보통은 load balancing 을 위해 장비를 두고 장애 있는 서버는 온라인 상에서 제외하는 방식을 그대로 응용한 것이라고 볼 수 있습니다. 어찌 보면 일시적이지만 패치나 배포하는 중의 서비스 중단은 장애라고 볼 수 있기 때문입니다.

         +----------+                 +----------+
         |    L4    |                 |  Gateway |
         +----+-+---+                 +----+-+---+
              | |                          | |
        +-----+ +----+               +-----+ +----+
        |            |               |            |
        v            v               v            v
   +----------+  +---+-----+    +----------+  +---+-----+
   | Service  |  | Service |    | Service  |  | Service |
   |    1     |  |    2    |    |    1     |  |    2    |
   +----------+  +---------+    +----------+  +---------+

마이크로 서비스는 보통 쉽게 사용할 수 있는 REST API 형태로 서비스를 제공합니다. 결과물로 받을 수 있는 데이터의 형태도 json 타입으로 자바스크립트에서 객체 형태로 쉽게 변환해서 조작하기에 매우 쉽습니다. 웹 서비스 형태로 제공되던 xml 형태와 비교하면 크기도 작고 눈으로 봐도 이해가 쉬운 형식으로 되어 있습니다. (가독성을 위해 jsonformatter 사이트를 자주 이용합니다.)

$ curl https://jsonplaceholder.typicode.com/users/1
{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "Sincere@april.biz",
  "address": {
    "street": "Kulas Light",
    "suite": "Apt. 556",
    "city": "Gwenborough",
    "zipcode": "92998-3874",
    "geo": {
      "lat": "-37.3159",
      "lng": "81.1496"
    }
  },
  "phone": "1-770-736-8031 x56442",
  "website": "hildegard.org",
  "company": {
    "name": "Romaguera-Crona",
    "catchPhrase": "Multi-layered client-server neural-net",
    "bs": "harness real-time e-markets"
  }
}

위와 같이 curl 프로그램을 사용해서 간단하게 REST API를 호출해서 사용자의 정보를 조회해 보았습니다.  json 형식이 간단하고 쉽게 눈에 들어오는 모양이라는 것을 아실 수 있습니다.

마이크로 서비스는 위 예제에서 보신 것처럼 여러 곳에서 제공되는 작은 기능들을 가져와서 사용할 수 있고 직접 만들어서 제공하기도 합니다. 요즘 전자 상거래 사이트에서 구매 결제를 직접 제공하지 않고 사이트 외부의 결제 서비스를 이용하여 결제할 수 있게 하는 것과 마찬가지 입니다. 이렇게 내부 외부의 흩어져 있는 서비스를 하나의 gateway에서 묶어서 제공하므로 복잡함과 수고로움을 덜기도 합니다. 예를 들어 자신의 PC 에 gateway 를 설치하고 실행시켜서 위 예제 사이트 주소를 등록해 놓으면 개발하지 않고도 자신의 PC에서 동일하게 동작하는 것을 볼 수 있습니다. 세팅 방법은 다음에 자세히 설명하겠습니다.

$ curl http://localhost:8080/users/1

API 를 서비스 한다는 것은 제공하는 주소로 많은 사용자들이 호출하고 있다는 것을 의미합니다. 새로운 기능을 더 추가해서 서비스하려 할 때도 기존의 기능을 사용하는 사용자를 고려할 필요가 있습니다. 그래서 새로운 버전은 새로운 주소를 제공할 필요가 있습니다. 기존의 주소를 변경해서 2중으로 코드를 관리하는 것이 상당히 번거롭습니다. Gateway 에서 주소 내에 버전(v1,v2)만 추가해 놓으면  되므로 새로운 서버 주소를 만들 필요도 없고 동일한 코드로 – 소스코드에는 v1,v2 없이 /users/{id} 로 정의 되어 있어도 –  별도의 서버에 배포만 하면 됩니다.

$ curl http://your.host.com/v1/users/1
$ curl http://your.host.com/v2/users/1

저는 이런 Gateway 의 필요성이 있다고 생각이 되었고 AWS 에서는 API Gateway 서비스가 제공되고 있어 그대로 활용하는 것도 방법일 수 있지만 모든 서비스가 Cloud 에 다 있는 것이 아니기 때문에 기존의 IDC 에 있는 서비스들도 참여시킬 수 있도록 설치형 서비스를 찾아 보았습니다. 오픈 소스로 제공되는 Kong API Gateway 를 알게 되었고 이를 사용해서 마이크로서비스를 구성했습니다.

Kong 은 Nginx 기반에 lua 언어로 개발된 plugin 형태로 API Gateway 를 제공하고 있습니다. 일단 Nginx 기반이라 – proxy 기능, 캐시 기능, 부하 분산 기능 등을 그대로 사용 – 안정성에서 만족 하였고 실제 로그를 확인하면 Gateway 의 처리 속도나 부하가 극히 적은 것을 알 수 있습니다.  Community 버전을 제공하고 있어서 무료로 사용 가능하다는 것이 또한 강점입니다. 제가 처음 사용할 당시는 무료버전이던 것이 기업용 버전이 추가되어 유료버전으로도 제공되고 있습니다. kong 자체가 plugin 이라 추가적인 plugin 으로 확장이 가능하고 오픈 소스를 가져다가 자신에 맞게 수정해서 사용할 수 있습니다. 기존 plugin 을 수정해서 Kafka 로그 plugin 을 추가한 사례를 나중에 설명하겠습니다.

해당 사이트의 설명을 보면 기본적으로 제공되는 plugin 정보를 얻을 수 있습니다. 저희는 인증에 관련해서 JWT, OAuth2 를 사용해서 복잡한 개발없이 간단히 인증처리를 구현했습니다. 모바일 접근을 허용하기 위해서 CORS 를 사용하였고 아직 사용하지는 않았지만 성능을 높이기 위한 캐시 기능(proxy caching)이라든가 해커의 공격을 대비한 Rate limiting 기능도 사용해보려 합니다. AWS 의 lamda 서비스와 연동도 가능하고 다양한 Log 기능도 제공합니다. 저희가 로그 기능을 확장 하려는 이유는 요청되고 응답되는 데이터가 로그에 포함되지 않아서 그 부분을 추가해서 로그를 설치했습니다.

물론 AWS에는 막강한 서비스가 많습니다. AWS API Gateway 역시 강력합니다. 그러나 aws 외에 서비스를 하거나 내부 인증 시스템과 연동되어야 하거나 자체 서비스를 활용해야 한다면 Kong 과 같은 오픈 서비스가 필요하지 않을까 합니다. 간단히 개발, 확인할 수 있도록 Docker를 이용한 kong 설정을 시작으로 문서들을 작성해보겠습니다.