コング入門

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]にあります。