1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Kong Gatewayに入門する with Helm

Last updated at Posted at 2023-12-28

Private AI周りでAPIを触ってて、APIをキャッシュして発行回数減らせないかな、と思ってたところ、Kong Gatewayがそれっぽい機能を持っていたのでKongに入門してみた。
せっかくなので、ここではProxy Cacheだけではなく、Get Startedにある

  • ServiceとRoute
  • レート制限
  • 鍵認証
  • ロードバランシング

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

インストール

Get Startedを始めるにあたり、Kong Gatewayを用意する。
Helmのインストール方法を参照してインストールする。

前提

ここでは以下の環境があるものとして進める

  • Kubernetesクラスタ(ここではTanzu Kubernetes Gridを利用)
  • Kubernetesクラスタはtype: LoadBalancerが利用可能
  • 作業端末にkubectl, helmコマンドがインストール済み

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

前準備

Ingressを使うので、Ingress Controllerを入れておく。
KongはIngress Controllerも配布しているので、これを使ってみる。
なお、Kong GatewayのHelm ChartにもIngress Controllerの項目があるのでそちらからインストールすることも出来そうだが、ここでは分けて入れた。
最初にCRDをインストールする。
配布されているものが標準的なGatewayリソースのCRDと、ExperimentalでTCPRouteとかも含むCRDの2種類用意されている。
せっかくなのでExperimental版をインストールする。

kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/experimental-install.yaml

Ingress Controllerをインストールする。

helm install kong-ingress --namespace kong --create-namespace --repo https://charts.konghq.com ingress

問題なければこんな感じでオブジェクトが作成される。

$ 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にしている)

curl -o quickstart.yaml -L https://bit.ly/KongGatewayHelmValuesAIO

次に自身のドメインの設定を行うが、ここは公式手順と異なりフリーのワイルドカードDNSサービスであるnip.ioを利用するため、sedの処理を以下のように変える。

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.ingressingressClassName: kongを追記
  • ingressController.enabledfalseに変更

初期パスワードやPostgresの接続先などを定義したSecretを作成する。Ingress ControllerをKongのものにしていない場合はNamespace(ここではkong)を作成すること。

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-literallicense="'{}'"のように空を渡す。

kubectl create secret generic kong-enterprise-license --from-literal=license="'{}'" -n kong --dry-run=client -o yaml | kubectl apply -f -

cert-managerをインストールする。

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を使ってオレオレ証明書を作成する。証明書を持ってる人は自分のものに差し替えることも可能。

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のリポジトリを追加する。

helm repo add kong https://charts.konghq.com ; helm repo update

Helm Chartをデプロイする。公式手順に従ってリリース名はquickstartにしている。

helm install quickstart kong/kong --namespace kong --values quickstart.yaml

デプロイが終わって、"https://kong.${BASE_DOMAIN}.nip.io"をブラウザで開くとUI画面が確認できる。
1703500134628.png
ちなみにNew Workspaceのボタンが活性化されていないのはFree ModeだとWorkspaceを新規作成できないためである。
基本的にはここからの作業はこのdefaultのworkspaceを使っていく。

ServiceとRoute

Kongではトラフィック管理にServiceとRouteと呼ばれるオブジェクトを用いている。
Serviceはアプリケーションが提供するサービスを抽象化したもので、プロトコルやホスト、パスなどを含む。
Service Objectの例

{
    "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
(引用元:Services and Routes)
RouteはServiceと関連付けられ、Serviceは複数のRouteを持つことが出来る。これにより、異なるパスへの異なるリクエストを単一のAPIで処理することも出来る。

ここではGet Startedの一部であるManaging services and routesの内容をKong Admin UIから試してみる。

Serviceの作成

Admin UIにアクセスし、Workspace内のdefaultをクリックし、Gateway ServicesからNew Gateway Serviceをクリックする。
クリックすると入力フォームが出てくるので入力する。
1703572823992.png

ここではGet StartedのService作成コマンドにあわせて、以下のように設定した。

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

1703574637840.png

また、curlで取得できることも確認する。
Helmでインストールした場合、Adminへのアクセス方法はIngressオブジェクトの中身を見ると/apiになっており、Serviceの参照URLは/services/<Service nameかID>となっているため、以下で取得を確認する。

curl -X GET https://kong.${BASE_DOMAIN}.nip.io/api/services/example_service -k -L | jq .

無事参照出来た。

{
  "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から作成する。
defaultWorkspaceの左サイドバーからRoutesをクリックし、New Routeをクリックする。
こちらも元のGet Startedの記載にあわせて入力する。
1703574126699.png
設定した値は以下となる。(設定していない箇所はデフォルト値を使用)

  • Name: example_route
  • Service: example_serviceを選択
  • Paths: /mock

無事作成できたら、Serviceと同じように詳細を確認する。
1703574591832.png

また、Serviceと同じようにcurlでも確認する。

curl -X GET https://kong.${BASE_DOMAIN}.nip.io/api/routes/example_route -k -L | jq .

こちらも無事取得できた。

{
  "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を使ってトラフィックをルーティングする。
-kong-proxyというkind: Serviceのオブジェクトがtype: LoadBalancerでIPを公開しており、これへのアクセスをルーティングしてくれるようなので、さっそくアクセスしてみる。
先程作成したRouteのPathは/mockだったので、kong-proxyのIPに/mockをつけたものがhttpbin.orgと思ってアクセスする。

$ 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へ飛ばしてくれて、結果を取得することが出来た。

レート制限

次にレート制限を確認する。
レート制限にはRate Limiting Pluginを利用する。
こちらもGet Startedの手順(CLI)では実施せずに、Admin UIベースで進める。
defaultWorkspaceの左サイドバーからPluginsをクリックし、New Pluginをクリックする。
こちらも元のGet Startedの記載にあわせて入力する。
Pluginの一覧画面になるので、検索窓で"Rate Limit"を検索する。
1703577339794.png
Enableをクリックするとインストール画面に遷移するので、値を設定する。
1703577462692.png
ここでは以下の値を設定した。

  • Instance Name: rate-limiting
  • minute: 5

これにより、1分あたり5回を超えてアクセスする分には制限が掛かるようになる。
他はデフォルト値とした。
なお、Get Startedではconfig.policy=localとしているが、これはUIから設定する場合はデフォルトがlocalとなっているため、設定不要となる。
Installをクリックするとインストールされる。
ServiceやRouteと同じようにView Detailsをクリックすると同じように詳細情報が取得できる。
1703577643678.png
設定を一部抜粋する。

    "error_code": 429,
    "error_message": "API rate limit exceeded",
    "minute": 5,

これは1分間に5回以上アクセスすると、429と設定されたエラーメッセージを返すことを意味している。
早速試してみる。
curlを連続して実行したところ、6回目に以下のエラーを得ることが出来た。

$ 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

Kong GatewayではProxy Cache Pluginを使ってキャッシュ機能を提供している。
これを使ってみる。
なお、以下のキャッシュの種類が用意されている。

  • グローバル:全てのリクエストに対してキャッシュする
  • Serviceレベル:特定のServiceに対してキャッシュする
  • Routeレベル:特定のRouteに対してキャッシュする
  • コンシューマレベル:コンシューマ(ユーザを抽象化したもの)単位でのキャッシュ

それぞれのレイヤでPluginをインストールして利用することになる。
ここではServiceレベルで試してみる。
defaultWorkspaceの左サイドバーからGateway Servicesで作成したexample_serviceをクリックし、Plugins->New Pluginをクリックする。
こちらも元のGet Startedの記載にあわせて入力する。
Pluginの一覧画面になるので、検索窓で"Proxy Caching"を検索し、Enableをクリックする。
1703578962069.png

こうすると、最初からProxyの範囲が指定された状態でインストール画面となる。
Get Startedに合わせて値を設定していく。
1703579322784.png

ここでは以下の値を設定し、他はデフォルト値とした。

  • cache_ttl: 30
  • request_method: GET
  • response_code: 200

cache_ttlを30に設定することで、キャッシュは30秒間保持され、期間を超えると破棄される。
インストール完了後、再度Proxyに対してcurlを実行する。

$ curl -i http://$PROXY_IP/mock/ip
:(省略)
X-Cache-Key: 8d9a6010fe0c02b2924e1f7bf7a1d4e4ce22fe87e91021c697cc28f8de0fc3f1
X-Cache-Status: Miss
:(省略)

キャッシュを見に行ったことが確認できた。
再度実行すると、以下のようにキャッシュを使ったことが読み取れる。

X-Cache-Key: 8d9a6010fe0c02b2924e1f7bf7a1d4e4ce22fe87e91021c697cc28f8de0fc3f1
X-Cache-Status: Hit

また、30秒以上間をあけて再実行すると、Missが表示されることが確認できる。
これによりキャッシュが使えていることが確認できる。

鍵認証

Kong GatewayではPluginで認証を提供しており、以下のような認証が利用できる。

  • 鍵認証
  • Basic認証
  • OAuth 2.0
  • LDAP
  • OpenID Connect

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

最初に鍵認証を有効化する。
Proxy Cacheと同様にグローバル、Service、Routeの単位で設定できるため、ここではProxy Cacheと同様にServiceに設定する。
defaultWorkspaceの左サイドバーからGateway Servicesで作成したexample_serviceをクリックし、Plugins->New Pluginをクリックする。
"key"で検索するとKey Authorization Pluginが見えるのでEnable にする。
1703582082082.png
値の設定画面ではInstance Nameをkey-authにし、他はデフォルト値のままインストールする。
これでキー認証が有効化された。

次にユーザを抽象化したオブジェクトであるコンシューマを作成する。
defaultWorkspaceの左サイドバーからConsumersをクリックし、New Consumerをクリックする。
Get Startedと同じくlukaというUsernameで作成する。
1703581710623.png
作成したコンシューマにキーを割り当てる。
作成したコンシューマのCredentrialsからNew Key Auth Credentialを選択し、キーを作成する。
1703725112859.png

ここではKeyにtop-secret-keyを設定した。
なお、この設定値はUIから確認できるし、Admin APIの/consumers/<ユーザ名>/key-authをGETすることでも確認できる。
先程までアクセスできていた、httpbinのサービスにアクセスしてみる。

$ 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"
}

鍵認証が設定されたことで、キーなしではアクセスに失敗するようになった。
ヘッダにキーを設定してアクセスしてみる。

$ 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"
}

無事取得できた。試しに設定していないキーでも試してみる。

$ 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"
}

ちゃんと弾かれた。

ロードバランシング

Kong Gatewayにはロードバランサの機能もあり、負荷分散やヘルスチェック、サーキットブレーカー的な機能を提供する模様。
ここではGet Startedに従って、ラウンドロビンで以下のようにhttpbin.orghttpbun.comに分散する。

なお、httpbun.comは今回初めて知ったが、httpbin.orgと同様の機能を提供するサービスのようだ。

$ curl httpbun.com/ip
{
  "origin": "xxx.xxx.xxx.xxx"
}

早速設定していく。
defaultWorkspaceの左サイドバーからUpstreamsをクリックし、New Upstreamをクリックする。
設定画面になるので値を入れてSaveをクリックする。
1703729261398.png
ここでは、Nameexample_upstreamを設定した。
なお、名前を入力する際に上記の画像のように(Add new value)と表示されるが、これをクリックしないと名前が正確に反映されず、Saveが活性化されずにクリックできないため注意。

次にロードバランスする先を設定する。
保存後、作成されたexample_upstreamをクリックし、TargetsからNew Targetをクリックしてhttpbin.org:80httpbun.com:80を追加する。なお、ポートを指定しない場合は8000ポートが割り当てられる。
1703730713260.png

最後にServiceを変更する。
今はexample_serviceのエンドポイントはhttpbin.orgを向いているが、これを今作成したexample_upstreamに変更する。
defaultWorkspaceの左サイドバーからGateway Services->example_serviceで画面遷移後、Gateway Service actionsからEdit configurationをクリックする。
1703730301448.png
Hostの項目をexample_upstreamに書き換え、Saveをクリックして保存する。
これでアクセスが分散する。

試してみる。何度かアクセスし、Hostが変わることを確認する。
キャッシュの設定が残っている場合は少し間を置いてアクセスしないと駄目かも。

$ 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.orghttpbun.comにアクセスしていることが確認できた。

まとめ

Kong Gatewayでの各種機能を一通り触って、以下を確認できた。

  • Kong GatewayでAPIに対するキャッシュ、認証、制限、LBなどの機能が簡単に設定できる
  • Get Startedに書かれているCLIでの手順は全てUIでも確認できる
  • Helmでインストールする環境でもGet Startedの内容は全て同等に実施できる

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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?