1前書き
Kong は、オープンソースのAPIゲートウェイおよびマイクロサービス管理層です。
Nginxとhttps://github.com/openresty/lua-nginx-module[lua-nginx-module](特にhttp://openresty.org/[OpenResty])に基づいて、Kongのプラガブルアーキテクチャはそれを柔軟で強力にします。
2主な概念
コードサンプルを詳しく説明する前に、Kongの主な概念を見てみましょう。
-
APIオブジェクト - HTTPエンドポイントのプロパティをラップします。
特定のタスクを実行するか、サービスを提供します。設定には、HTTPメソッド、エンドポイントURI、APIサーバーを指すアップストリームURL、最大プロキシー数、レート制限、タイムアウトなどがあります
-
Consumer Object - 私たちのAPIを使っている人のプロパティをラップ
エンドポイント追跡、アクセス制御などに使用されます。 Upstream Object - ** 受信リクエストがどのようにプロキシされるのか
仮想ホスト名で表される負荷分散 ターゲットオブジェクト - ** は実装され提供されるサービスを表します。
ホスト名(またはIPアドレス)とポートで識別されます。ご了承ください すべてのアップストリームのターゲットは追加または無効にすることしかできません。の歴史 目標の変更は上流で維持されます Plugin Object - ** プラグイン可能な機能は私たちの機能を豊かにします
要求と応答のライフサイクルの間にアプリケーション。例えば、API 有効にすると、認証およびレート制限機能を追加できます。 関連するプラグインKongは非常に強力なプラグインを提供しています https://konghq.com/plugins/ 管理API - Kongの管理に使用される** RESTful APIエンドポイント
設定、エンドポイント、コンシューマ、プラグインなど
以下の図は、Kongがレガシーアーキテクチャとどのように異なるかを示しています。これは、なぜこれらの概念が導入されたのかを理解するのに役立ちます。
リンク:/uploads/Screen-Shot-2018-01-18-at-14.39.07-768x497.png%20768w[]+(ソース:https://getkong.org/)
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を操作するときに使用されるAPIの識別子です。
動作 ** "hosts" は与えられたリクエストをルーティングするために使われます
"Host" ヘッダーを照合して "upstream url" __ ** 相対パスは設定された「uris」に一致します
APIを非推奨にしたい場合や設定が間違っている場合は、単純に削除できます。
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コンシューマの追加
それでは、セキュリティについて説明しましょう。具体的には、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にauthプラグインを適用します。
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());
Eugen は当社のAPIコンシューマの1つであることを忘れないでください。そのため、認証キーを追加してこの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は、バックエンドサービスへのリクエストを負荷分散するための2つの戦略を提供しています。動的リングバランサと直接的な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());
次に、アップストリーム用に2つのターゲット、 weight = 10 を持つテストバージョン、および weight = 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はローカルインターフェイスからの管理者の要求のみを受け付けます。これはほとんどの場合十分な制限です。しかし、他のネットワークインターフェースを介して管理したい場合は、 kong.conf の admin listen__値を変更し、ファイアウォールルールを設定することができます。
または、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の管理と上流サーバーへの要求のルーティング、さらにロードバランシングなどのより高度な機能について説明しました。
それでも、私達が探求するためのもっと多くのしっかりした機能があり、私達が必要なら私達自身のプラグインを開発することができます - あなたはhttps://getkong.org/docs/[公式文書]をここで探検し続けることができます]
いつもどおり、完全な実装はhttps://github.com/eugenp/tutorials/tree/master/spring-boot?[over on Github]にあります。