Open API platform Kong 소개
1. 소개
Kong 은 오픈 소스 API 게이트웨이 및 마이크로 서비스 관리 레이어입니다.
Nginx와 lua-nginx 모듈 (특히 OpenResty )을 기반으로하는 Kong의 플러그 형 아키텍처는 유연하고 강력합니다.
2. 주요 개념
코드 샘플을 살펴보기 전에 Kong의 주요 개념을 살펴 보겠습니다.
- API 객체 - 특정 작업을 수행하거나 일부 서비스를 제공하는 모든 HTTP 끝점의 속성을 래핑합니다. 구성에는 HTTP 메소드, 엔드 포인트 URI, API 서버를 가리키는 업스트림 URL 및 프록시 요청, 최대 회수, 속도 제한, 시간 초과 등을 위해 사용됩니다.
- Consumer Object - API 끝점을 사용하는 모든 사용자의 속성을 래핑합니다. 추적, 액세스 제어 등에 사용됩니다.
- 상향 객체 (Upstream Object) - 가상 호스트 이름으로 표시되는 들어오는 요청을 프록시 또는로드 균형 조정하는 방법을 설명합니다.
- 대상 객체 - 호스트 이름 (또는 IP 주소) 및 포트로 식별되는 서비스가 구현 및 제공되는 것을 나타냅니다. 모든 업스트림의 대상은 추가 또는 비활성화 만 할 수 있습니다. 목표 변경의 이력은 업스트림에 의해 유지됩니다.
- Plugin Object - 요청 및 응답 수명주기 동안 애플리케이션의 기능을 풍부하게하는 플러그 가능 기능. 예를 들어 관련 플러그인을 사용하도록 설정하여 API 인증 및 속도 제한 기능을 추가 할 수 있습니다. Kong은 플러그인 갤러리 에서 매우 강력한 플러그인을 제공합니다.
- 관리 API - Kong 구성, 끝점, 소비자, 플러그인 등을 관리하는 데 사용되는 RESTful API 끝점
아래의 그림은 Kong이 기존 아키텍처와 다른 점을 보여 주며, 이것이 왜 이러한 개념을 도입했는지 이해하는 데 도움이 될 수 있습니다.
3. 설정
공식 문서는 다양한 환경에 대한 자세한 지침 을 제공 합니다.
4. API 관리
로컬에서 Kong을 설정 한 후 간단한 주식 쿼리 끝점을 프록시하여 Kong의 강력한 기능을 한 번 물어 봅시다.
1 2 3 4 5 6 7 8 9 | @RestController @RequestMapping ( "/stock" ) public class QueryController { @GetMapping ( "/{code}" ) public String getStockPrice( @PathVariable String code){ return "BTC" .equalsIgnoreCase(code) ? "10000" : "0" ; } } |
4.1. API 추가하기
다음으로 쿼리 API를 Kong에 추가해 보겠습니다.
관리 API는 http : // localhost : 8001을 통해 액세스 할 수 있으므로 모든 API 관리 작업이이 기본 URI로 완료됩니다.
1 2 3 4 5 6 7 | APIObject stockAPI = new APIObject( HttpEntity<APIObject> apiEntity = new HttpEntity<>(stockAPI); ResponseEntity<String> addAPIResp = restTemplate.postForEntity( assertEquals(HttpStatus.CREATED, addAPIResp.getStatusCode()); |
여기에 다음과 같은 구성으로 API를 추가했습니다.
1 2 3 4 5 6 |
- "name" 은 API의 식별자로, 동작을 조작 할 때 사용됩니다.
- " 호스트" 헤더를 일치시킴으로써 들어오는 요청을 주어진 "upstream_url" 로 라우팅하는 데 "호스트" 가 사용됩니다
- 상대 경로는 구성된 "uris"
API를 비난하고 싶거나 구성이 잘못 되었으면 간단히 제거 할 수 있습니다.
1 |
API가 추가 된 후에는 http : // localhost : 8000 :
1 2 3 4 5 6 7 8 9 10 11 12 13 | String apiListResp = restTemplate.getForObject( assertTrue(apiListResp.contains( "stock-api" )); HttpHeaders headers = new HttpHeaders(); headers.set( "Host" , "stock.api" ); RequestEntity<String> requestEntity = new RequestEntity<>( ResponseEntity<String> stockPriceResp = restTemplate.exchange(requestEntity, String. class ); assertEquals( "10000" , stockPriceResp.getBody()); |
위의 코드 샘플에서는 방금 Kong에 추가 한 API를 통해 주가를 쿼리하려고합니다.
http : // localhost : 8000 / stock / btc 를 요청 하면 http : // localhost : 8080 / stock / btc 에서 직접 쿼리하는 것과 동일한 서비스를 얻을 수 있습니다.
4.2. API 소비자 추가하기
보안에 대해 이야기합니다. 특히 API에 액세스하는 사용자의 인증입니다.
나중에 인증 기능을 활성화 할 수 있도록 주식 쿼리 API에 소비자를 추가합시다.
API에 대한 소비자를 추가하는 것은 API를 추가하는 것만 큼 간단합니다. 소비자의 이름 (또는 id)은 모든 소비자의 유일한 필수 필드입니다.
1 2 3 4 5 6 | ConsumerObject consumer = new ConsumerObject( "eugenp" ); HttpEntity<ConsumerObject> addConsumerEntity = new HttpEntity<>(consumer); ResponseEntity<String> addConsumerResp = restTemplate.postForEntity( assertEquals(HttpStatus.CREATED, addConsumerResp.getStatusCode()); |
여기에 새로운 소비자로 "eugenp"를 추가했습니다.
1 2 3 | { "username" : "eugenp" } |
4.3. 인증 사용
여기에 Kong의 가장 강력한 기능인 플러그인이 있습니다.
이제 프록시 된 주식 쿼리 API에 인증 플러그인을 적용 할 것입니다.
1 2 3 4 5 6 | PluginObject authPlugin = new PluginObject( "key-auth" ); ResponseEntity<String> enableAuthResp = restTemplate.postForEntity( new HttpEntity<>(authPlugin), String. class ); assertEquals(HttpStatus.CREATED, enableAuthResp.getStatusCode()); |
프록시 URI를 통해 주식 가격을 쿼리하려고하면 요청이 거부됩니다.
1 2 3 4 5 6 7 8 | HttpHeaders headers = new HttpHeaders(); headers.set( "Host" , "stock.api" ); RequestEntity<String> requestEntity = new RequestEntity<>( ResponseEntity<String> stockPriceResp = restTemplate .exchange(requestEntity, String. class ); assertEquals(HttpStatus.UNAUTHORIZED, stockPriceResp.getStatusCode()); |
기억 오이겐은 우리의 API 소비자 중 하나입니다, 그래서 우리는 그 인증 키를 추가하여이 API를 사용할 수 있도록해야합니다 :
1 2 3 4 5 6 7 | String consumerKey = "eugenp.pass" ; KeyAuthObject keyAuth = new KeyAuthObject(consumerKey); ResponseEntity<String> keyAuthResp = restTemplate.postForEntity( new HttpEntity<>(keyAuth), String. class ); assertTrue(HttpStatus.CREATED == keyAuthResp.getStatusCode()); |
그런 다음 Eugen 은 이전과 마찬가지로이 API를 사용할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 | HttpHeaders headers = new HttpHeaders(); headers.set( "Host" , "stock.api" ); headers.set( "apikey" , consumerKey); RequestEntity<String> requestEntity = new RequestEntity<>( headers, HttpMethod.GET, ResponseEntity<String> stockPriceResp = restTemplate .exchange(requestEntity, String. class ); assertEquals( "10000" , stockPriceResp.getBody()); |
5. 고급 기능
기본 API 프록시 및 관리 외에도 Kong은 API로드 균형 조정, 클러스터링, 상태 확인 및 모니터링 등을 지원합니다.
이 섹션에서는 Kong과의 요청을로드 밸런스하는 방법과 관리 API를 보호하는 방법에 대해 살펴 보겠습니다.
5.1. 로드 균형 조정
Kong은 백엔드 서비스에 대한 요청을로드 밸런싱하는 두 가지 전략, 동적 링 밸런서 및 간단한 DNS 기반 방법을 제공합니다. 간단히하기 위해, 우리는 링 - 밸런서를 사용할 것 입니다.
이전에 언급했듯이 업스트림은로드 균형 조정에 사용되며 각 업스트림에는 여러 대상이있을 수 있습니다.
Kong은 가중 라운드 로빈 및 해시 기반 균형 알고리즘을 모두 지원합니다. 기본적 으로 각 가중치에 따라 요청이 전달되는 가중 라운드 로빈 방식이 사용됩니다 .
먼저, 업스트림을 준비합시다.
1 2 3 4 5 6 7 | UpstreamObject upstream = new UpstreamObject( "stock.api.service" ); ResponseEntity<String> addUpstreamResp = restTemplate.postForEntity( new HttpEntity<>(upstream), String. class ); assertEquals(HttpStatus.CREATED, addUpstreamResp.getStatusCode()); |
그런 다음 업스트림에 대해 두 개의 대상, 가중치가 10 인 테스트 버전 및 가중치가 40 인 릴리스 버전을 추가합니다 .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | TargetObject testTarget = new TargetObject( "localhost:8080" , 10 ); ResponseEntity<String> addTargetResp = restTemplate.postForEntity( new HttpEntity<>(testTarget), String. class ); assertEquals(HttpStatus.CREATED, ddTargetResp.getStatusCode()); TargetObject releaseTarget = new TargetObject( "localhost:9090" , 40 ); addTargetResp = restTemplate.postForEntity( new HttpEntity<>(releaseTarget), String. class ); assertEquals(HttpStatus.CREATED, addTargetResp.getStatusCode()); |
위의 구성으로 요청의 1/5은 테스트 버전으로, 4/5는 버전 출시 예정이라고 가정 할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | APIObject stockAPI = new APIObject( "balanced-stock-api" , "balanced.stock.api" , "/" ); HttpEntity<APIObject> apiEntity = new HttpEntity<>(stockAPI); ResponseEntity<String> addAPIResp = restTemplate.postForEntity( assertEquals(HttpStatus.CREATED, addAPIResp.getStatusCode()); HttpHeaders headers = new HttpHeaders(); headers.set( "Host" , "balanced.stock.api" ); for ( int i = 0 ; i < 1000 ; i++) { RequestEntity<String> requestEntity = new RequestEntity<>( ResponseEntity<String> stockPriceResp = restTemplate.exchange(requestEntity, String. class ); assertEquals( "10000" , stockPriceResp.getBody()); } int releaseCount = restTemplate.getForObject( int testCount = restTemplate.getForObject( assertTrue(Math.round(releaseCount * 1.0 / testCount) == 4 ); |
가중치 적용 - 라운드 로빈 방식은 백엔드 서비스에 대한 요청을 대략 가중치와 균형을 맞추기 때문에 비율의 근사값 만 확인할 수 있으며 위 코드의 마지막 줄에 반영됩니다.
5.2. 관리 API 보안
기본적으로 Kong은 로컬 인터페이스의 관리 요청 만 받아들입니다. 이는 대부분의 경우 충분하게 제한됩니다. 우리가 다른 네트워크 인터페이스를 통해 관리 할 경우에, 우리는 변경할 수 있습니다 admin_listen 가치 kong.conf을 하고, 방화벽 규칙을 구성합니다.
또는 Kong을 Admin API 자체의 프록시로 사용할 수 있습니다. "/ admin-api"경로를 사용하여 API를 관리하려는 경우 다음과 같은 API를 추가 할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 | APIObject stockAPI = new APIObject( "admin-api" , "admin.api" , "/admin-api" ); HttpEntity<APIObject> apiEntity = new HttpEntity<>(stockAPI); ResponseEntity<String> addAPIResp = restTemplate.postForEntity( apiEntity, String. class ); assertEquals(HttpStatus.CREATED, addAPIResp.getStatusCode()); |
이제 프록시 된 관리 API를 사용하여 API를 관리 할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | HttpHeaders headers = new HttpHeaders(); headers.set( "Host" , "admin.api" ); APIObject baeldungAPI = new APIObject( "baeldung-api" , "baeldung.com" , "/" ); RequestEntity<APIObject> requestEntity = new RequestEntity<>( baeldungAPI, headers, HttpMethod.POST, ResponseEntity<String> addAPIResp = restTemplate .exchange(requestEntity, String. class ); assertEquals(HttpStatus.CREATED, addAPIResp.getStatusCode()); |
확실하게, 우리는 프록시 된 API를 안전하게하고 싶습니다. 이것은 프록시 API를위한 인증 플러그 인을 사용하면 쉽게 구현할 수 있습니다.
6. 요약
이 기사에서는 마이크로 서비스 API 게이트웨이 용 플랫폼 인 Kong을 소개하고 API 및 라우팅 요청을 업스트림 서버로 관리하는 핵심 기능과로드 밸런싱과 같은 고급 기능에 중점을 두었습니다.
그러나 우리가 탐구 할 수있는 더 많은 견고한 기능이 있으며 필요한 경우 플러그인을 개발할 수 있습니다 . 여기 에서 공식 문서를 계속 탐색 할 수 있습니다 .
언제나 그렇듯이 전체 구현은 Github 에서 찾을 수 있습니다 .