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