Kong Gatewayをデプロイする（Traditionalモード編）

# はじめに
Kong Gatewayは、以下の4つのモードでデプロイすることができます。
* Traditionalモード
* DB-less and declarativeモード
* Hybridモード
* Kong Konnect

それぞれの方式には利点と制限事項があります。そのため、Kong Gatewayを本番環境にインストールする際には、どのモードを選択するかを慎重に判断することが重要です。

本記事では、Traditionalモードの特徴、メリット、デメリット、ならびにデプロイ手順について説明します。

Kong Gatewayとは何かを知りたい場合は、以下の記事をご覧ください。

https://qiita.com/m5takeda/items/d7c74681c66692144ccc

# Traditionalモードとは
Traditionalモードは、Kong Gatewayの各インスタンスが直接データベース（DB）に接続し、すべてのKongインスタンスが同一のDBを共有する構成です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2812915/fd63458b-7c89-85ac-547d-690286ff9fb5.png" width=70%>

## 特徴
* **DBのタイプ**：
サポートされるDBはPostgreSQLのみです。DBには、Route、Service、プラグインなどの設定情報やメトリクス情報を保存します。

* **負荷分散**：
Kongインスタンス間での負荷分散を行うには、Kongインスタンスの前にロードバランサを設置します。

* **キャッシュ機能**：
Kongインスタンスはリクエストをプロキシする際に、DBに毎回接続せず、DBの情報をメモリにキャッシュします。キャッシュされる情報には、Service、Route、Consumer、プラグイン、クレデンシャルなどが含まれます。

* **設定変更の同期**：
各ノードはDBの更新情報をポーリングするジョブを定期的に実行します。他のノードによる設定変更が検知されるとキャッシュ無効化イベントが発生し、関連するキャッシュが削除されます。

* **読み取り専用レプリカの利用**：
PostgreSQLの読み取り専用レプリカを利用し、メインDBインスタンスの負荷を軽減できます。これにより、読み取り専用クエリがメインDBではなく読み取り専用レプリカへ送信されます。

## メリット
* **シンプルな構成**：
Traditionalモードは構成が最もシンプルで、構築が容易です。

* **DBを必要とするプラグインのサポート**：
クラスタ戦略によるレート制限やOAuth 2.0のようにDBを必要とするプラグインをサポートする唯一の構成です。詳細は[プラグインの互換性](https://docs.konghq.com/hub/plugins/compatibility/)をご覧ください。

## デメリット
* **ノードの脆弱性**：
すべてのKongインスタンスがコントロールプレーン[^1]とデータプレーン[^2]の役割を持つため、1つのノードが攻撃された場合、他のすべての実行中のノードに影響が及ぶ可能性があります。

[^1]: すべてのデータプレーンの設定を管理する。API構成管理、ノードへの構成データの配布、ノードの監視、管理インタフェースの提供などの機能を持つ。

[^2]: APIトラフィックの処理とルーティングを提供する。トラフィックのプロキシ、モニタリング、ロギング、保護などの機能をもつ。

* **高負荷の影響**：
Kong Gateway Enterpriseでは、Kong Managerが高負荷な処理（例えば、分析データの処理やグラフのレンダリング）を行っているノードにおいて、リクエストのスループットが低下する可能性があります。


# Traditionalモードのセットアップ

公式ドキュメントを参考に、Dockerを使用してKong GatewayをTraditionalモードでデプロイします。

https://docs.konghq.com/gateway/latest/install/docker/

## 環境
* WSL 2
* Ubuntu 22.04.1
* Docker v1.0.29

## 実施手順
### DBの準備
TraditionalモードではDBが必要になるため、PostgreSQLでDBを構築します。

(1) Dockerネットワークを作成します。
```bash
$ docker network create kong-net
```

(2) PostgreSQLコンテナを起動します。
```bash
$ docker run -d --name kong-database \
 --network=kong-net \
 -p 5432:5432 \
 -e "POSTGRES_USER=kong" \
 -e "POSTGRES_DB=kong" \
 -e "POSTGRES_PASSWORD=kongpass" \
 postgres:13
```
設定項目は以下の通りです。

|項目名  |説明  |設定値  |
|---|---|---|
|POSTGRES_USER|Postgresのユーザ名。Kong Gatewayから期待されるデフォルト値は`kong`。|kong|
|POSTGRES_DB|PostgresのDB名。Kong Gatewayから期待されるデフォルト値は`kong`。 |kong|
|POSTGRES_PASSSWORD|Postgresのパスワード。|kongpass|


(3) Kong DBを準備します。
```bash
$ docker run --rm --network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_PASSWORD=kongpass" \
-e "KONG_PASSWORD=test" \
kong/kong-gateway:3.8.1.0 kong migrations bootstrap
```
`{IMAGE-NAME:TAG} kong migrations bootstrap`は、Postgres DBを準備するためのKong Gatewayのコマンドです。

設定項目は以下の通りです。

|項目名  |説明  |設定値  |
|---|---|---|
|KONG_DATABASE|Kongが使用するDBの種類。|postgres|
|KONG_PG_HOST|手順(2)で`kong-net`ネットワーク上で通信しているPostgres Dockerコンテナの名前。|kong-database|
|KONG_PG_PASSWORD|手順(2)でPostgresコンテナを立ち上げるときに設定したパスワード。|kongpass|
|KONG_PASSWORD <br>※Kong Gateway Enterpriseのみ|Kong GatewayのSuper Adminユーザ[^3]のデフォルトパスワード。|test|

[^3]: RBAC機能を設定するために、最初に作成するユーザ。

### Kong Gatewayの起動

(1) (オプション）Kong Gateway Enterpriseのライセンスを持っている場合は、ライセンスキーを変数にエクスポートします。
※こちらのライセンスキーはダミーです。
```bash
$ export KONG_LICENSE_DATA='{"license"：{"payload": {"admin_seats": "1", "customer": "Example Company, Inc", "dataplanes": "1", "license_creation_date": "2017-07-20", "license_expiration_date"："2017-07-20","license_key":"00141000017ODj3AAG_a1V41000004wT0OEAU","product_subscription":"Konnect Enterprise","support_plan":"None"},"signature":"6985968131533a967fcc721244a979948b1066967f1e9cd65dbd8eeabe060fc32d894a2945f5e4a03c1cd2198c74e058ac63d28b045c2f1fcec95877bd790e1b","version":"1"}}'
```

(2) Kong Gatewayを搭載したコンテナを起動します。

```bash
$ docker run -d --name kong-gateway \
--network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_USER=kong" \
-e "KONG_PG_PASSWORD=kongpass" \
-e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
-e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
-e "KONG_PROXY_ERROR_LOG=/dev/stderr" \
-e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \
-e "KONG_ADMIN_LISTEN=0.0.0.0:8001" \
-e "KONG_ADMIN_GUI_URL=http://localhost:8002" \
-e KONG_LICENSE_DATA \
-p 8000:8000 \
-p 8443:8443 \
-p 8001:8001 \
-p 8444:8444 \
-p 8002:8002 \
-p 8445:8445 \
kong/kong-gateway:3.8.1.0
```

設定項目は以下の通りです。

|項目名  |説明  |設定値  |
|---|---|---|
|KONG_DATABASE|Kongが使用するDBの種類。|postgres|
|KONG_PG_HOST|Postgres Dockerコンテナの名前。 |kong-database|
|KONG_PG_USER|Postgresのユーザ名。|kong|
|KONG_PG_PASSWORD|Postgresのパスワード。|kongpass|
|すべての_LOG設定|出力するログのファイルパスを設定するか、stdoutとstderrにメッセージとエラーを出力する。|/dev/stdoutまたは/dev/stderr|
|KONG_ADMIN_LISTEN|Kong Admin APIがリクエストをリッスンするポート。|0.0.0.0:8001|
|KONG_ADMIN_GUI_URL|Kong ManagerにアクセスするためのURL。|http://localhost:8002|
|KONG_LICENSE_DATA <br>※Kong Gateway Enterpriseのみ|ライセンスファイルを環境変数として保存している場合、環境変数からライセンスを取得する。|-|

また、各ポートの役割は以下にまとめられています。

https://docs.konghq.com/gateway/latest/production/networking/default-ports/

## 動作確認

(1) Admin APIの`/service`エンドポイントにアクセスし、インストールできたか確認します。

```bash
$ curl -i -X GET --url http://localhost:8001/services
```

ステータスコードに200が出力されたら成功です。
```bash
HTTP/1.1 200 OK
Date: Mon, 18 Nov 2024 19:58:26 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: http://localhost:8002
X-Kong-Admin-Request-ID: b333997748d4935ba36a4533d4e23b1c
vary: Origin
Access-Control-Allow-Credentials: true
Content-Length: 23
X-Kong-Admin-Latency: 170
Server: kong/3.8.1.0-enterprise-edition

{"data":[],"next":null}
```

(2) `KONG_ADMIN_GUI_URL`で指定したURLを使ってKong Managerにアクセスし、Kong Managerが起動していることを確認します。

```
http://localhost:8002
```

![Kong Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2812915/2f0c484b-5d4b-6a47-1ed0-4f1f18b2b27f.png)

# さいごに
本記事では、Kong Gatewayのデプロイ方式の一つであるTraditionalモードについて、その特徴、メリット、デメリット、そして具体的なセットアップ手順を説明しました。Traditionalモードは、構成がシンプルで容易に構築できます。

一方で、全ノードがコントロールプレーンとデータプレーンの両方の役割を持つため、ノードの脆弱性に注意が必要です。また、高負荷による影響を受けやすいため、デプロイ時にこれらの点を考慮することが重要です。