Kong Gatewayに入門する with Helm

Private AI周りでAPIを触ってて、APIをキャッシュして発行回数減らせないかな、と思ってたところ、Kong Gatewayがそれっぽい機能を持っていたのでKongに入門してみた。
せっかくなので、ここではProxy Cacheだけではなく、[Get Started](https://docs.konghq.com/gateway/3.5.x/get-started/)にある
- ServiceとRoute
- レート制限
- 鍵認証
- ロードバランシング

も合わせて確認する。
ただ、Get Startedに沿って入門したいのだが、Get StartedはDocker前提で書かれていてHelmベースでKongを導入した人にはなぞりにくい内容となっている。
ここではHelmベースに置き換えたらどうなるかと、せっかくのUIも活用したいのでなるべくCLIを使わずに設定できるか、の観点でGet Startedの内容を少しアレンジして検証する。

## インストール
Get Startedを始めるにあたり、Kong Gatewayを用意する。
[Helmのインストール方法](https://docs.konghq.com/gateway/3.5.x/install/kubernetes/helm-quickstart/)を参照してインストールする。

### 前提
ここでは以下の環境があるものとして進める
- Kubernetesクラスタ（ここではTanzu Kubernetes Gridを利用）
- Kubernetesクラスタは`type: LoadBalancer`が利用可能
- 作業端末にkubectl, helmコマンドがインストール済み

また、今回検証で使ったKong Gatewayのバージョンは3.5である。

### 前準備
Ingressを使うので、Ingress Controllerを入れておく。
Kongは[Ingress Controllerも配布している](https://github.com/Kong/kubernetes-ingress-controller)ので、これを使ってみる。
なお、Kong GatewayのHelm ChartにもIngress Controllerの項目があるのでそちらからインストールすることも出来そうだが、ここでは分けて入れた。
最初にCRDをインストールする。
配布されているものが標準的な`Gateway`リソースのCRDと、Experimentalで`TCPRoute`とかも含むCRDの2種類用意されている。
せっかくなのでExperimental版をインストールする。
```sh
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/experimental-install.yaml
```
Ingress Controllerをインストールする。
```sh
helm install kong-ingress --namespace kong --create-namespace --repo https://charts.konghq.com ingress
```
問題なければこんな感じでオブジェクトが作成される。
```sh
$ kubectl get all -n kong
NAME                                           READY   STATUS    RESTARTS   AGE
pod/kong-ingress-controller-6f8bf5f6bc-g9bql   1/1     Running   0          32s
pod/kong-ingress-gateway-7778fbf68f-dhqm5      1/1     Running   0          32s

NAME                                                 TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)                         AGE
service/kong-ingress-controller-validation-webhook   ClusterIP      10.100.137.100   <none>         443/TCP                         34s
service/kong-ingress-gateway-admin                   ClusterIP      None             <none>         8444/TCP                        34s
service/kong-ingress-gateway-manager                 NodePort       10.106.59.205    <none>         8002:31176/TCP,8445:31808/TCP   34s
service/kong-ingress-gateway-proxy                   LoadBalancer   10.102.184.40    10.220.35.70   80:31070/TCP,443:30384/TCP      34s

NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kong-ingress-controller   1/1     1            1           33s
deployment.apps/kong-ingress-gateway      1/1     1            1           33s

NAME                                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/kong-ingress-controller-6f8bf5f6bc   1         1         1       33s
replicaset.apps/kong-ingress-gateway-7778fbf68f      1         1         1       33s
```

次にKong GatewayのHelmのvalues.yamlを取ってくる。(公式手順にあわせて名前はquickstart.yamlにしている)
```sh
curl -o quickstart.yaml -L https://bit.ly/KongGatewayHelmValuesAIO
```
次に自身のドメインの設定を行うが、ここは公式手順と異なりフリーのワイルドカードDNSサービスである[nip.io](https://nip.io/)を利用するため、sedの処理を以下のように変える。
```sh
export BASE_DOMAIN=$(sed "s/\./-/g" <<< $(kubectl get svc -n kong kong-ingress-gateway-proxy -o jsonpath={.status.loadBalancer.ingress[0].ip}))
sed -i "s/127-0-0-1\.nip\.io/${BASE_DOMAIN}.nip.io/g" quickstart.yaml
```
また、他に以下の変更を加えた。
- `admin.ingress`に`ingressClassName: kong`を追記
- `ingressController.enabled`を`false`に変更

初期パスワードやPostgresの接続先などを定義したSecretを作成する。Ingress ControllerをKongのものにしていない場合はNamespace(ここではkong)を作成すること。
```sh
kubectl create secret generic kong-config-secret -n kong \
    --from-literal=portal_session_conf='{"storage":"kong","secret":"super_secret_salt_string","cookie_name":"portal_session","cookie_same_site":"Lax","cookie_secure":false}' \
    --from-literal=admin_gui_session_conf='{"storage":"kong","secret":"super_secret_salt_string","cookie_name":"admin_session","cookie_same_site":"Lax","cookie_secure":false}' \
    --from-literal=pg_host="enterprise-postgresql.kong.svc.cluster.local" \
    --from-literal=kong_admin_password=kong \
    --from-literal=password=kong
```

LicenseのSecretを作成する。ライセンスが無い場合は`--from-literal`で`license="'{}'"`のように空を渡す。
```sh
kubectl create secret generic kong-enterprise-license --from-literal=license="'{}'" -n kong --dry-run=client -o yaml | kubectl apply -f -
```
cert-managerをインストールする。
```sh
helm repo add jetstack https://charts.jetstack.io ; helm repo update
helm upgrade --install cert-manager jetstack/cert-manager \
    --set installCRDs=true --namespace cert-manager --create-namespace
```
cert-managerを使ってオレオレ証明書を作成する。証明書を持ってる人は自分のものに差し替えることも可能。
```yaml
bash -c "cat <<EOF | kubectl apply -n kong -f -
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
 name: quickstart-kong-selfsigned-issuer-root
spec:
 selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
 name: quickstart-kong-selfsigned-issuer-ca
spec:
 commonName: quickstart-kong-selfsigned-issuer-ca
 duration: 2160h0m0s
 isCA: true
 issuerRef:
   group: cert-manager.io
   kind: Issuer
   name: quickstart-kong-selfsigned-issuer-root
 privateKey:
   algorithm: ECDSA
   size: 256
 renewBefore: 360h0m0s
 secretName: quickstart-kong-selfsigned-issuer-ca
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
 name: quickstart-kong-selfsigned-issuer
spec:
 ca:
   secretName: quickstart-kong-selfsigned-issuer-ca
EOF"
```

### Kong Gatewayのデプロイ
Kongのリポジトリを追加する。
```sh
helm repo add kong https://charts.konghq.com ; helm repo update
```
Helm Chartをデプロイする。公式手順に従ってリリース名は`quickstart`にしている。
```sh
helm install quickstart kong/kong --namespace kong --values quickstart.yaml
```
デプロイが終わって、"https\://kong.${BASE_DOMAIN}.nip.io"をブラウザで開くとUI画面が確認できる。
![1703500134628.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/6f01e637-f0af-6702-94f4-d29e4194fa06.png)
ちなみに`New Workspace`のボタンが活性化されていないのは[Free ModeだとWorkspaceを新規作成できない](https://docs.konghq.com/gateway/latest/kong-enterprise/workspaces/)ためである。
基本的にはここからの作業はこの`default`のworkspaceを使っていく。

## [ServiceとRoute](https://docs.konghq.com/gateway/3.5.x/get-started/services-and-routes/)
Kongではトラフィック管理にServiceとRouteと呼ばれるオブジェクトを用いている。
Serviceはアプリケーションが提供するサービスを抽象化したもので、プロトコルやホスト、パスなどを含む。
[Service Objectの例](https://docs.konghq.com/gateway/latest/admin-api/#service-object)：
```json
{
    "id": "9748f662-7711-4a90-8186-dc02f10eb0f5",
    "created_at": 1422386534,
    "updated_at": 1422386534,
    "name": "my-service",
    "retries": 5,
    "protocol": "http",
    "host": "example.com",
    "port": 80,
    "path": "/some_api",
    ：（省略）
```
Routeはアプリケーション内のリソースへのパスで、クライアントからのリクエストにマッチするルールを定義する。
![1703501009009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/0ca82ebb-ee3b-dfbe-58a4-d1eb08060686.png)
（引用元：[Services and Routes](https://docs.konghq.com/gateway/3.5.x/get-started/services-and-routes/))
RouteはServiceと関連付けられ、Serviceは複数のRouteを持つことが出来る。これにより、異なるパスへの異なるリクエストを単一のAPIで処理することも出来る。
```mermaid
stateDiagram-v2
    User1 --> Route1 : /web GET
    User2 --> Route2 : /api POST
    Route1 --> Service
    Route2 --> Service
    Service --> App
```
ここではGet Startedの一部である[Managing services and routes](https://docs.konghq.com/gateway/3.5.x/get-started/services-and-routes/#managing-services-and-routes)の内容をKong Admin UIから試してみる。

### Serviceの作成
Admin UIにアクセスし、Workspace内の`default`をクリックし、`Gateway Services`から`New Gateway Service`をクリックする。
クリックすると入力フォームが出てくるので入力する。
![1703572823992.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/83cde73d-20e6-556c-c90d-1f1cdbfdcf3a.png)

ここではGet StartedのService作成コマンドにあわせて、以下のように設定した。
- `Name`: example_service
- `Upstream URL`: http://httpbin.org

無事Serviceが作成されたらUIから確認できるはずだ。
作成されたServiceの右の︙をクリックし、`View Details`をクリックすると内容が確認できる。
Formatのところを選択するとJSONでも表示できる。

![1703574637840.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/8c848ae8-a672-3690-8e5b-53216d8526bd.png)

また、curlで取得できることも確認する。
Helmでインストールした場合、Adminへのアクセス方法はIngressオブジェクトの中身を見ると`/api`になっており、Serviceの参照URLは`/services/<Service nameかID>`となっているため、以下で取得を確認する。
```sh
curl -X GET https://kong.${BASE_DOMAIN}.nip.io/api/services/example_service -k -L | jq .
```
無事参照出来た。
```json
{
  "port": 80,
  "id": "0ad9fb49-c198-4620-80b2-9305808bc625",
  "client_certificate": null,
  "write_timeout": 60000,
  "connect_timeout": 60000,
  "name": "example_service",
  "read_timeout": 60000,
  "host": "httpbin.org",
  "protocol": "http",
  "tags": null,
  "ca_certificates": null,
  "tls_verify": null,
  "tls_verify_depth": null,
  "path": null,
  "retries": 5,
  "enabled": true,
  "created_at": 1703572948,
  "updated_at": 1703572948
}
```

### Routeの作成
こちらも同じくUIから作成する。
`default`Workspaceの左サイドバーから`Routes`をクリックし、`New Route`をクリックする。
こちらも元のGet Startedの記載にあわせて入力する。
![1703574126699.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/b3ce4a46-d9ee-b0c0-cb58-d05103a53c29.png)
設定した値は以下となる。(設定していない箇所はデフォルト値を使用)
- `Name`: example_route
- `Service`: example_serviceを選択
- `Paths`: /mock 

無事作成できたら、Serviceと同じように詳細を確認する。
![1703574591832.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/b721aeb1-b00c-2c26-9646-e9e5c7e8343b.png)

また、Serviceと同じようにcurlでも確認する。
```sh
curl -X GET https://kong.${BASE_DOMAIN}.nip.io/api/routes/example_route -k -L | jq .
```
こちらも無事取得できた。
```json
{
  "service": {
    "id": "0ad9fb49-c198-4620-80b2-9305808bc625"
  },
  "id": "e3aaef3d-8b12-46bb-b7f0-37c94bfc5f58",
  "request_buffering": true,
  "response_buffering": true,
  "destinations": null,
  "https_redirect_status_code": 426,
  "regex_priority": 0,
  "headers": null,
  "snis": null,
  "sources": null,
  "protocols": [
    "http",
    "https"
  ],
  "tags": [],
  "paths": [
    "/mock"
  ],
  "path_handling": "v0",
  "preserve_host": false,
  "strip_path": true,
  "name": "example_route",
  "updated_at": 1703574216,
  "methods": null,
  "created_at": 1703574216,
  "hosts": null
}
```

### エンドサービスへのアクセス
KongはRouteに定義したPathを使ってトラフィックをルーティングする。
<Helmリリース名>-kong-proxyという`kind: Service`のオブジェクトが`type: LoadBalancer`でIPを公開しており、これへのアクセスをルーティングしてくれるようなので、さっそくアクセスしてみる。
先程作成したRouteのPathは`/mock`だったので、kong-proxyのIPに`/mock`をつけたものがhttpbin.orgと思ってアクセスする。
```sh
$ export PROXY_IP=$(kubectl get svc -n kong quickstart-kong-proxy -o jsonpath={.status.loadBalancer.ingress[0].ip})
$ curl -X GET http://${PROXY_IP}/mock/ip -k
{
  "origin": "192.168.3.1, xxx.xxx.xxx.xxx"
}
```
無事httpbinへ飛ばしてくれて、結果を取得することが出来た。

## [レート制限](https://docs.konghq.com/gateway/3.5.x/get-started/rate-limiting/)
次にレート制限を確認する。
レート制限には[Rate Limiting Plugin](https://docs.konghq.com/hub/kong-inc/rate-limiting/)を利用する。
こちらもGet Startedの手順（CLI）では実施せずに、Admin UIベースで進める。
`default`Workspaceの左サイドバーから`Plugins`をクリックし、`New Plugin`をクリックする。
こちらも元のGet Startedの記載にあわせて入力する。
Pluginの一覧画面になるので、検索窓で"Rate Limit"を検索する。
![1703577339794.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/0160f97f-9346-8e4b-0e37-213087eb4b5f.png)
`Enable`をクリックするとインストール画面に遷移するので、値を設定する。
![1703577462692.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/144c678e-fc32-b52c-1ba8-cbd5c3b86da0.png)
ここでは以下の値を設定した。
- `Instance Name`: rate-limiting
- `minute`: 5

これにより、1分あたり5回を超えてアクセスする分には制限が掛かるようになる。
他はデフォルト値とした。
なお、Get Startedでは`config.policy=local`としているが、これはUIから設定する場合はデフォルトが`local`となっているため、設定不要となる。
`Install`をクリックするとインストールされる。
ServiceやRouteと同じように`View Details`をクリックすると同じように詳細情報が取得できる。
![1703577643678.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/86907032-5efa-1eed-9a35-e2d1fd695cf9.png)
設定を一部抜粋する。
```json
    "error_code": 429,
    "error_message": "API rate limit exceeded",
    "minute": 5,
```
これは1分間に5回以上アクセスすると、429と設定されたエラーメッセージを返すことを意味している。
早速試してみる。
curlを連続して実行したところ、6回目に以下のエラーを得ることが出来た。
```sh
$ curl -i http://$PROXY_IP/mock/ip
HTTP/1.1 429 Too Many Requests
Date: Tue, 26 Dec 2023 11:06:09 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
RateLimit-Reset: 51
X-RateLimit-Limit-Minute: 5
Retry-After: 51
X-RateLimit-Remaining-Minute: 0
RateLimit-Remaining: 0
RateLimit-Limit: 5
Content-Length: 92
X-Kong-Response-Latency: 0
Server: kong/3.5.0.2-enterprise-edition
X-Kong-Request-Id: 0dd34b10979c3b4bcf68517b51361e5c

{
  "message":"API rate limit exceeded",
  "request_id":"0dd34b10979c3b4bcf68517b51361e5c"
}
```
これにより、レート制限が適切に効いたことが確認できる。
また、ヘッダでレート制限の情報が取得できることも確認できる。

## [Proxy Cache](https://docs.konghq.com/gateway/3.5.x/get-started/proxy-caching/)
Kong Gatewayでは[Proxy Cache Plugin](https://docs.konghq.com/hub/kong-inc/proxy-cache/)を使ってキャッシュ機能を提供している。
これを使ってみる。
なお、以下のキャッシュの種類が用意されている。
- グローバル：全てのリクエストに対してキャッシュする
- Serviceレベル：特定のServiceに対してキャッシュする
- Routeレベル：特定のRouteに対してキャッシュする
- コンシューマレベル：コンシューマ（ユーザを抽象化したもの）単位でのキャッシュ

それぞれのレイヤでPluginをインストールして利用することになる。
ここではServiceレベルで試してみる。
`default`Workspaceの左サイドバーから`Gateway Services`で作成した`example_service`をクリックし、`Plugins`->`New Plugin`をクリックする。
こちらも元のGet Startedの記載にあわせて入力する。
Pluginの一覧画面になるので、検索窓で"Proxy Caching"を検索し、`Enable`をクリックする。
![1703578962069.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/b7f91cb5-d561-30d7-7124-2183e753d51b.png)

こうすると、最初からProxyの範囲が指定された状態でインストール画面となる。
Get Startedに合わせて値を設定していく。
![1703579322784.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/9d40567e-9b93-d90f-82cd-430f4356ac0c.png)

ここでは以下の値を設定し、他はデフォルト値とした。
- `cache_ttl`: 30
- `request_method`: GET
- `response_code`: 200

`cache_ttl`を30に設定することで、キャッシュは30秒間保持され、期間を超えると破棄される。
インストール完了後、再度Proxyに対してcurlを実行する。
```sh
$ curl -i http://$PROXY_IP/mock/ip
：（省略）
X-Cache-Key: 8d9a6010fe0c02b2924e1f7bf7a1d4e4ce22fe87e91021c697cc28f8de0fc3f1
X-Cache-Status: Miss
：（省略）
```
キャッシュを見に行ったことが確認できた。
再度実行すると、以下のようにキャッシュを使ったことが読み取れる。
```sh
X-Cache-Key: 8d9a6010fe0c02b2924e1f7bf7a1d4e4ce22fe87e91021c697cc28f8de0fc3f1
X-Cache-Status: Hit
```
また、30秒以上間をあけて再実行すると、`Miss`が表示されることが確認できる。
これによりキャッシュが使えていることが確認できる。


## [鍵認証](https://docs.konghq.com/gateway/3.5.x/get-started/key-authentication/)
Kong GatewayではPluginで認証を提供しており、以下のような認証が利用できる。
- 鍵認証
- Basic認証
- OAuth 2.0
- LDAP
- OpenID Connect

ここでは鍵認証を試してみる。

最初に鍵認証を有効化する。
Proxy Cacheと同様にグローバル、Service、Routeの単位で設定できるため、ここではProxy Cacheと同様にServiceに設定する。
`default`Workspaceの左サイドバーから`Gateway Services`で作成した`example_service`をクリックし、`Plugins`->`New Plugin`をクリックする。
"key"で検索するとKey Authorization Pluginが見えるので`Enable` にする。
![1703582082082.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/00177672-6e1a-9fda-d493-d430fe6368d4.png)
値の設定画面ではInstance Nameを`key-auth`にし、他はデフォルト値のままインストールする。 
これでキー認証が有効化された。

次にユーザを抽象化したオブジェクトであるコンシューマを作成する。
`default`Workspaceの左サイドバーから`Consumers`をクリックし、`New Consumer`をクリックする。
Get Startedと同じく`luka`というUsernameで作成する。
![1703581710623.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/777588f2-1016-d607-55b5-2bf2008bbd1e.png)
作成したコンシューマにキーを割り当てる。
作成したコンシューマの`Credentrials`から`New Key Auth Credential`を選択し、キーを作成する。
![1703725112859.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/8d93b2a2-4e01-58f8-d892-9eb732a2fec8.png)

ここではKeyに`top-secret-key`を設定した。
なお、この設定値はUIから確認できるし、Admin APIの`/consumers/<ユーザ名>/key-auth`をGETすることでも確認できる。
先程までアクセスできていた、httpbinのサービスにアクセスしてみる。
```sh
$ curl -i http://$PROXY_IP/mock/ip
HTTP/1.1 401 Unauthorized
Date: Thu, 28 Dec 2023 00:01:45 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
WWW-Authenticate: Key realm="kong"
Content-Length: 96
X-Kong-Response-Latency: 2
Server: kong/3.5.0.2-enterprise-edition
X-Kong-Request-Id: b723b10614ac7a3e1ecc431880199603

{
  "message":"No API key found in request",
  "request_id":"b723b10614ac7a3e1ecc431880199603"
}
```
鍵認証が設定されたことで、キーなしではアクセスに失敗するようになった。
ヘッダにキーを設定してアクセスしてみる。
```sh
$ curl -i http://$PROXY_IP/mock/ip -H 'apikey:top-secret-key'
HTTP/1.1 200 OK
Content-Type: application/json
：（省略）
X-Kong-Request-Id: 7970436b3bcdfc6a0f6e583c6b11d32c

{
  "origin": "192.168.3.1, xxx.xxx.xxx.xxx"
}
```
無事取得できた。試しに設定していないキーでも試してみる。
```sh
$ curl -i http://$PROXY_IP/mock/ip -H 'apikey:nokey'
HTTP/1.1 401 Unauthorized
Date: Thu, 28 Dec 2023 00:07:49 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Content-Length: 81
X-Kong-Response-Latency: 15
Server: kong/3.5.0.2-enterprise-edition
X-Kong-Request-Id: b2cc5178a000f45450462543b2f0712f

{
  "message":"Unauthorized",
  "request_id":"b2cc5178a000f45450462543b2f0712f"
}
```
ちゃんと弾かれた。



## [ロードバランシング](https://docs.konghq.com/gateway/3.5.x/get-started/load-balancing/)
Kong Gatewayにはロードバランサの機能もあり、負荷分散やヘルスチェック、サーキットブレーカー的な機能を提供する模様。
ここではGet Startedに従って、ラウンドロビンで以下のように`httpbin.org`と`httpbun.com`に分散する。
```mermaid
stateDiagram-v2
    User --> Route: /ip GET
    Route --> Service
    Service --> Upstream
    Upstream --> httpbin.org
    Upstream --> httpbun.com
```
なお、`httpbun.com`は今回初めて知ったが、`httpbin.org`と同様の機能を提供するサービスのようだ。
```sh
$ curl httpbun.com/ip
{
  "origin": "xxx.xxx.xxx.xxx"
}
```
早速設定していく。
`default`Workspaceの左サイドバーから`Upstreams`をクリックし、`New Upstream`をクリックする。
設定画面になるので値を入れて`Save`をクリックする。
![1703729261398.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/652676da-353c-5204-9a13-f2266f62c22f.png)
ここでは、`Name`に`example_upstream`を設定した。
なお、名前を入力する際に上記の画像のように`(Add new value)`と表示されるが、これをクリックしないと名前が正確に反映されず、`Save`が活性化されずにクリックできないため注意。

次にロードバランスする先を設定する。
保存後、作成された`example_upstream`をクリックし、`Targets`から`New Target`をクリックして`httpbin.org:80`と`httpbun.com:80`を追加する。なお、ポートを指定しない場合は8000ポートが割り当てられる。
![1703730713260.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/c8dea083-c14f-27fa-8e28-e0145399b699.png)

最後にServiceを変更する。
今は`example_service`のエンドポイントは`httpbin.org`を向いているが、これを今作成した`example_upstream`に変更する。
`default`Workspaceの左サイドバーから`Gateway Services`->`example_service`で画面遷移後、`Gateway Service actions`から`Edit configuration`をクリックする。
![1703730301448.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/63066ebc-9615-28e8-89f7-e2cac5fed478.png)
`Host`の項目を`example_upstream`に書き換え、`Save`をクリックして保存する。
これでアクセスが分散する。

試してみる。何度かアクセスし、Hostが変わることを確認する。
キャッシュの設定が残っている場合は少し間を置いてアクセスしないと駄目かも。
```sh
$ curl -i http://$PROXY_IP/mock/headers -H 'apikey:top-secret-key' 2>&1 | grep '"Host"'
    "Host": "httpbin.org",
$ curl -i http://$PROXY_IP/mock/headers -H 'apikey:top-secret-key' 2>&1 | grep '"Host"'
  "Host": "httpbun.com",
```
`httpbin.org`と`httpbun.com`にアクセスしていることが確認できた。

## まとめ
Kong Gatewayでの各種機能を一通り触って、以下を確認できた。
- Kong GatewayでAPIに対するキャッシュ、認証、制限、LBなどの機能が簡単に設定できる
- Get Startedに書かれているCLIでの手順は全てUIでも確認できる
- Helmでインストールする環境でもGet Startedの内容は全て同等に実施できる

所感としては、特別なコマンドを使わず設定できること、UIは癖がないことなどから非常に使いやすいツールだと感じた。
また、Podのログも少し見たが、しっかり出ているようなのでトラシュもやりやすそう。
なお、どうも似たようなことがKong Ingress Controllerでも[出来そう](https://docs.konghq.com/kubernetes-ingress-controller/latest/get-started/)なので、こちらも機会があれば確認してみたいと思う。